fix(api): 1.0.4 — OrganisationSummaryResponse record→@Data (compat JSF/EL), version bump

This commit is contained in:
dahoud
2026-04-11 02:00:07 +00:00
parent 5fa4711a8f
commit 43678c8ae9
21 changed files with 897 additions and 238 deletions

View File

@@ -6,7 +6,7 @@
<groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-parent</artifactId>
<version>1.0.0</version>
<version>1.0.4</version>
<packaging>pom</packaging>
<name>UnionFlow - Parent</name>
@@ -60,6 +60,7 @@
<artifactId>unionflow-server-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-parent</artifactId>
<version>1.0.0</version>
<version>1.0.4</version>
<relativePath>parent-pom.xml</relativePath>
</parent>

View File

@@ -1,13 +1,22 @@
package dev.lions.unionflow.server.api.dto.common;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO d'erreur unifié retourné par tous les endpoints REST.
* Remplace les ErrorResponse locales dupliquées dans chaque Resource.
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ErrorResponse(String message, String error) {
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
private String message;
private String error;
/** Constructeur pratique avec message uniquement (cas le plus courant). */
public static ErrorResponse of(String message) {

View File

@@ -1,7 +1,10 @@
package dev.lions.unionflow.server.api.dto.communication.response;
import dev.lions.unionflow.server.api.enums.communication.ConversationType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@@ -14,20 +17,23 @@ import java.util.UUID;
* @version 1.0
* @since 2026-03-16
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public record ConversationResponse(
UUID id,
String name,
String description,
ConversationType type,
List<UUID> participantIds,
UUID organisationId,
MessageResponse lastMessage,
int unreadCount,
boolean isMuted,
boolean isPinned,
boolean isArchived,
LocalDateTime createdAt,
LocalDateTime updatedAt,
String avatarUrl
) {}
public class ConversationResponse {
private UUID id;
private String name;
private String description;
private ConversationType type;
private List<UUID> participantIds;
private UUID organisationId;
private MessageResponse lastMessage;
private int unreadCount;
private boolean muted;
private boolean pinned;
private boolean archived;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private String avatarUrl;
}

View File

@@ -3,7 +3,10 @@ package dev.lions.unionflow.server.api.dto.communication.response;
import dev.lions.unionflow.server.api.enums.communication.MessagePriority;
import dev.lions.unionflow.server.api.enums.communication.MessageStatus;
import dev.lions.unionflow.server.api.enums.communication.MessageType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@@ -16,24 +19,27 @@ import java.util.UUID;
* @version 1.0
* @since 2026-03-16
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public record MessageResponse(
UUID id,
UUID conversationId,
UUID senderId,
String senderName,
String senderAvatar,
String content,
MessageType type,
MessageStatus status,
MessagePriority priority,
List<UUID> recipientIds,
List<String> recipientRoles,
UUID organisationId,
LocalDateTime createdAt,
LocalDateTime readAt,
List<String> attachments,
boolean isEdited,
LocalDateTime editedAt,
boolean isDeleted
) {}
public class MessageResponse {
private UUID id;
private UUID conversationId;
private UUID senderId;
private String senderName;
private String senderAvatar;
private String content;
private MessageType type;
private MessageStatus status;
private MessagePriority priority;
private List<UUID> recipientIds;
private List<String> recipientRoles;
private UUID organisationId;
private LocalDateTime createdAt;
private LocalDateTime readAt;
private List<String> attachments;
private boolean edited;
private LocalDateTime editedAt;
private boolean deleted;
}

View File

@@ -1,5 +1,9 @@
package dev.lions.unionflow.server.api.dto.cotisation.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.UUID;
@@ -7,29 +11,32 @@ import java.util.UUID;
/**
* Réponse simplifiée pour les listes de cotisations.
*
* @param id Identifiant unique.
* @param numeroReference Référence unique.
* @param nomMembre Nom du membre.
* @param montantDu Montant total dû.
* @param montantPaye Montant déjà réglé.
* @param statut Statut actuel (code).
* @param statutLibelle Libellé du statut pour l'UI.
* @param dateEcheance Date limite.
* @param annee Année concernée.
* @param actif Indique si l'entité est active.
* @author UnionFlow Team
* @version 1.0
* @since 2026-02-22
*/
public record CotisationSummaryResponse(
UUID id,
String numeroReference,
String nomMembre,
BigDecimal montantDu,
BigDecimal montantPaye,
String statut,
String statutLibelle,
LocalDate dateEcheance,
Integer annee,
Boolean actif) {
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CotisationSummaryResponse {
/** Identifiant unique. */
private UUID id;
/** Référence unique. */
private String numeroReference;
/** Nom du membre. */
private String nomMembre;
/** Montant total dû. */
private BigDecimal montantDu;
/** Montant déjà réglé. */
private BigDecimal montantPaye;
/** Statut actuel (code). */
private String statut;
/** Libellé du statut pour l'UI. */
private String statutLibelle;
/** Date limite. */
private LocalDate dateEcheance;
/** Année concernée. */
private Integer annee;
/** Indique si l'entité est active. */
private Boolean actif;
}

View File

@@ -1,5 +1,9 @@
package dev.lions.unionflow.server.api.dto.dashboard;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -10,39 +14,42 @@ import java.time.LocalDate;
* @author UnionFlow Team
* @version 1.0
*/
public record MembreDashboardSyntheseResponse(
String prenom,
String nom,
LocalDate dateInscription,
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MembreDashboardSyntheseResponse implements Serializable {
private String prenom;
private String nom;
private LocalDate dateInscription;
// Cotisations
BigDecimal mesCotisationsPaiement,
private BigDecimal mesCotisationsPaiement;
/** Total des cotisations payées sur l'année en cours (pour affichage dashboard). */
BigDecimal totalCotisationsPayeesAnnee,
private BigDecimal totalCotisationsPayeesAnnee;
/** Total des cotisations payées tout temps (pour la carte « Contribution Totale »). */
BigDecimal totalCotisationsPayeesToutTemps,
private BigDecimal totalCotisationsPayeesToutTemps;
/** Nombre de cotisations PAYÉES (pour la carte « Cotisations »). */
Integer nombreCotisationsPayees,
String statutCotisations,
private Integer nombreCotisationsPayees;
private String statutCotisations;
/** Taux de cotisation en % (0-100). Calculé sur l'année courante ou toutes années si pas de cotisation 2026. */
Integer tauxCotisationsPerso,
private Integer tauxCotisationsPerso;
/** Nombre TOTAL de cotisations (toutes années, tous statuts) — pour calcul du taux d'engagement. */
Integer nombreCotisationsTotal,
private Integer nombreCotisationsTotal;
// Epargne
BigDecimal monSoldeEpargne,
BigDecimal evolutionEpargneNombre,
String evolutionEpargne,
Integer objectifEpargne,
private BigDecimal monSoldeEpargne;
private BigDecimal evolutionEpargneNombre;
private String evolutionEpargne;
private Integer objectifEpargne;
// Evenements
Integer mesEvenementsInscrits,
Integer evenementsAVenir,
Integer tauxParticipationPerso,
private Integer mesEvenementsInscrits;
private Integer evenementsAVenir;
private Integer tauxParticipationPerso;
// Aides
Integer mesDemandesAide,
Integer aidesEnCours,
Integer tauxAidesApprouvees) implements Serializable {
private Integer mesDemandesAide;
private Integer aidesEnCours;
private Integer tauxAidesApprouvees;
}

View File

@@ -1,5 +1,9 @@
package dev.lions.unionflow.server.api.dto.membre;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -18,57 +22,55 @@ import java.time.LocalDate;
* <li>Capacité d'emprunt estimée (3× l'épargne — règle mutuelle classique)</li>
* </ul>
*
* @param numeroMembre Numéro unique du membre sur la plateforme (ex: MUF-2026-001)
* @param nomComplet Nom et prénom du membre
* @param organisationNom Nom de l'organisation principale (ou null si aucune)
* @param dateAdhesion Date d'inscription sur la plateforme
* @param statutCompte Statut actuel du compte (ACTIF, SUSPENDU, etc.)
*
* @param soldeCotisations Total des cotisations payées (toutes années confondues)
* @param soldeEpargne Solde disponible sur l'ensemble des comptes épargne actifs
* @param soldeBloque Montant bloqué (garantie de prêt)
* @param soldeTotalDisponible soldeCotisations + soldeEpargne - soldeBloque
* @param encoursCreditTotal Montant total des prêts en cours (0 si fonctionnalité non encore activée)
* @param capaciteEmprunt Capacité d'emprunt estimée (3 × soldeEpargne selon règle mutuelle standard)
*
* @param nombreCotisationsPayees Nombre de cotisations payées (historique complet)
* @param nombreCotisationsTotal Nombre total de cotisations (payées + en attente + retard)
* @param nombreCotisationsEnRetard Nombre de cotisations en retard
* @param tauxEngagement Taux de paiement global en % (0-100)
*
* @param nombreComptesEpargne Nombre de comptes épargne actifs
* @param dateCalcul Date/heure du calcul (pour information client)
*
* @author UnionFlow Team
* @version 1.0
*/
public record CompteAdherentResponse(
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CompteAdherentResponse implements Serializable {
// ── Identité ──────────────────────────────────────────────────────────
String numeroMembre,
String nomComplet,
String organisationNom,
LocalDate dateAdhesion,
String statutCompte,
/** Numéro unique du membre sur la plateforme (ex: MUF-2026-001) */
private String numeroMembre;
/** Nom et prénom du membre */
private String nomComplet;
/** Nom de l'organisation principale (ou null si aucune) */
private String organisationNom;
/** Date d'inscription sur la plateforme */
private LocalDate dateAdhesion;
/** Statut actuel du compte (ACTIF, SUSPENDU, etc.) */
private String statutCompte;
// ── Soldes ────────────────────────────────────────────────────────────
BigDecimal soldeCotisations,
BigDecimal soldeEpargne,
BigDecimal soldeBloque,
BigDecimal soldeTotalDisponible,
BigDecimal encoursCreditTotal,
BigDecimal capaciteEmprunt,
/** Total des cotisations payées (toutes années confondues) */
private BigDecimal soldeCotisations;
/** Solde disponible sur l'ensemble des comptes épargne actifs */
private BigDecimal soldeEpargne;
/** Montant bloqué (garantie de prêt) */
private BigDecimal soldeBloque;
/** soldeCotisations + soldeEpargne - soldeBloque */
private BigDecimal soldeTotalDisponible;
/** Montant total des prêts en cours (0 si fonctionnalité non encore activée) */
private BigDecimal encoursCreditTotal;
/** Capacité d'emprunt estimée (3 × soldeEpargne selon règle mutuelle standard) */
private BigDecimal capaciteEmprunt;
// ── Cotisations ───────────────────────────────────────────────────────
Integer nombreCotisationsPayees,
Integer nombreCotisationsTotal,
Integer nombreCotisationsEnRetard,
Integer tauxEngagement,
/** Nombre de cotisations payées (historique complet) */
private Integer nombreCotisationsPayees;
/** Nombre total de cotisations (payées + en attente + retard) */
private Integer nombreCotisationsTotal;
/** Nombre de cotisations en retard */
private Integer nombreCotisationsEnRetard;
/** Taux de paiement global en % (0-100) */
private Integer tauxEngagement;
// ── Épargne ───────────────────────────────────────────────────────────
Integer nombreComptesEpargne,
/** Nombre de comptes épargne actifs */
private Integer nombreComptesEpargne;
// ── Méta ──────────────────────────────────────────────────────────────
LocalDate dateCalcul
) implements Serializable {}
/** Date/heure du calcul (pour information client) */
private LocalDate dateCalcul;
}

View File

@@ -1,5 +1,9 @@
package dev.lions.unionflow.server.api.dto.membre.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
@@ -7,81 +11,56 @@ import java.util.UUID;
/**
* DTO de réponse résumé pour Membre (listes et optimisations).
*
* <p>Ce record expose des méthodes calculées pour la compatibilité JSF EL :
* {@link #nomComplet()}, {@link #statut()}, {@link #typeMembre()}, etc.
* <p>Classe JavaBean pour compatibilité JSF EL (EL cherche getXxx()).
* Expose également des propriétés calculées (nomComplet, statut, typeMembre, etc.)
*/
public record MembreSummaryResponse(
UUID id,
String numeroMembre,
String prenom,
String nom,
String email,
String telephone,
String profession,
String statutCompte,
String statutCompteLibelle,
String statutCompteSeverity,
Boolean actif,
List<String> roles,
UUID organisationId,
String organisationNom,
LocalDate dateAdhesion) {
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MembreSummaryResponse {
// ── Getters JavaBean pour compatibilité JSF EL (EL cherche getXxx()) ──────
public UUID getId() { return id; }
public String getNumeroMembre() { return numeroMembre; }
public String getPrenom() { return prenom; }
public String getNom() { return nom; }
public String getEmail() { return email; }
public String getTelephone() { return telephone; }
public String getProfession() { return profession; }
public String getStatutCompte() { return statutCompte; }
public String getStatutCompteLibelle() { return statutCompteLibelle; }
public String getStatutCompteSeverity() { return statutCompteSeverity; }
public Boolean getActif() { return actif; }
public boolean isActif() { return Boolean.TRUE.equals(actif); }
public List<String> getRoles() { return roles; }
public UUID getOrganisationId() { return organisationId; }
public String getOrganisationNom() { return organisationNom; }
public LocalDate getDateAdhesion() { return dateAdhesion; }
// Getters JavaBean pour les propriétés calculées
public String getNomComplet() { return nomComplet(); }
public String getStatut() { return statut(); }
public String getStatutLibelle() { return statutLibelle(); }
public String getStatutSeverity() { return statutSeverity(); }
public String getStatutIcon() { return statutIcon(); }
public String getTypeMembre() { return typeMembre(); }
public String getTypeSeverity() { return typeSeverity(); }
public String getTypeIcon() { return typeIcon(); }
private UUID id;
private String numeroMembre;
private String prenom;
private String nom;
private String email;
private String telephone;
private String profession;
private String statutCompte;
private String statutCompteLibelle;
private String statutCompteSeverity;
private Boolean actif;
private List<String> roles;
private UUID organisationId;
private String organisationNom;
private LocalDate dateAdhesion;
// ── Propriétés calculées pour la compatibilité JSF EL ──────────────────
/** Prénom + Nom concaténés. */
public String nomComplet() {
public String getNomComplet() {
String p = prenom != null ? prenom.trim() : "";
String n = nom != null ? nom.trim() : "";
return (p + " " + n).trim();
}
/** Alias de {@link #statutCompte()} pour #{membre.statut}. */
public String statut() {
/** Alias de {@link #getStatutCompte()} pour #{membre.statut}. */
public String getStatut() {
return statutCompte;
}
/** Alias de {@link #statutCompteLibelle()} pour #{membre.statutLibelle}. */
public String statutLibelle() {
/** Alias de {@link #getStatutCompteLibelle()} pour #{membre.statutLibelle}. */
public String getStatutLibelle() {
return statutCompteLibelle;
}
/** Alias de {@link #statutCompteSeverity()} pour #{membre.statutSeverity}. */
public String statutSeverity() {
/** Alias de {@link #getStatutCompteSeverity()} pour #{membre.statutSeverity}. */
public String getStatutSeverity() {
return statutCompteSeverity;
}
/** Icône PrimeIcons calculée depuis {@link #statutCompte()}. */
public String statutIcon() {
/** Icône PrimeIcons calculée depuis {@link #getStatutCompte()}. */
public String getStatutIcon() {
if (statutCompte == null) return "pi pi-question-circle";
return switch (statutCompte) {
case "ACTIF" -> "pi pi-check-circle";
@@ -92,8 +71,8 @@ public record MembreSummaryResponse(
};
}
/** Libellé du rôle principal calculé depuis {@link #roles()}. */
public String typeMembre() {
/** Libellé du rôle principal calculé depuis {@link #getRoles()}. */
public String getTypeMembre() {
if (roles == null || roles.isEmpty()) return "Membre";
if (roles.contains("PRESIDENT")) return "Président";
if (roles.contains("VICE_PRESIDENT")) return "Vice-Président";
@@ -104,8 +83,8 @@ public record MembreSummaryResponse(
return "Membre";
}
/** Severity PrimeUI calculée depuis {@link #roles()}. */
public String typeSeverity() {
/** Severity PrimeUI calculée depuis {@link #getRoles()}. */
public String getTypeSeverity() {
if (roles == null || roles.isEmpty()) return "secondary";
if (roles.contains("PRESIDENT")) return "primary";
if (roles.contains("VICE_PRESIDENT")) return "primary";
@@ -116,8 +95,8 @@ public record MembreSummaryResponse(
return "secondary";
}
/** Icône PrimeIcons calculée depuis {@link #roles()}. */
public String typeIcon() {
/** Icône PrimeIcons calculée depuis {@link #getRoles()}. */
public String getTypeIcon() {
if (roles == null || roles.isEmpty()) return "pi pi-user";
if (roles.contains("PRESIDENT")) return "pi pi-star";
if (roles.contains("VICE_PRESIDENT")) return "pi pi-star";

View File

@@ -1,23 +1,31 @@
package dev.lions.unionflow.server.api.dto.organisation.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.UUID;
/**
* Résumé d'une organisation pour les listes.
* Classe JavaBean (pas un record) pour compatibilité JSF/EL (getNom() requis).
*
* @author UnionFlow Team
* @version 3.0
* @version 3.1
* @since 2026-02-22
*/
public record OrganisationSummaryResponse(
UUID id,
String nom,
String nomCourt,
String typeOrganisation,
String typeOrganisationLibelle,
String statut,
String statutLibelle,
String statutSeverity,
Integer nombreMembres,
Boolean actif) {
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrganisationSummaryResponse {
private UUID id;
private String nom;
private String nomCourt;
private String typeOrganisation;
private String typeOrganisationLibelle;
private String statut;
private String statutLibelle;
private String statutSeverity;
private Integer nombreMembres;
private Boolean actif;
}

View File

@@ -1,24 +1,31 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.UUID;
import lombok.Builder;
/**
* Réponse du polling de statut d'une IntentionPaiement Wave.
* Utilisée par le web pour savoir si le paiement est confirmé.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public record IntentionStatutResponse(
UUID intentionId,
public class IntentionStatutResponse {
private UUID intentionId;
/** INITIEE | EN_COURS | COMPLETEE | EXPIREE | ECHOUEE */
String statut,
private String statut;
/** URL à encoder en QR code (wave_launch_url Wave Checkout) */
String waveLaunchUrl,
String waveCheckoutSessionId,
private String waveLaunchUrl;
private String waveCheckoutSessionId;
/** ID de transaction Wave (TCN...) — disponible quand COMPLETEE */
String waveTransactionId,
BigDecimal montant,
String referenceCotisation,
String message
) {}
private String waveTransactionId;
private BigDecimal montant;
private String referenceCotisation;
private String message;
}

View File

@@ -1,5 +1,9 @@
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;
@@ -11,14 +15,17 @@ import java.util.UUID;
* @author UnionFlow Team
* @version 3.0
*/
public record PaiementSummaryResponse(
UUID id,
String numeroReference,
BigDecimal montant,
String codeDevise,
String methodePaiementLibelle,
String statutPaiement,
String statutPaiementLibelle,
String statutPaiementSeverity,
LocalDateTime datePaiement) {
@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;
}

View File

@@ -52,5 +52,17 @@ public record CreateTypeReferenceRequest(
Boolean estSysteme,
/** UUID de l'organisation (null = global). */
UUID organisationId) {
UUID organisationId,
/**
* Catégorie fonctionnelle (ex: FINANCIER_SOLIDAIRE).
* Obligatoire pour domaine=TYPE_ORGANISATION.
*/
@Size(max = 50) String categorie,
/**
* Modules métier CSV (ex: "MEMBRES,COTISATIONS,TONTINE,FINANCE").
* Obligatoire pour domaine=TYPE_ORGANISATION.
*/
String modulesRequis) {
}

View File

@@ -41,5 +41,11 @@ public record UpdateTypeReferenceRequest(
Boolean estDefaut,
/** Nouvel état actif/inactif (optionnel). */
Boolean actif) {
Boolean actif,
/** Nouvelle catégorie fonctionnelle (optionnel). */
@Size(max = 50) String categorie,
/** Nouveaux modules requis CSV (optionnel). */
String modulesRequis) {
}

View File

@@ -60,4 +60,19 @@ public class TypeReferenceResponse extends BaseResponse {
/** UUID de l'organisation (null = global). */
private UUID organisationId;
/**
* Catégorie fonctionnelle du type d'organisation.
* Valeurs: ASSOCIATIF, FINANCIER_SOLIDAIRE, RELIGIEUX, PROFESSIONNEL, RESEAU_FEDERATION.
* Uniquement pertinent pour domaine=TYPE_ORGANISATION.
*/
private String categorie;
/**
* Modules métier activés pour ce type d'organisation (CSV).
* Exemple: "MEMBRES,COTISATIONS,TONTINE,FINANCE"
* Utilisé pour initialiser Organisation.modulesActifs à la création.
* Uniquement pertinent pour domaine=TYPE_ORGANISATION.
*/
private String modulesRequis;
}

View File

@@ -0,0 +1,32 @@
package dev.lions.unionflow.server.api.dto.common;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
class ErrorResponseTest {
@Test
void testOf_messageUniquement() {
ErrorResponse response = ErrorResponse.of("Une erreur est survenue");
assertThat(response.message()).isEqualTo("Une erreur est survenue");
assertThat(response.error()).isNull();
}
@Test
void testOfError_errorUniquement() {
ErrorResponse response = ErrorResponse.ofError("NOT_FOUND");
assertThat(response.message()).isNull();
assertThat(response.error()).isEqualTo("NOT_FOUND");
}
@Test
void testConstructeurComplet() {
ErrorResponse response = new ErrorResponse("Message d'erreur", "VALIDATION_ERROR");
assertThat(response.message()).isEqualTo("Message d'erreur");
assertThat(response.error()).isEqualTo("VALIDATION_ERROR");
}
}

View File

@@ -228,6 +228,28 @@ class CotisationResponseTest {
}
}
@Nested
@DisplayName("Alias getMethodePaiementLibelle")
class AliasMethodePaiement {
@Test
@DisplayName("getMethodePaiementLibelle retourne modePaiementLibelle")
void getMethodePaiementLibelle_retourneModePaiementLibelle() {
CotisationResponse r = CotisationResponse.builder()
.modePaiementLibelle("Wave Money")
.build();
assertThat(r.getMethodePaiementLibelle()).isEqualTo("Wave Money");
}
@Test
@DisplayName("getMethodePaiementLibelle retourne null si non renseigné")
void getMethodePaiementLibelle_null() {
CotisationResponse r = CotisationResponse.builder().build();
assertThat(r.getMethodePaiementLibelle()).isNull();
}
}
@Nested
@DisplayName("Builder complet")
class BuilderComplet {

View File

@@ -0,0 +1,344 @@
package dev.lions.unionflow.server.api.dto.membre.response;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@DisplayName("Tests MembreResponse")
class MembreResponseTest {
@Nested
@DisplayName("Builder et getters de base")
class BuilderGetters {
@Test
@DisplayName("builder remplit tous les champs")
void builder_tousLesChamps() {
UUID id = UUID.randomUUID();
UUID keycloakId = UUID.randomUUID();
UUID orgId = UUID.randomUUID();
LocalDate dateNaissance = LocalDate.of(1990, 5, 15);
LocalDate dateAdhesion = LocalDate.of(2024, 1, 10);
MembreResponse m = MembreResponse.builder()
.numeroMembre("M-001")
.keycloakId(keycloakId)
.prenom("Jean")
.nom("Dupont")
.nomComplet("Jean Dupont")
.email("jean.dupont@example.com")
.telephone("+225001122334")
.telephoneWave("+225001122334")
.dateNaissance(dateNaissance)
.age(35)
.profession("Ingénieur")
.photoUrl("https://example.com/photo.jpg")
.statutMatrimonial("MARIE")
.statutMatrimonialLibelle("Marié")
.nationalite("Ivoirienne")
.typeIdentite("CNI")
.typeIdentiteLibelle("Carte Nationale d'Identité")
.numeroIdentite("CI12345")
.niveauVigilanceKyc("STANDARD")
.statutKyc("VERIFIE")
.dateVerificationIdentite(LocalDate.of(2024, 2, 1))
.statutCompte("ACTIF")
.statutCompteLibelle("Actif")
.statutCompteSeverity("success")
.roles(Arrays.asList("MEMBRE"))
.organisationId(orgId)
.organisationNom("Club Lions Abidjan")
.dateAdhesion(dateAdhesion)
.adresse("123 Rue de la Paix")
.ville("Abidjan")
.codePostal("00225")
.notes("Membre actif")
.nombreEvenementsParticipes(5)
.motDePasseTemporaire("TempPass123!")
.build();
m.setId(id);
assertThat(m.getId()).isEqualTo(id);
assertThat(m.getNumeroMembre()).isEqualTo("M-001");
assertThat(m.getKeycloakId()).isEqualTo(keycloakId);
assertThat(m.getPrenom()).isEqualTo("Jean");
assertThat(m.getNom()).isEqualTo("Dupont");
assertThat(m.getNomComplet()).isEqualTo("Jean Dupont");
assertThat(m.getEmail()).isEqualTo("jean.dupont@example.com");
assertThat(m.getTelephone()).isEqualTo("+225001122334");
assertThat(m.getTelephoneWave()).isEqualTo("+225001122334");
assertThat(m.getDateNaissance()).isEqualTo(dateNaissance);
assertThat(m.getAge()).isEqualTo(35);
assertThat(m.getProfession()).isEqualTo("Ingénieur");
assertThat(m.getPhotoUrl()).isEqualTo("https://example.com/photo.jpg");
assertThat(m.getStatutMatrimonial()).isEqualTo("MARIE");
assertThat(m.getStatutMatrimonialLibelle()).isEqualTo("Marié");
assertThat(m.getNationalite()).isEqualTo("Ivoirienne");
assertThat(m.getTypeIdentite()).isEqualTo("CNI");
assertThat(m.getTypeIdentiteLibelle()).isEqualTo("Carte Nationale d'Identité");
assertThat(m.getNumeroIdentite()).isEqualTo("CI12345");
assertThat(m.getNiveauVigilanceKyc()).isEqualTo("STANDARD");
assertThat(m.getStatutKyc()).isEqualTo("VERIFIE");
assertThat(m.getDateVerificationIdentite()).isEqualTo(LocalDate.of(2024, 2, 1));
assertThat(m.getStatutCompte()).isEqualTo("ACTIF");
assertThat(m.getStatutCompteLibelle()).isEqualTo("Actif");
assertThat(m.getStatutCompteSeverity()).isEqualTo("success");
assertThat(m.getRoles()).containsExactly("MEMBRE");
assertThat(m.getOrganisationId()).isEqualTo(orgId);
assertThat(m.getOrganisationNom()).isEqualTo("Club Lions Abidjan");
assertThat(m.getDateAdhesion()).isEqualTo(dateAdhesion);
assertThat(m.getAdresse()).isEqualTo("123 Rue de la Paix");
assertThat(m.getVille()).isEqualTo("Abidjan");
assertThat(m.getCodePostal()).isEqualTo("00225");
assertThat(m.getNotes()).isEqualTo("Membre actif");
assertThat(m.getNombreEvenementsParticipes()).isEqualTo(5);
assertThat(m.getMotDePasseTemporaire()).isEqualTo("TempPass123!");
}
@Test
@DisplayName("constructeur vide produit un objet non null")
void constructeurVide() {
MembreResponse m = new MembreResponse();
assertThat(m).isNotNull();
assertThat(m.getPrenom()).isNull();
assertThat(m.getNom()).isNull();
}
@Test
@DisplayName("setters mettent à jour les champs")
void setters_mettentAJour() {
MembreResponse m = new MembreResponse();
m.setPrenom("Marie");
m.setNom("Martin");
m.setEmail("marie.martin@example.com");
m.setStatutCompte("INACTIF");
m.setStatutCompteSeverity("secondary");
m.setDateAdhesion(LocalDate.of(2023, 6, 1));
assertThat(m.getPrenom()).isEqualTo("Marie");
assertThat(m.getNom()).isEqualTo("Martin");
assertThat(m.getEmail()).isEqualTo("marie.martin@example.com");
}
}
@Nested
@DisplayName("getInitiales")
class GetInitiales {
@Test
@DisplayName("retourne initiales quand prénom et nom sont renseignés")
void initiales_prenomNomPresents() {
MembreResponse m = MembreResponse.builder().prenom("Jean").nom("Dupont").build();
assertThat(m.getInitiales()).isEqualTo("JD");
}
@Test
@DisplayName("retourne initiale du prénom uniquement si nom null")
void initiales_nomNull() {
MembreResponse m = MembreResponse.builder().prenom("Jean").nom(null).build();
assertThat(m.getInitiales()).isEqualTo("J");
}
@Test
@DisplayName("retourne initiale du nom uniquement si prénom null")
void initiales_prenomNull() {
MembreResponse m = MembreResponse.builder().prenom(null).nom("Dupont").build();
assertThat(m.getInitiales()).isEqualTo("D");
}
@Test
@DisplayName("retourne chaîne vide si prénom et nom vides")
void initiales_prenomNomVides() {
MembreResponse m = MembreResponse.builder().prenom("").nom("").build();
assertThat(m.getInitiales()).isEmpty();
}
@Test
@DisplayName("retourne chaîne vide si prénom et nom null")
void initiales_prenomNomNull() {
MembreResponse m = new MembreResponse();
assertThat(m.getInitiales()).isEmpty();
}
}
@Nested
@DisplayName("getDateAdhesionFormatee")
class GetDateAdhesionFormatee {
@Test
@DisplayName("retourne null quand dateAdhesion est null")
void dateAdhesion_null() {
MembreResponse m = new MembreResponse();
assertThat(m.getDateAdhesionFormatee()).isNull();
}
@Test
@DisplayName("retourne date formatée dd/MM/yyyy")
void dateAdhesion_formatee() {
MembreResponse m = MembreResponse.builder().dateAdhesion(LocalDate.of(2024, 3, 15)).build();
assertThat(m.getDateAdhesionFormatee()).isEqualTo("15/03/2024");
}
}
@Nested
@DisplayName("getStatut et getStatutSeverity")
class AliasStatut {
@Test
@DisplayName("getStatut retourne statutCompte")
void getStatut() {
MembreResponse m = MembreResponse.builder().statutCompte("ACTIF").build();
assertThat(m.getStatut()).isEqualTo("ACTIF");
}
@Test
@DisplayName("getStatutSeverity retourne statutCompteSeverity")
void getStatutSeverity() {
MembreResponse m = MembreResponse.builder().statutCompteSeverity("warning").build();
assertThat(m.getStatutSeverity()).isEqualTo("warning");
}
}
@Nested
@DisplayName("getTypeMembre")
class GetTypeMembre {
@Test
@DisplayName("retourne Membre quand roles null")
void typeMembre_rolesNull() {
MembreResponse m = new MembreResponse();
assertThat(m.getTypeMembre()).isEqualTo("Membre");
}
@Test
@DisplayName("retourne Membre quand roles vide")
void typeMembre_rolesVide() {
MembreResponse m = MembreResponse.builder().roles(Collections.emptyList()).build();
assertThat(m.getTypeMembre()).isEqualTo("Membre");
}
@Test
@DisplayName("retourne Président quand rôle PRESIDENT")
void typeMembre_president() {
MembreResponse m = MembreResponse.builder().roles(List.of("PRESIDENT")).build();
assertThat(m.getTypeMembre()).isEqualTo("Président");
}
@Test
@DisplayName("retourne Vice-Président quand rôle VICE_PRESIDENT")
void typeMembre_vicePresident() {
MembreResponse m = MembreResponse.builder().roles(List.of("VICE_PRESIDENT")).build();
assertThat(m.getTypeMembre()).isEqualTo("Vice-Président");
}
@Test
@DisplayName("retourne Secrétaire quand rôle SECRETAIRE")
void typeMembre_secretaire() {
MembreResponse m = MembreResponse.builder().roles(List.of("SECRETAIRE")).build();
assertThat(m.getTypeMembre()).isEqualTo("Secrétaire");
}
@Test
@DisplayName("retourne Trésorier quand rôle TRESORIER")
void typeMembre_tresorier() {
MembreResponse m = MembreResponse.builder().roles(List.of("TRESORIER")).build();
assertThat(m.getTypeMembre()).isEqualTo("Trésorier");
}
@Test
@DisplayName("retourne Administrateur quand rôle ADMIN_ORGANISATION")
void typeMembre_adminOrganisation() {
MembreResponse m = MembreResponse.builder().roles(List.of("ADMIN_ORGANISATION")).build();
assertThat(m.getTypeMembre()).isEqualTo("Administrateur");
}
@Test
@DisplayName("retourne Modérateur quand rôle MODERATEUR")
void typeMembre_moderateur() {
MembreResponse m = MembreResponse.builder().roles(List.of("MODERATEUR")).build();
assertThat(m.getTypeMembre()).isEqualTo("Modérateur");
}
@Test
@DisplayName("retourne Membre pour rôle inconnu")
void typeMembre_roleInconnu() {
MembreResponse m = MembreResponse.builder().roles(List.of("AUTRE_ROLE")).build();
assertThat(m.getTypeMembre()).isEqualTo("Membre");
}
}
@Nested
@DisplayName("getTypeSeverity")
class GetTypeSeverity {
@Test
@DisplayName("retourne secondary quand roles null")
void typeSeverity_rolesNull() {
MembreResponse m = new MembreResponse();
assertThat(m.getTypeSeverity()).isEqualTo("secondary");
}
@Test
@DisplayName("retourne secondary quand roles vide")
void typeSeverity_rolesVide() {
MembreResponse m = MembreResponse.builder().roles(Collections.emptyList()).build();
assertThat(m.getTypeSeverity()).isEqualTo("secondary");
}
@Test
@DisplayName("retourne primary pour PRESIDENT")
void typeSeverity_president() {
MembreResponse m = MembreResponse.builder().roles(List.of("PRESIDENT")).build();
assertThat(m.getTypeSeverity()).isEqualTo("primary");
}
@Test
@DisplayName("retourne primary pour VICE_PRESIDENT")
void typeSeverity_vicePresident() {
MembreResponse m = MembreResponse.builder().roles(List.of("VICE_PRESIDENT")).build();
assertThat(m.getTypeSeverity()).isEqualTo("primary");
}
@Test
@DisplayName("retourne info pour SECRETAIRE")
void typeSeverity_secretaire() {
MembreResponse m = MembreResponse.builder().roles(List.of("SECRETAIRE")).build();
assertThat(m.getTypeSeverity()).isEqualTo("info");
}
@Test
@DisplayName("retourne warning pour TRESORIER")
void typeSeverity_tresorier() {
MembreResponse m = MembreResponse.builder().roles(List.of("TRESORIER")).build();
assertThat(m.getTypeSeverity()).isEqualTo("warning");
}
@Test
@DisplayName("retourne danger pour ADMIN_ORGANISATION")
void typeSeverity_adminOrganisation() {
MembreResponse m = MembreResponse.builder().roles(List.of("ADMIN_ORGANISATION")).build();
assertThat(m.getTypeSeverity()).isEqualTo("danger");
}
@Test
@DisplayName("retourne warning pour MODERATEUR")
void typeSeverity_moderateur() {
MembreResponse m = MembreResponse.builder().roles(List.of("MODERATEUR")).build();
assertThat(m.getTypeSeverity()).isEqualTo("warning");
}
@Test
@DisplayName("retourne secondary pour rôle inconnu")
void typeSeverity_roleInconnu() {
MembreResponse m = MembreResponse.builder().roles(List.of("INCONNU")).build();
assertThat(m.getTypeSeverity()).isEqualTo("secondary");
}
}
}

View File

@@ -37,6 +37,8 @@ class CreateTypeReferenceRequestTest {
.estDefaut(true)
.estSysteme(true)
.organisationId(organisationId)
.categorie("FINANCIER_SOLIDAIRE")
.modulesRequis("MEMBRES,COTISATIONS,TONTINE,FINANCE")
.build();
assertThat(request).isNotNull();
@@ -51,6 +53,8 @@ class CreateTypeReferenceRequestTest {
assertThat(request.estDefaut()).isTrue();
assertThat(request.estSysteme()).isTrue();
assertThat(request.organisationId()).isEqualTo(organisationId);
assertThat(request.categorie()).isEqualTo("FINANCIER_SOLIDAIRE");
assertThat(request.modulesRequis()).isEqualTo("MEMBRES,COTISATIONS,TONTINE,FINANCE");
}
@Test

View File

@@ -31,7 +31,9 @@ class UpdateTypeReferenceRequestTest {
"warning",
5,
true,
false
false,
"FINANCIER_SOLIDAIRE",
"MEMBRES,COTISATIONS,TONTINE"
);
assertThat(request).isNotNull();
@@ -44,6 +46,8 @@ class UpdateTypeReferenceRequestTest {
assertThat(request.ordreAffichage()).isEqualTo(5);
assertThat(request.estDefaut()).isTrue();
assertThat(request.actif()).isFalse();
assertThat(request.categorie()).isEqualTo("FINANCIER_SOLIDAIRE");
assertThat(request.modulesRequis()).isEqualTo("MEMBRES,COTISATIONS,TONTINE");
}
@Test
@@ -57,11 +61,15 @@ class UpdateTypeReferenceRequestTest {
null,
null,
null,
null,
null,
null
);
assertThat(request).isNotNull();
assertThat(request.libelle()).isEqualTo("Libellé mis à jour");
assertThat(request.categorie()).isNull();
assertThat(request.modulesRequis()).isNull();
}
@Test
@@ -76,6 +84,8 @@ class UpdateTypeReferenceRequestTest {
null,
null,
null,
null,
null,
null
);
@@ -97,6 +107,8 @@ class UpdateTypeReferenceRequestTest {
null,
null,
null,
null,
null,
null
);
@@ -106,6 +118,29 @@ class UpdateTypeReferenceRequestTest {
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("libelle"));
}
@Test
void testValidation_CategorieTooLong() {
String longCategorie = "A".repeat(51);
UpdateTypeReferenceRequest request = new UpdateTypeReferenceRequest(
null,
null,
null,
null,
null,
null,
null,
null,
null,
longCategorie,
null
);
Set<ConstraintViolation<UpdateTypeReferenceRequest>> violations = validator.validate(request);
assertThat(violations).isNotEmpty();
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("categorie"));
}
@Test
void testValidation_ValidFields() {
UpdateTypeReferenceRequest request = new UpdateTypeReferenceRequest(
@@ -117,7 +152,9 @@ class UpdateTypeReferenceRequestTest {
"success",
1,
false,
true
true,
"ASSOCIATIF",
"MEMBRES,COTISATIONS"
);
Set<ConstraintViolation<UpdateTypeReferenceRequest>> violations = validator.validate(request);
@@ -136,7 +173,9 @@ class UpdateTypeReferenceRequestTest {
null,
null,
null,
true
true,
"ASSOCIATIF",
"MEMBRES"
);
UpdateTypeReferenceRequest request2 = new UpdateTypeReferenceRequest(
@@ -148,7 +187,9 @@ class UpdateTypeReferenceRequestTest {
null,
null,
null,
true
true,
"ASSOCIATIF",
"MEMBRES"
);
assertThat(request1).isEqualTo(request2);
@@ -166,7 +207,9 @@ class UpdateTypeReferenceRequestTest {
null,
null,
null,
true
true,
"FINANCIER_SOLIDAIRE",
"MEMBRES,TONTINE"
);
String toString = request.toString();
@@ -174,5 +217,6 @@ class UpdateTypeReferenceRequestTest {
assertThat(toString).isNotNull();
assertThat(toString).contains("UpdateTypeReferenceRequest");
assertThat(toString).contains("CODE_UPDATE");
assertThat(toString).contains("FINANCIER_SOLIDAIRE");
}
}

View File

@@ -0,0 +1,141 @@
package dev.lions.unionflow.server.api.dto.reference.response;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.Test;
class TypeReferenceResponseTest {
@Test
void testBuilder_AllFields() {
UUID id = UUID.randomUUID();
UUID orgId = UUID.randomUUID();
LocalDateTime now = LocalDateTime.now();
TypeReferenceResponse response = TypeReferenceResponse.builder()
.domaine("TYPE_ORGANISATION")
.code("TONTINE")
.libelle("Tontine")
.description("Organisation de type tontine")
.icone("pi-money-bill")
.couleur("#F59E0B")
.severity("warning")
.ordreAffichage(1)
.estDefaut(false)
.estSysteme(true)
.organisationId(orgId)
.categorie("FINANCIER_SOLIDAIRE")
.modulesRequis("MEMBRES,COTISATIONS,TONTINE,FINANCE")
.build();
response.setId(id);
response.setDateCreation(now);
response.setDateModification(now);
response.setCreePar("admin@test.com");
response.setModifiePar("admin@test.com");
response.setVersion(1L);
response.setActif(true);
assertThat(response.getDomaine()).isEqualTo("TYPE_ORGANISATION");
assertThat(response.getCode()).isEqualTo("TONTINE");
assertThat(response.getLibelle()).isEqualTo("Tontine");
assertThat(response.getDescription()).isEqualTo("Organisation de type tontine");
assertThat(response.getIcone()).isEqualTo("pi-money-bill");
assertThat(response.getCouleur()).isEqualTo("#F59E0B");
assertThat(response.getSeverity()).isEqualTo("warning");
assertThat(response.getOrdreAffichage()).isEqualTo(1);
assertThat(response.getEstDefaut()).isFalse();
assertThat(response.getEstSysteme()).isTrue();
assertThat(response.getOrganisationId()).isEqualTo(orgId);
assertThat(response.getCategorie()).isEqualTo("FINANCIER_SOLIDAIRE");
assertThat(response.getModulesRequis()).isEqualTo("MEMBRES,COTISATIONS,TONTINE,FINANCE");
assertThat(response.getId()).isEqualTo(id);
assertThat(response.getDateCreation()).isEqualTo(now);
assertThat(response.getDateModification()).isEqualTo(now);
assertThat(response.getCreePar()).isEqualTo("admin@test.com");
assertThat(response.getModifiePar()).isEqualTo("admin@test.com");
assertThat(response.getVersion()).isEqualTo(1L);
assertThat(response.getActif()).isTrue();
}
@Test
void testNoArgsConstructor() {
TypeReferenceResponse response = new TypeReferenceResponse();
assertThat(response).isNotNull();
assertThat(response.getDomaine()).isNull();
assertThat(response.getCode()).isNull();
assertThat(response.getCategorie()).isNull();
assertThat(response.getModulesRequis()).isNull();
}
@Test
void testAllArgsConstructor() {
UUID orgId = UUID.randomUUID();
TypeReferenceResponse response = new TypeReferenceResponse(
"TYPE_ORGANISATION",
"MUTUELLE",
"Mutuelle d'épargne",
"Description mutuelle",
"pi-wallet",
"#6366F1",
"info",
2,
true,
false,
orgId,
"FINANCIER_SOLIDAIRE",
"MEMBRES,EPARGNE,CREDIT"
);
assertThat(response.getDomaine()).isEqualTo("TYPE_ORGANISATION");
assertThat(response.getCode()).isEqualTo("MUTUELLE");
assertThat(response.getLibelle()).isEqualTo("Mutuelle d'épargne");
assertThat(response.getCategorie()).isEqualTo("FINANCIER_SOLIDAIRE");
assertThat(response.getModulesRequis()).isEqualTo("MEMBRES,EPARGNE,CREDIT");
assertThat(response.getEstDefaut()).isTrue();
assertThat(response.getEstSysteme()).isFalse();
assertThat(response.getOrganisationId()).isEqualTo(orgId);
}
@Test
void testSetters() {
TypeReferenceResponse response = new TypeReferenceResponse();
response.setDomaine("STATUT_MEMBRE");
response.setCode("ACTIF");
response.setLibelle("Membre Actif");
response.setDescription("Description");
response.setIcone("pi-user");
response.setCouleur("#22C55E");
response.setSeverity("success");
response.setOrdreAffichage(1);
response.setEstDefaut(true);
response.setEstSysteme(false);
response.setOrganisationId(null);
response.setCategorie("ASSOCIATIF");
response.setModulesRequis("MEMBRES,COTISATIONS");
assertThat(response.getDomaine()).isEqualTo("STATUT_MEMBRE");
assertThat(response.getCode()).isEqualTo("ACTIF");
assertThat(response.getCategorie()).isEqualTo("ASSOCIATIF");
assertThat(response.getModulesRequis()).isEqualTo("MEMBRES,COTISATIONS");
}
@Test
void testEqualsAndHashCode() {
UUID id = UUID.randomUUID();
TypeReferenceResponse r1 = TypeReferenceResponse.builder().build();
r1.setId(id);
TypeReferenceResponse r2 = TypeReferenceResponse.builder().build();
r2.setId(id);
assertThat(r1).isEqualTo(r2);
assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
}
}