feat(api): DTOs v3.0 — membre computed fields, CreateMembreRequest builder, souscription DTOs, RBAC enums enrichis

- MembreResponse: ajout getInitiales(), getDateAdhesionFormatee(), getStatut(), getSeverity() computed
- CotisationResponse: alias getMethodePaiementLibelle()
- CreateMembreRequest: builder pattern, organisationId UUID
- Nouveaux DTOs souscription: FormuleAbonnementResponse, SouscriptionDemandeRequest, SouscriptionStatutResponse
- Nouveaux enums: PlageMembres, StatutValidationSouscription, TypeOrganisationFacturation
- StatutMembre enrichi (RADIE, ARCHIVE, INVITE, EN_ATTENTE_VALIDATION)
- TypeOrganisation, TypeFormule, StatutSouscription mis à jour
This commit is contained in:
dahoud
2026-04-07 20:51:10 +00:00
parent fb14bac741
commit 5fa4711a8f
42 changed files with 2330 additions and 58 deletions

View File

@@ -0,0 +1,21 @@
package dev.lions.unionflow.server.api.dto.common;
import com.fasterxml.jackson.annotation.JsonInclude;
/**
* 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) {
/** Constructeur pratique avec message uniquement (cas le plus courant). */
public static ErrorResponse of(String message) {
return new ErrorResponse(message, null);
}
/** Constructeur pratique avec les deux champs (compatibilité avec l'ancien format). */
public static ErrorResponse ofError(String error) {
return new ErrorResponse(null, error);
}
}

View File

@@ -96,6 +96,32 @@ public class CotisationResponse extends BaseResponse {
private Long joursRetard; private Long joursRetard;
private Boolean enRetard; private Boolean enRetard;
// === MÉTHODES DE FORMATAGE ===
public String getMontantDuFormatte() {
if (montantDu == null) return "0 FCFA";
return String.format(java.util.Locale.US, "%,.0f %s", montantDu, codeDevise != null ? codeDevise : "FCFA");
}
public String getMontantPayeFormatte() {
if (montantPaye == null) return "0 FCFA";
return String.format(java.util.Locale.US, "%,.0f %s", montantPaye, codeDevise != null ? codeDevise : "FCFA");
}
public String getMontantRestantFormatte() {
if (montantRestant == null) return "0 FCFA";
return String.format(java.util.Locale.US, "%,.0f %s", montantRestant, codeDevise != null ? codeDevise : "FCFA");
}
public boolean isMontantRestantPositif() {
return montantRestant != null && montantRestant.signum() > 0;
}
/** Alias de {@link #modePaiementLibelle} pour #{cotisation.methodePaiementLibelle}. */
public String getMethodePaiementLibelle() {
return modePaiementLibelle;
}
// Informations de paiement // Informations de paiement
private String methodePaiement; // WAVE_MONEY, VIREMENT, ESPECES, CARTE, MOBILE_MONEY private String methodePaiement; // WAVE_MONEY, VIREMENT, ESPECES, CARTE, MOBILE_MONEY
private String referencePaiement; // Référence externe du paiement private String referencePaiement; // Référence externe du paiement

View File

@@ -5,6 +5,7 @@ import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement; import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement; import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier; import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
@@ -151,10 +152,82 @@ public class EvenementResponse extends BaseResponse {
return typeEvenement != null ? typeEvenement.getLibelle() : "Non défini"; return typeEvenement != null ? typeEvenement.getLibelle() : "Non défini";
} }
public String getTypeEvenementIcon() {
if (typeEvenement == null) return "pi pi-calendar";
return switch (typeEvenement) {
case ASSEMBLEE_GENERALE -> "pi pi-building";
case FORMATION -> "pi pi-book";
case REUNION_BUREAU -> "pi pi-users";
case CONFERENCE -> "pi pi-microphone";
case ATELIER -> "pi pi-wrench";
case CEREMONIE -> "pi pi-flag";
case ACTIVITE_SOCIALE, ACTION_CARITATIVE, AUTRE -> "pi pi-calendar";
};
}
public String getTypeEvenementSeverity() {
if (typeEvenement == null) return "secondary";
return switch (typeEvenement) {
case ASSEMBLEE_GENERALE -> "warning";
case FORMATION -> "info";
case ACTIVITE_SOCIALE, ACTION_CARITATIVE, REUNION_BUREAU, CONFERENCE, ATELIER, CEREMONIE, AUTRE -> "secondary";
};
}
public String getStatutLibelle() { public String getStatutLibelle() {
return statut != null ? statut.getLibelle() : "Non défini"; return statut != null ? statut.getLibelle() : "Non défini";
} }
public String getStatutSeverity() {
if (statut == null) return "secondary";
return switch (statut) {
case PLANIFIE -> "info";
case EN_COURS -> "success";
case TERMINE, CONFIRME -> "secondary";
case ANNULE -> "danger";
case REPORTE -> "warning";
};
}
public String getDateDebutFormatee() {
return dateDebut != null ? dateDebut.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) : "";
}
public String getHeureDebutFormatee() {
return heureDebut != null ? heureDebut.format(DateTimeFormatter.ofPattern("HH:mm")) : "";
}
public String getHeureFinFormatee() {
return heureFin != null ? heureFin.format(DateTimeFormatter.ofPattern("HH:mm")) : "";
}
public String getStatutIcon() {
if (statut == null) return "pi pi-question";
return switch (statut) {
case PLANIFIE -> "pi pi-clock";
case CONFIRME -> "pi pi-check-circle";
case EN_COURS -> "pi pi-play";
case TERMINE -> "pi pi-check";
case ANNULE -> "pi pi-times";
case REPORTE -> "pi pi-refresh";
};
}
public String getPrioriteSeverity() {
if (priorite == null) return "secondary";
return switch (priorite) {
case CRITIQUE -> "danger";
case HAUTE -> "warning";
case NORMALE -> "info";
case BASSE -> "secondary";
};
}
public String getBudgetFormate() {
if (budget == null) return "";
return String.format(java.util.Locale.US, "%,.0f %s", budget, codeDevise != null ? codeDevise : "FCFA");
}
public String getPrioriteLibelle() { public String getPrioriteLibelle() {
return priorite != null ? priorite.getLibelle() : "Normale"; return priorite != null ? priorite.getLibelle() : "Normale";
} }

View File

@@ -40,7 +40,7 @@ public record CreateMembreRequest(
@NotBlank @Size(max = 100) String nom, @NotBlank @Size(max = 100) String nom,
@NotBlank @Email @Size(max = 255) String email, @NotBlank @Email @Size(max = 255) String email,
@Size(max = 20) String telephone, @Size(max = 20) String telephone,
@Size(max = 13) String telephoneWave, @Size(max = 20) String telephoneWave,
@NotNull LocalDate dateNaissance, @NotNull LocalDate dateNaissance,
@Size(max = 100) String profession, @Size(max = 100) String profession,
@Size(max = 500) String photoUrl, @Size(max = 500) String photoUrl,

View File

@@ -14,7 +14,7 @@ public record UpdateMembreRequest(
@NotBlank @Size(max = 100) String nom, @NotBlank @Size(max = 100) String nom,
@NotBlank @Email @Size(max = 255) String email, @NotBlank @Email @Size(max = 255) String email,
@Size(max = 20) String telephone, @Size(max = 20) String telephone,
@Size(max = 13) String telephoneWave, @Size(max = 20) String telephoneWave,
@NotNull LocalDate dateNaissance, @NotNull LocalDate dateNaissance,
@Size(max = 100) String profession, @Size(max = 100) String profession,
@Size(max = 500) String photoUrl, @Size(max = 500) String photoUrl,

View File

@@ -2,6 +2,7 @@ package dev.lions.unionflow.server.api.dto.membre.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID; import java.util.UUID;
import java.util.List; import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -65,6 +66,71 @@ public class MembreResponse extends BaseResponse {
// ── Adhésion (contexte organisation) ─────── // ── Adhésion (contexte organisation) ───────
private UUID organisationId; private UUID organisationId;
private String associationNom; private String organisationNom;
private LocalDate dateAdhesion; private LocalDate dateAdhesion;
// ── Adresse principale ─────────────────────
private String adresse;
private String ville;
private String codePostal;
// ── Notes / biographie ─────────────────────
private String notes;
// ── Statistiques ───────────────────────────
private int nombreEvenementsParticipes;
// ── Provisionnement (retourné une seule fois à la création) ────
/** Mot de passe temporaire généré lors du provisionnement Keycloak.
* Null pour toutes les autres opérations. L'utilisateur devra le changer à la première connexion. */
private String motDePasseTemporaire;
// ── Méthodes calculées pour la compatibilité JSF EL ────────────
/** Initiales (première lettre prénom + première lettre nom) pour les avatars JSF. */
public String getInitiales() {
String p = (prenom != null && !prenom.isEmpty()) ? prenom.substring(0, 1).toUpperCase() : "";
String n = (nom != null && !nom.isEmpty()) ? nom.substring(0, 1).toUpperCase() : "";
return p + n;
}
/** Date d'adhésion formatée "dd/MM/yyyy" pour #{membre.dateAdhesionFormatee}. */
public String getDateAdhesionFormatee() {
if (dateAdhesion == null) return null;
return dateAdhesion.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
}
/** Alias de statutCompte pour #{membre.statut}. */
public String getStatut() {
return statutCompte;
}
/** Alias de statutCompteSeverity pour #{membre.statutSeverity}. */
public String getStatutSeverity() {
return statutCompteSeverity;
}
/** Libellé du rôle principal calculé depuis les rôles. */
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";
if (roles.contains("SECRETAIRE")) return "Secrétaire";
if (roles.contains("TRESORIER")) return "Trésorier";
if (roles.contains("ADMIN_ORGANISATION")) return "Administrateur";
if (roles.contains("MODERATEUR")) return "Modérateur";
return "Membre";
}
/** Severity PrimeUI calculée depuis les rôles. */
public String getTypeSeverity() {
if (roles == null || roles.isEmpty()) return "secondary";
if (roles.contains("PRESIDENT")) return "primary";
if (roles.contains("VICE_PRESIDENT")) return "primary";
if (roles.contains("SECRETAIRE")) return "info";
if (roles.contains("TRESORIER")) return "warning";
if (roles.contains("ADMIN_ORGANISATION")) return "danger";
if (roles.contains("MODERATEUR")) return "warning";
return "secondary";
}
} }

View File

@@ -1,10 +1,14 @@
package dev.lions.unionflow.server.api.dto.membre.response; package dev.lions.unionflow.server.api.dto.membre.response;
import java.util.UUID; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID;
/** /**
* DTO de réponse résumé pour Membre (listes et optimisations). * 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.
*/ */
public record MembreSummaryResponse( public record MembreSummaryResponse(
UUID id, UUID id,
@@ -20,5 +24,107 @@ public record MembreSummaryResponse(
Boolean actif, Boolean actif,
List<String> roles, List<String> roles,
UUID organisationId, UUID organisationId,
String associationNom) { String organisationNom,
LocalDate dateAdhesion) {
// ── 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(); }
// ── Propriétés calculées pour la compatibilité JSF EL ──────────────────
/** Prénom + Nom concaténés. */
public String nomComplet() {
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() {
return statutCompte;
}
/** Alias de {@link #statutCompteLibelle()} pour #{membre.statutLibelle}. */
public String statutLibelle() {
return statutCompteLibelle;
}
/** Alias de {@link #statutCompteSeverity()} pour #{membre.statutSeverity}. */
public String statutSeverity() {
return statutCompteSeverity;
}
/** Icône PrimeIcons calculée depuis {@link #statutCompte()}. */
public String statutIcon() {
if (statutCompte == null) return "pi pi-question-circle";
return switch (statutCompte) {
case "ACTIF" -> "pi pi-check-circle";
case "INACTIF" -> "pi pi-pause-circle";
case "SUSPENDU" -> "pi pi-ban";
case "RADIE" -> "pi pi-times-circle";
default -> "pi pi-question-circle";
};
}
/** Libellé du rôle principal calculé depuis {@link #roles()}. */
public String typeMembre() {
if (roles == null || roles.isEmpty()) return "Membre";
if (roles.contains("PRESIDENT")) return "Président";
if (roles.contains("VICE_PRESIDENT")) return "Vice-Président";
if (roles.contains("SECRETAIRE")) return "Secrétaire";
if (roles.contains("TRESORIER")) return "Trésorier";
if (roles.contains("ADMIN_ORGANISATION")) return "Administrateur";
if (roles.contains("MODERATEUR")) return "Modérateur";
return "Membre";
}
/** Severity PrimeUI calculée depuis {@link #roles()}. */
public String typeSeverity() {
if (roles == null || roles.isEmpty()) return "secondary";
if (roles.contains("PRESIDENT")) return "primary";
if (roles.contains("VICE_PRESIDENT")) return "primary";
if (roles.contains("SECRETAIRE")) return "info";
if (roles.contains("TRESORIER")) return "warning";
if (roles.contains("ADMIN_ORGANISATION")) return "danger";
if (roles.contains("MODERATEUR")) return "warning";
return "secondary";
}
/** Icône PrimeIcons calculée depuis {@link #roles()}. */
public String typeIcon() {
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";
if (roles.contains("SECRETAIRE")) return "pi pi-file-edit";
if (roles.contains("TRESORIER")) return "pi pi-wallet";
if (roles.contains("ADMIN_ORGANISATION")) return "pi pi-shield";
if (roles.contains("MODERATEUR")) return "pi pi-wrench";
return "pi pi-user";
}
} }

View File

@@ -70,5 +70,12 @@ public record CreateOrganisationRequest(
@Size(max = 1000) String partenaires, @Size(max = 1000) String partenaires,
@Size(max = 1000) String notes, @Size(max = 1000) String notes,
BigDecimal latitude, BigDecimal latitude,
BigDecimal longitude) { BigDecimal longitude,
@Size(max = 500) String adresse,
@Size(max = 100) String ville,
@Size(max = 100) String region,
@Size(max = 100) String pays,
@Size(max = 20) String codePostal,
Boolean organisationPublique,
Boolean accepteNouveauxMembres) {
} }

View File

@@ -44,5 +44,12 @@ public record UpdateOrganisationRequest(
@Size(max = 1000) String partenaires, @Size(max = 1000) String partenaires,
@Size(max = 1000) String notes, @Size(max = 1000) String notes,
BigDecimal latitude, BigDecimal latitude,
BigDecimal longitude) { BigDecimal longitude,
@Size(max = 500) String adresse,
@Size(max = 100) String ville,
@Size(max = 100) String region,
@Size(max = 100) String pays,
@Size(max = 20) String codePostal,
Boolean organisationPublique,
Boolean accepteNouveauxMembres) {
} }

View File

@@ -29,7 +29,7 @@ public record InitierPaiementEnLigneRequest(
message = "Méthode de paiement invalide. Valeurs autorisées : WAVE, ORANGE_MONEY, FREE_MONEY, CARTE_BANCAIRE") message = "Méthode de paiement invalide. Valeurs autorisées : WAVE, ORANGE_MONEY, FREE_MONEY, CARTE_BANCAIRE")
String methodePaiement, String methodePaiement,
@NotBlank(message = "Le numéro de téléphone est obligatoire") /** 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)") @Pattern(regexp = "^\\d{9,15}$", message = "Numéro de téléphone invalide (9-15 chiffres)")
String numeroTelephone, String numeroTelephone,

View File

@@ -0,0 +1,24 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
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é.
*/
@Builder
public record IntentionStatutResponse(
UUID intentionId,
/** INITIEE | EN_COURS | COMPLETEE | EXPIREE | ECHOUEE */
String statut,
/** URL à encoder en QR code (wave_launch_url Wave Checkout) */
String waveLaunchUrl,
String waveCheckoutSessionId,
/** ID de transaction Wave (TCN...) — disponible quand COMPLETEE */
String waveTransactionId,
BigDecimal montant,
String referenceCotisation,
String message
) {}

View File

@@ -0,0 +1,128 @@
package dev.lions.unionflow.server.api.dto.souscription;
import java.math.BigDecimal;
/**
* Représentation publique d'une formule d'abonnement UnionFlow.
*
* <p>Retournée par le endpoint {@code GET /api/souscriptions/formules} (PermitAll).
* Les prix affichés sont les prix de base avant application des coefficients
* de type d'organisation et de période.
*
* @author UnionFlow Team
* @version 1.0
* @since 2026-03-30
*/
public class FormuleAbonnementResponse {
/** Code de la formule : BASIC, STANDARD, PREMIUM */
private String code;
/** Libellé court de la formule */
private String libelle;
/** Description marketing de la formule */
private String description;
/** Code de la plage de membres : PETITE, MOYENNE, GRANDE, TRES_GRANDE */
private String plage;
/** Libellé de la plage (ex: "Petite structure (1100 membres)") */
private String plageLibelle;
/** Nombre minimum de membres pour cette plage */
private int minMembres;
/**
* Nombre maximum de membres pour cette plage.
* -1 signifie illimité (TRES_GRANDE).
*/
private int maxMembres;
/** Prix mensuel de base en XOF (sans remise de période ni coefficient) */
private BigDecimal prixMensuel;
/** Prix annuel équivalent (prixMensuel × 12 × coefficient annuel) */
private BigDecimal prixAnnuel;
/** Ordre d'affichage dans le catalogue */
private int ordreAffichage;
// ── Champs Option C ───────────────────────────────────────────────────────
/** Nom commercial du plan (MICRO, DECOUVERTE, ESSENTIEL, AVANCE, PROFESSIONNEL, ENTERPRISE) */
private String planCommercial;
/** Niveau de reporting (BASIQUE, STANDARD, AVANCE) */
private String niveauReporting;
/** Accès à l'API REST inclus */
private boolean apiAccess;
/** Module fédération multi-org inclus (ENTERPRISE) */
private boolean federationAccess;
/** Support prioritaire inclus */
private boolean supportPrioritaire;
/** SLA garanti (ex: "99.0%", "99.9%") */
private String slaGaranti;
/** Nombre maximum d'administrateurs (-1 = illimité) */
private int maxAdmins;
public FormuleAbonnementResponse() {}
// ─── Getters & Setters ───────────────────────────────────────────────────────
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getLibelle() { return libelle; }
public void setLibelle(String libelle) { this.libelle = libelle; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getPlage() { return plage; }
public void setPlage(String plage) { this.plage = plage; }
public String getPlageLibelle() { return plageLibelle; }
public void setPlageLibelle(String plageLibelle) { this.plageLibelle = plageLibelle; }
public int getMinMembres() { return minMembres; }
public void setMinMembres(int minMembres) { this.minMembres = minMembres; }
public int getMaxMembres() { return maxMembres; }
public void setMaxMembres(int maxMembres) { this.maxMembres = maxMembres; }
public BigDecimal getPrixMensuel() { return prixMensuel; }
public void setPrixMensuel(BigDecimal prixMensuel) { this.prixMensuel = prixMensuel; }
public BigDecimal getPrixAnnuel() { return prixAnnuel; }
public void setPrixAnnuel(BigDecimal prixAnnuel) { this.prixAnnuel = prixAnnuel; }
public int getOrdreAffichage() { return ordreAffichage; }
public void setOrdreAffichage(int ordreAffichage) { this.ordreAffichage = ordreAffichage; }
public String getPlanCommercial() { return planCommercial; }
public void setPlanCommercial(String planCommercial) { this.planCommercial = planCommercial; }
public String getNiveauReporting() { return niveauReporting; }
public void setNiveauReporting(String niveauReporting) { this.niveauReporting = niveauReporting; }
public boolean isApiAccess() { return apiAccess; }
public void setApiAccess(boolean apiAccess) { this.apiAccess = apiAccess; }
public boolean isFederationAccess() { return federationAccess; }
public void setFederationAccess(boolean federationAccess) { this.federationAccess = federationAccess; }
public boolean isSupportPrioritaire() { return supportPrioritaire; }
public void setSupportPrioritaire(boolean supportPrioritaire) { this.supportPrioritaire = supportPrioritaire; }
public String getSlaGaranti() { return slaGaranti; }
public void setSlaGaranti(String slaGaranti) { this.slaGaranti = slaGaranti; }
public int getMaxAdmins() { return maxAdmins; }
public void setMaxAdmins(int maxAdmins) { this.maxAdmins = maxAdmins; }
}

View File

@@ -0,0 +1,79 @@
package dev.lions.unionflow.server.api.dto.souscription;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* Requête de création d'une demande de souscription UnionFlow.
*
* <p>Envoyée par l'ADMIN_ORGANISATION lors de l'onboarding pour sélectionner
* la formule, la plage de membres, la période et le type de son organisation.
*
* @author UnionFlow Team
* @version 1.0
* @since 2026-03-30
*/
public class SouscriptionDemandeRequest {
/** Niveau de formule : BASIC, STANDARD, PREMIUM */
@NotBlank(message = "Le type de formule est obligatoire")
private String typeFormule;
/** Tranche de membres : PETITE, MOYENNE, GRANDE, TRES_GRANDE */
@NotBlank(message = "La plage de membres est obligatoire")
private String plageMembres;
/** Périodicité de facturation : MENSUEL, TRIMESTRIEL, SEMESTRIEL, ANNUEL */
@NotBlank(message = "Le type de période est obligatoire")
private String typePeriode;
/** Type d'organisation pour le calcul du coefficient : ASSOCIATION, MUTUELLE, COOPERATIVE, FEDERATION
* Optionnel — si absent, le service le dérive depuis l'entité Organisation. */
private String typeOrganisation;
/** UUID de l'organisation concernée */
@NotNull(message = "L'identifiant de l'organisation est obligatoire")
private String organisationId;
public SouscriptionDemandeRequest() {}
public String getTypeFormule() {
return typeFormule;
}
public void setTypeFormule(String typeFormule) {
this.typeFormule = typeFormule;
}
public String getPlageMembres() {
return plageMembres;
}
public void setPlageMembres(String plageMembres) {
this.plageMembres = plageMembres;
}
public String getTypePeriode() {
return typePeriode;
}
public void setTypePeriode(String typePeriode) {
this.typePeriode = typePeriode;
}
public String getTypeOrganisation() {
return typeOrganisation;
}
public void setTypeOrganisation(String typeOrganisation) {
this.typeOrganisation = typeOrganisation;
}
public String getOrganisationId() {
return organisationId;
}
public void setOrganisationId(String organisationId) {
this.organisationId = organisationId;
}
}

View File

@@ -0,0 +1,155 @@
package dev.lions.unionflow.server.api.dto.souscription;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* Réponse décrivant l'état courant d'une souscription UnionFlow.
*
* <p>Retournée par les endpoints de création de demande, de consultation
* et d'initiation du paiement Wave.
*
* @author UnionFlow Team
* @version 1.0
* @since 2026-03-30
*/
public class SouscriptionStatutResponse {
private String souscriptionId;
private String statutValidation;
private String statutLibelle;
private String typeFormule;
private String plageMembres;
private String plageLibelle;
private String typePeriode;
private String typeOrganisation;
private BigDecimal montantTotal;
private BigDecimal montantMensuelBase;
private BigDecimal coefficientApplique;
private String waveSessionId;
/** URL Wave à ouvrir dans le navigateur/WebView pour initier le paiement. */
private String waveLaunchUrl;
private LocalDate dateDebut;
private LocalDate dateFin;
private LocalDate dateValidation;
private String commentaireRejet;
private String organisationId;
private String organisationNom;
// ── Quota & features (Option C) ─────────────────────────────────────────
private Integer quotaMax;
private Integer quotaUtilise;
private Integer quotaRestant;
private boolean quotaDepasse;
private String planCommercial;
private boolean apiAccess;
private boolean federationAccess;
private boolean supportPrioritaire;
private String slaGaranti;
private Integer maxAdmins;
private String niveauReporting;
/** Nombre de jours avant expiration (négatif = déjà expiré) */
private long joursAvantExpiration;
/** Statut de la souscription : ACTIVE, EXPIREE, SUSPENDUE, EN_ATTENTE, RESILIEE */
private String statut;
public SouscriptionStatutResponse() {}
// ─── Getters & Setters ───────────────────────────────────────────────────────
public String getSouscriptionId() { return souscriptionId; }
public void setSouscriptionId(String souscriptionId) { this.souscriptionId = souscriptionId; }
public String getStatutValidation() { return statutValidation; }
public void setStatutValidation(String statutValidation) { this.statutValidation = statutValidation; }
public String getStatutLibelle() { return statutLibelle; }
public void setStatutLibelle(String statutLibelle) { this.statutLibelle = statutLibelle; }
public String getTypeFormule() { return typeFormule; }
public void setTypeFormule(String typeFormule) { this.typeFormule = typeFormule; }
public String getPlageMembres() { return plageMembres; }
public void setPlageMembres(String plageMembres) { this.plageMembres = plageMembres; }
public String getPlageLibelle() { return plageLibelle; }
public void setPlageLibelle(String plageLibelle) { this.plageLibelle = plageLibelle; }
public String getTypePeriode() { return typePeriode; }
public void setTypePeriode(String typePeriode) { this.typePeriode = typePeriode; }
public String getTypeOrganisation() { return typeOrganisation; }
public void setTypeOrganisation(String typeOrganisation) { this.typeOrganisation = typeOrganisation; }
public BigDecimal getMontantTotal() { return montantTotal; }
public void setMontantTotal(BigDecimal montantTotal) { this.montantTotal = montantTotal; }
public BigDecimal getMontantMensuelBase() { return montantMensuelBase; }
public void setMontantMensuelBase(BigDecimal montantMensuelBase) { this.montantMensuelBase = montantMensuelBase; }
public BigDecimal getCoefficientApplique() { return coefficientApplique; }
public void setCoefficientApplique(BigDecimal coefficientApplique) { this.coefficientApplique = coefficientApplique; }
public String getWaveSessionId() { return waveSessionId; }
public void setWaveSessionId(String waveSessionId) { this.waveSessionId = waveSessionId; }
public String getWaveLaunchUrl() { return waveLaunchUrl; }
public void setWaveLaunchUrl(String waveLaunchUrl) { this.waveLaunchUrl = waveLaunchUrl; }
public LocalDate getDateDebut() { return dateDebut; }
public void setDateDebut(LocalDate dateDebut) { this.dateDebut = dateDebut; }
public LocalDate getDateFin() { return dateFin; }
public void setDateFin(LocalDate dateFin) { this.dateFin = dateFin; }
public LocalDate getDateValidation() { return dateValidation; }
public void setDateValidation(LocalDate dateValidation) { this.dateValidation = dateValidation; }
public String getCommentaireRejet() { return commentaireRejet; }
public void setCommentaireRejet(String commentaireRejet) { this.commentaireRejet = commentaireRejet; }
public String getOrganisationId() { return organisationId; }
public void setOrganisationId(String organisationId) { this.organisationId = organisationId; }
public String getOrganisationNom() { return organisationNom; }
public void setOrganisationNom(String organisationNom) { this.organisationNom = organisationNom; }
public Integer getQuotaMax() { return quotaMax; }
public void setQuotaMax(Integer quotaMax) { this.quotaMax = quotaMax; }
public Integer getQuotaUtilise() { return quotaUtilise; }
public void setQuotaUtilise(Integer quotaUtilise) { this.quotaUtilise = quotaUtilise; }
public Integer getQuotaRestant() { return quotaRestant; }
public void setQuotaRestant(Integer quotaRestant) { this.quotaRestant = quotaRestant; }
public boolean isQuotaDepasse() { return quotaDepasse; }
public void setQuotaDepasse(boolean quotaDepasse) { this.quotaDepasse = quotaDepasse; }
public String getPlanCommercial() { return planCommercial; }
public void setPlanCommercial(String planCommercial) { this.planCommercial = planCommercial; }
public boolean isApiAccess() { return apiAccess; }
public void setApiAccess(boolean apiAccess) { this.apiAccess = apiAccess; }
public boolean isFederationAccess() { return federationAccess; }
public void setFederationAccess(boolean federationAccess) { this.federationAccess = federationAccess; }
public boolean isSupportPrioritaire() { return supportPrioritaire; }
public void setSupportPrioritaire(boolean supportPrioritaire) { this.supportPrioritaire = supportPrioritaire; }
public String getSlaGaranti() { return slaGaranti; }
public void setSlaGaranti(String slaGaranti) { this.slaGaranti = slaGaranti; }
public Integer getMaxAdmins() { return maxAdmins; }
public void setMaxAdmins(Integer maxAdmins) { this.maxAdmins = maxAdmins; }
public String getNiveauReporting() { return niveauReporting; }
public void setNiveauReporting(String niveauReporting) { this.niveauReporting = niveauReporting; }
public long getJoursAvantExpiration() { return joursAvantExpiration; }
public void setJoursAvantExpiration(long joursAvantExpiration) { this.joursAvantExpiration = joursAvantExpiration; }
public String getStatut() { return statut; }
public void setStatut(String statut) { this.statut = statut; }
}

View File

@@ -0,0 +1,64 @@
package dev.lions.unionflow.server.api.enums.abonnement;
/**
* Tranches de taille d'organisation pour le calcul tarifaire UnionFlow.
*
* <p>Chaque plage définit un intervalle [min, max] de membres.
* La plage TRES_GRANDE est sans limite supérieure (Integer.MAX_VALUE).
*
* @author UnionFlow Team
* @version 1.0
* @since 2026-03-30
*/
public enum PlageMembres {
PETITE("Petite structure (1100 membres)", 1, 100),
MOYENNE("Moyenne structure (101500 membres)", 101, 500),
GRANDE("Grande structure (5012 000 membres)", 501, 2000),
TRES_GRANDE("Très grande structure (2 000+ membres)", 2001, Integer.MAX_VALUE);
private final String libelle;
private final int min;
private final int max;
PlageMembres(String libelle, int min, int max) {
this.libelle = libelle;
this.min = min;
this.max = max;
}
/**
* Détermine la plage tarifaire correspondant à un nombre de membres donné.
*
* @param nombre nombre de membres de l'organisation
* @return la plage correspondante (TRES_GRANDE si aucune ne correspond)
*/
public static PlageMembres fromNombreMembres(int nombre) {
for (PlageMembres p : values()) {
if (nombre >= p.min && nombre <= p.max) {
return p;
}
}
return TRES_GRANDE;
}
public String getLibelle() {
return libelle;
}
public int getMin() {
return min;
}
/**
* Retourne le max de membres pour la plage.
* Retourne -1 pour TRES_GRANDE (illimité) afin de faciliter la sérialisation JSON.
*/
public int getMaxAffichage() {
return this == TRES_GRANDE ? -1 : max;
}
public int getMax() {
return max;
}
}

View File

@@ -1,6 +1,7 @@
package dev.lions.unionflow.server.api.enums.abonnement; package dev.lions.unionflow.server.api.enums.abonnement;
public enum StatutSouscription { public enum StatutSouscription {
EN_ATTENTE("En attente de validation"),
ACTIVE("Active"), ACTIVE("Active"),
EXPIREE("Expirée"), EXPIREE("Expirée"),
SUSPENDUE("Suspendue — quota dépassé ou impayé"), SUSPENDUE("Suspendue — quota dépassé ou impayé"),

View File

@@ -0,0 +1,43 @@
package dev.lions.unionflow.server.api.enums.abonnement;
/**
* Cycle de vie de validation d'une souscription UnionFlow.
*
* <p>Transitions valides :
* <pre>
* EN_ATTENTE_PAIEMENT → PAIEMENT_INITIE → PAIEMENT_CONFIRME → VALIDEE
* ↘ REJETEE
* </pre>
*
* @author UnionFlow Team
* @version 1.0
* @since 2026-03-30
*/
public enum StatutValidationSouscription {
EN_ATTENTE_PAIEMENT("En attente de paiement — souscription créée"),
PAIEMENT_INITIE("Paiement initié — session Wave ouverte"),
PAIEMENT_CONFIRME("Paiement confirmé — en attente de validation SuperAdmin"),
VALIDEE("Validée — compte activé"),
REJETEE("Rejetée — souscription refusée");
private final String libelle;
StatutValidationSouscription(String libelle) {
this.libelle = libelle;
}
public String getLibelle() {
return libelle;
}
/** Indique si la souscription est dans un état terminal (non modifiable). */
public boolean isTerminal() {
return this == VALIDEE || this == REJETEE;
}
/** Indique si un paiement Wave peut être initié depuis cet état. */
public boolean peutInitierPaiement() {
return this == EN_ATTENTE_PAIEMENT;
}
}

View File

@@ -1,17 +1,23 @@
package dev.lions.unionflow.server.api.enums.abonnement; package dev.lions.unionflow.server.api.enums.abonnement;
/** /**
* Énumération des types de formules d'abonnement UnionFlow * Niveaux de formule d'abonnement UnionFlow.
*
* <p>Trois niveaux disponibles, chacun applicable à toutes les plages de taille
* ({@link PlageMembres}). Les prix de base sont définis dans la matrice tarifaire
* et varient selon la plage et le type d'organisation.
*
* <p>Migration depuis l'ancien enum : STARTER→BASIC, CRYSTAL supprimé.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 2.0
* @since 2025-01-10 * @since 2026-03-30
*/ */
public enum TypeFormule { public enum TypeFormule {
STARTER("Starter — 1 à 50 membres — 5 000 XOF/mois"),
STANDARD("Standard — 51 à 200 membres — 7 000 XOF/mois"), BASIC("Basic"),
PREMIUM("Premium — 201 à 500 membres — 9 000 XOF/mois"), STANDARD("Standard"),
CRYSTAL("Crystal — 501+ membres — 10 000 XOF/mois"); PREMIUM("Premium");
private final String libelle; private final String libelle;

View File

@@ -0,0 +1,51 @@
package dev.lions.unionflow.server.api.enums.abonnement;
import java.math.BigDecimal;
/**
* Catégorie tarifaire d'une organisation pour le calcul du prix de souscription.
*
* <p>Distinct de {@code TypeOrganisation} (catégorisation métier).
* Chaque valeur porte deux coefficients multiplicateurs :
* <ul>
* <li>{@code coefficientBase} — appliqué aux formules BASIC et STANDARD</li>
* <li>{@code coefficientPremium} — appliqué uniquement à la formule PREMIUM</li>
* </ul>
*
* <p>Exemple : FEDERATION paye le tarif normal (×1.0) en BASIC/STANDARD
* mais un coefficient ×1.5 en PREMIUM (fonctionnalités multi-entités).
*/
public enum TypeOrganisationFacturation {
ASSOCIATION("Association / ONG locale", new BigDecimal("1.0"), new BigDecimal("1.0")),
MUTUELLE("Mutuelle (santé, fonctionnaires, scolaires)", new BigDecimal("1.2"), new BigDecimal("1.2")),
COOPERATIVE("Coopérative / Microfinance", new BigDecimal("1.3"), new BigDecimal("1.3")),
FEDERATION("Fédération / Grande ONG", new BigDecimal("1.0"), new BigDecimal("1.5"));
private final String libelle;
private final BigDecimal coefficientBase;
private final BigDecimal coefficientPremium;
TypeOrganisationFacturation(String libelle, BigDecimal coefficientBase, BigDecimal coefficientPremium) {
this.libelle = libelle;
this.coefficientBase = coefficientBase;
this.coefficientPremium = coefficientPremium;
}
/**
* Retourne le coefficient tarifaire approprié selon le code de formule.
*
* @param typeFormule code de la formule (BASIC, STANDARD, PREMIUM)
* @return coefficient multiplicateur du prix mensuel de base
*/
public BigDecimal getCoefficient(String typeFormule) {
if ("PREMIUM".equals(typeFormule) && this == FEDERATION) {
return coefficientPremium;
}
return coefficientBase;
}
public String getLibelle() { return libelle; }
public BigDecimal getCoefficientBase() { return coefficientBase; }
public BigDecimal getCoefficientPremium() { return coefficientPremium; }
}

View File

@@ -1,12 +1,50 @@
package dev.lions.unionflow.server.api.enums.abonnement; package dev.lions.unionflow.server.api.enums.abonnement;
import java.math.BigDecimal;
/**
* Périodes d'abonnement UnionFlow avec remises associées.
*
* <p>Le {@code coefficient} est multiplié par le prix mensuel de base,
* puis par le nombre de mois pour obtenir le montant total.
*
* <ul>
* <li>MENSUEL : prix normal × 1 mois</li>
* <li>TRIMESTRIEL : prix × 0.95 × 3 mois (5% de remise)</li>
* <li>SEMESTRIEL : prix × 0.90 × 6 mois (10% de remise)</li>
* <li>ANNUEL : prix × 0.80 × 12 mois (20% de remise, équivaut à 2 mois offerts)</li>
* </ul>
*
* @author UnionFlow Team
* @version 2.0
* @since 2026-03-30
*/
public enum TypePeriodeAbonnement { public enum TypePeriodeAbonnement {
MENSUEL("Mensuel"),
ANNUEL("Annuel — 2 mois offerts"); MENSUEL("Mensuel", 1, new BigDecimal("1.00")),
TRIMESTRIEL("Trimestriel — 5% de remise", 3, new BigDecimal("0.95")),
SEMESTRIEL("Semestriel — 10% de remise", 6, new BigDecimal("0.90")),
ANNUEL("Annuel — 20% de remise (2 mois offerts)", 12, new BigDecimal("0.80"));
private final String libelle; private final String libelle;
private final int nombreMois;
private final BigDecimal coefficient;
TypePeriodeAbonnement(String libelle) { this.libelle = libelle; } TypePeriodeAbonnement(String libelle, int nombreMois, BigDecimal coefficient) {
this.libelle = libelle;
this.nombreMois = nombreMois;
this.coefficient = coefficient;
}
public String getLibelle() { return libelle; } public String getLibelle() {
return libelle;
}
public int getNombreMois() {
return nombreMois;
}
public BigDecimal getCoefficient() {
return coefficient;
}
} }

View File

@@ -8,6 +8,7 @@ package dev.lions.unionflow.server.api.enums.membre;
* @since 2025-01-10 * @since 2025-01-10
*/ */
public enum StatutMembre { public enum StatutMembre {
INVITE("Invité — en attente d'acceptation"),
EN_ATTENTE_VALIDATION("En attente de validation"), EN_ATTENTE_VALIDATION("En attente de validation"),
ACTIF("Actif"), ACTIF("Actif"),
INACTIF("Inactif — cotisations en retard"), INACTIF("Inactif — cotisations en retard"),
@@ -15,7 +16,8 @@ public enum StatutMembre {
DEMISSIONNAIRE("Démissionnaire"), DEMISSIONNAIRE("Démissionnaire"),
RADIE("Radié — exclusion définitive"), RADIE("Radié — exclusion définitive"),
HONORAIRE("Honoraire — sans cotisation obligatoire"), HONORAIRE("Honoraire — sans cotisation obligatoire"),
DECEDE("Décédé — archivage / gestion ayants droit"); DECEDE("Décédé — archivage / gestion ayants droit"),
ARCHIVE("Archivé — données conservées, accès révoqué");
private final String libelle; private final String libelle;

View File

@@ -1,21 +1,26 @@
package dev.lions.unionflow.server.api.enums.organisation; package dev.lions.unionflow.server.api.enums.organisation;
/** /**
* Énumération des types d'organisations supportés par UnionFlow * Types d'organisations supportées par UnionFlow.
*
* <p>Utilisé pour la <strong>catégorisation métier</strong> des organisations
* (Lions Club, Mutuelle santé, ONG, etc.). Ne pas confondre avec
* {@link TypeOrganisationFacturation} qui porte les coefficients tarifaires.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-10 * @since 2025-01-10
*/ */
public enum TypeOrganisation { public enum TypeOrganisation {
ASSOCIATION("Association"), ASSOCIATION("Association"),
MUTUELLE_EPARGNE_CREDIT("Mutuelle d'épargne et de crédit"), MUTUELLE_EPARGNE_CREDIT("Mutuelle d'épargne et de crédit"),
MUTUELLE_SANTE("Mutuelle de santé"), MUTUELLE_SANTE("Mutuelle de santé"),
TONTINE("Tontine / épargne rotative"), TONTINE("Tontine / épargne rotative"),
ONG("ONG / Association humanitaire"), ONG("ONG / Association humanitaire"),
COOPERATIVE_AGRICOLE("Coopérative agricole / production"), COOPERATIVE_AGRICOLE("Coopérative agricole"),
ASSOCIATION_PROFESSIONNELLE("Association professionnelle / Ordre"), ASSOCIATION_PROFESSIONNELLE("Association professionnelle"),
ASSOCIATION_COMMUNAUTAIRE("Association communautaire / quartier"), ASSOCIATION_COMMUNAUTAIRE("Association communautaire"),
ORGANISATION_RELIGIEUSE("Organisation religieuse"), ORGANISATION_RELIGIEUSE("Organisation religieuse"),
FEDERATION("Fédération / Union d'associations"), FEDERATION("Fédération / Union d'associations"),
SYNDICAT("Syndicat non partisan"), SYNDICAT("Syndicat non partisan"),

View File

@@ -40,7 +40,7 @@ public final class TestDataFactory {
String email) { String email) {
return new MembreSummaryResponse( return new MembreSummaryResponse(
UUID.randomUUID(), numero, prenom, nom, email, "0102030405", "Profession", "ACTIF", "Actif", "success", true, UUID.randomUUID(), numero, prenom, nom, email, "0102030405", "Profession", "ACTIF", "Actif", "success", true,
List.of("MEMBRE"), null, null); List.of("MEMBRE"), null, null, null);
} }
public static CreateMembreRequest createCreateMembreRequest(int age) { public static CreateMembreRequest createCreateMembreRequest(int age) {

View File

@@ -132,6 +132,102 @@ class CotisationResponseTest {
} }
} }
@Nested
@DisplayName("Méthodes de formatage des montants")
class MethodesFormatageMontants {
@Test
@DisplayName("getMontantDuFormatte retourne 0 FCFA quand montantDu null")
void testMontantDuNull() {
CotisationResponse r = CotisationResponse.builder().build();
assertThat(r.getMontantDuFormatte()).isEqualTo("0 FCFA");
}
@Test
@DisplayName("getMontantDuFormatte formate avec devise par défaut FCFA")
void testMontantDuSansDevise() {
CotisationResponse r = CotisationResponse.builder().montantDu(BigDecimal.valueOf(5000)).build();
assertThat(r.getMontantDuFormatte()).isEqualTo("5,000 FCFA");
}
@Test
@DisplayName("getMontantDuFormatte formate avec codeDevise fourni")
void testMontantDuAvecDevise() {
CotisationResponse r = CotisationResponse.builder().montantDu(BigDecimal.valueOf(5000)).codeDevise("XOF").build();
assertThat(r.getMontantDuFormatte()).isEqualTo("5,000 XOF");
}
@Test
@DisplayName("getMontantPayeFormatte retourne 0 FCFA quand montantPaye null")
void testMontantPayeNull() {
CotisationResponse r = CotisationResponse.builder().build();
assertThat(r.getMontantPayeFormatte()).isEqualTo("0 FCFA");
}
@Test
@DisplayName("getMontantPayeFormatte formate avec devise par défaut FCFA")
void testMontantPayeSansDevise() {
CotisationResponse r = CotisationResponse.builder().montantPaye(BigDecimal.valueOf(2000)).build();
assertThat(r.getMontantPayeFormatte()).isEqualTo("2,000 FCFA");
}
@Test
@DisplayName("getMontantPayeFormatte formate avec codeDevise fourni")
void testMontantPayeAvecDevise() {
CotisationResponse r = CotisationResponse.builder().montantPaye(BigDecimal.valueOf(2000)).codeDevise("EUR").build();
assertThat(r.getMontantPayeFormatte()).isEqualTo("2,000 EUR");
}
@Test
@DisplayName("getMontantRestantFormatte retourne 0 FCFA quand montantRestant null")
void testMontantRestantNull() {
CotisationResponse r = CotisationResponse.builder().build();
assertThat(r.getMontantRestantFormatte()).isEqualTo("0 FCFA");
}
@Test
@DisplayName("getMontantRestantFormatte formate avec devise par défaut FCFA")
void testMontantRestantSansDevise() {
CotisationResponse r = CotisationResponse.builder().montantRestant(BigDecimal.valueOf(3000)).build();
assertThat(r.getMontantRestantFormatte()).isEqualTo("3,000 FCFA");
}
@Test
@DisplayName("getMontantRestantFormatte formate avec codeDevise fourni")
void testMontantRestantAvecDevise() {
CotisationResponse r = CotisationResponse.builder().montantRestant(BigDecimal.valueOf(3000)).codeDevise("XOF").build();
assertThat(r.getMontantRestantFormatte()).isEqualTo("3,000 XOF");
}
@Test
@DisplayName("isMontantRestantPositif retourne false quand montantRestant null")
void testMontantRestantPositifNull() {
CotisationResponse r = CotisationResponse.builder().build();
assertThat(r.isMontantRestantPositif()).isFalse();
}
@Test
@DisplayName("isMontantRestantPositif retourne false quand montantRestant = 0")
void testMontantRestantPositifZero() {
CotisationResponse r = CotisationResponse.builder().montantRestant(BigDecimal.ZERO).build();
assertThat(r.isMontantRestantPositif()).isFalse();
}
@Test
@DisplayName("isMontantRestantPositif retourne false quand montantRestant négatif")
void testMontantRestantPositifNegatif() {
CotisationResponse r = CotisationResponse.builder().montantRestant(BigDecimal.valueOf(-100)).build();
assertThat(r.isMontantRestantPositif()).isFalse();
}
@Test
@DisplayName("isMontantRestantPositif retourne true quand montantRestant > 0")
void testMontantRestantPositifVrai() {
CotisationResponse r = CotisationResponse.builder().montantRestant(BigDecimal.valueOf(500)).build();
assertThat(r.isMontantRestantPositif()).isTrue();
}
}
@Nested @Nested
@DisplayName("Builder complet") @DisplayName("Builder complet")
class BuilderComplet { class BuilderComplet {

View File

@@ -492,4 +492,259 @@ class EvenementResponseTest {
assertThat(r.estComplet()).isFalse(); assertThat(r.estComplet()).isFalse();
} }
} }
@Nested
@DisplayName("getTypeEvenementIcon")
class GetTypeEvenementIcon {
@Test
@DisplayName("retourne icône par défaut quand type null")
void testNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-calendar");
}
@Test
@DisplayName("ASSEMBLEE_GENERALE → pi pi-building")
void testAssembleeGenerale() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.ASSEMBLEE_GENERALE).build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-building");
}
@Test
@DisplayName("FORMATION → pi pi-book")
void testFormation() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.FORMATION).build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-book");
}
@Test
@DisplayName("REUNION_BUREAU → pi pi-users")
void testReunionBureau() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.REUNION_BUREAU).build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-users");
}
@Test
@DisplayName("CONFERENCE → pi pi-microphone")
void testConference() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.CONFERENCE).build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-microphone");
}
@Test
@DisplayName("ATELIER → pi pi-wrench")
void testAtelier() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.ATELIER).build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-wrench");
}
@Test
@DisplayName("CEREMONIE → pi pi-flag")
void testCeremonie() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.CEREMONIE).build();
assertThat(r.getTypeEvenementIcon()).isEqualTo("pi pi-flag");
}
@Test
@DisplayName("ACTIVITE_SOCIALE, ACTION_CARITATIVE, AUTRE → pi pi-calendar")
void testAutres() {
assertThat(EvenementResponse.builder().typeEvenement(TypeEvenementMetier.ACTIVITE_SOCIALE).build().getTypeEvenementIcon()).isEqualTo("pi pi-calendar");
assertThat(EvenementResponse.builder().typeEvenement(TypeEvenementMetier.ACTION_CARITATIVE).build().getTypeEvenementIcon()).isEqualTo("pi pi-calendar");
assertThat(EvenementResponse.builder().typeEvenement(TypeEvenementMetier.AUTRE).build().getTypeEvenementIcon()).isEqualTo("pi pi-calendar");
}
}
@Nested
@DisplayName("getTypeEvenementSeverity")
class GetTypeEvenementSeverity {
@Test
@DisplayName("retourne secondary quand type null")
void testNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getTypeEvenementSeverity()).isEqualTo("secondary");
}
@Test
@DisplayName("ASSEMBLEE_GENERALE → warning")
void testAssembleeGenerale() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.ASSEMBLEE_GENERALE).build();
assertThat(r.getTypeEvenementSeverity()).isEqualTo("warning");
}
@Test
@DisplayName("FORMATION → info")
void testFormation() {
EvenementResponse r = EvenementResponse.builder().typeEvenement(TypeEvenementMetier.FORMATION).build();
assertThat(r.getTypeEvenementSeverity()).isEqualTo("info");
}
@Test
@DisplayName("autres types → secondary")
void testAutres() {
for (TypeEvenementMetier t : new TypeEvenementMetier[]{
TypeEvenementMetier.ACTIVITE_SOCIALE, TypeEvenementMetier.ACTION_CARITATIVE,
TypeEvenementMetier.REUNION_BUREAU, TypeEvenementMetier.CONFERENCE,
TypeEvenementMetier.ATELIER, TypeEvenementMetier.CEREMONIE, TypeEvenementMetier.AUTRE}) {
assertThat(EvenementResponse.builder().typeEvenement(t).build().getTypeEvenementSeverity())
.as("Type: %s", t).isEqualTo("secondary");
}
}
}
@Nested
@DisplayName("getStatutSeverity")
class GetStatutSeverity {
@Test
@DisplayName("retourne secondary quand statut null")
void testNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getStatutSeverity()).isEqualTo("secondary");
}
@Test
@DisplayName("PLANIFIE → info")
void testPlanifie() {
assertThat(EvenementResponse.builder().statut(StatutEvenement.PLANIFIE).build().getStatutSeverity()).isEqualTo("info");
}
@Test
@DisplayName("EN_COURS → success")
void testEnCours() {
assertThat(EvenementResponse.builder().statut(StatutEvenement.EN_COURS).build().getStatutSeverity()).isEqualTo("success");
}
@Test
@DisplayName("TERMINE et CONFIRME → secondary")
void testTermineConfirme() {
assertThat(EvenementResponse.builder().statut(StatutEvenement.TERMINE).build().getStatutSeverity()).isEqualTo("secondary");
assertThat(EvenementResponse.builder().statut(StatutEvenement.CONFIRME).build().getStatutSeverity()).isEqualTo("secondary");
}
@Test
@DisplayName("ANNULE → danger")
void testAnnule() {
assertThat(EvenementResponse.builder().statut(StatutEvenement.ANNULE).build().getStatutSeverity()).isEqualTo("danger");
}
@Test
@DisplayName("REPORTE → warning")
void testReporte() {
assertThat(EvenementResponse.builder().statut(StatutEvenement.REPORTE).build().getStatutSeverity()).isEqualTo("warning");
}
}
@Nested
@DisplayName("getStatutIcon")
class GetStatutIcon {
@Test
@DisplayName("retourne pi pi-question quand statut null")
void testNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getStatutIcon()).isEqualTo("pi pi-question");
}
@Test
@DisplayName("tous les statuts retournent la bonne icône")
void testTousStatuts() {
assertThat(EvenementResponse.builder().statut(StatutEvenement.PLANIFIE).build().getStatutIcon()).isEqualTo("pi pi-clock");
assertThat(EvenementResponse.builder().statut(StatutEvenement.CONFIRME).build().getStatutIcon()).isEqualTo("pi pi-check-circle");
assertThat(EvenementResponse.builder().statut(StatutEvenement.EN_COURS).build().getStatutIcon()).isEqualTo("pi pi-play");
assertThat(EvenementResponse.builder().statut(StatutEvenement.TERMINE).build().getStatutIcon()).isEqualTo("pi pi-check");
assertThat(EvenementResponse.builder().statut(StatutEvenement.ANNULE).build().getStatutIcon()).isEqualTo("pi pi-times");
assertThat(EvenementResponse.builder().statut(StatutEvenement.REPORTE).build().getStatutIcon()).isEqualTo("pi pi-refresh");
}
}
@Nested
@DisplayName("getPrioriteSeverity")
class GetPrioriteSeverity {
@Test
@DisplayName("retourne secondary quand priorite null")
void testNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getPrioriteSeverity()).isEqualTo("secondary");
}
@Test
@DisplayName("toutes les priorités retournent la bonne sévérité")
void testToutesPriorites() {
assertThat(EvenementResponse.builder().priorite(PrioriteEvenement.CRITIQUE).build().getPrioriteSeverity()).isEqualTo("danger");
assertThat(EvenementResponse.builder().priorite(PrioriteEvenement.HAUTE).build().getPrioriteSeverity()).isEqualTo("warning");
assertThat(EvenementResponse.builder().priorite(PrioriteEvenement.NORMALE).build().getPrioriteSeverity()).isEqualTo("info");
assertThat(EvenementResponse.builder().priorite(PrioriteEvenement.BASSE).build().getPrioriteSeverity()).isEqualTo("secondary");
}
}
@Nested
@DisplayName("getDateDebutFormatee, getHeureDebutFormatee, getHeureFinFormatee, getBudgetFormate")
class MethodesFormatage {
@Test
@DisplayName("getDateDebutFormatee retourne — quand null")
void testDateDebutNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getDateDebutFormatee()).isEqualTo("");
}
@Test
@DisplayName("getDateDebutFormatee formate en dd/MM/yyyy")
void testDateDebut() {
EvenementResponse r = EvenementResponse.builder().dateDebut(java.time.LocalDate.of(2026, 4, 7)).build();
assertThat(r.getDateDebutFormatee()).isEqualTo("07/04/2026");
}
@Test
@DisplayName("getHeureDebutFormatee retourne — quand null")
void testHeureDebutNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getHeureDebutFormatee()).isEqualTo("");
}
@Test
@DisplayName("getHeureDebutFormatee formate en HH:mm")
void testHeureDebut() {
EvenementResponse r = EvenementResponse.builder().heureDebut(java.time.LocalTime.of(9, 30)).build();
assertThat(r.getHeureDebutFormatee()).isEqualTo("09:30");
}
@Test
@DisplayName("getHeureFinFormatee retourne — quand null")
void testHeureFinNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getHeureFinFormatee()).isEqualTo("");
}
@Test
@DisplayName("getHeureFinFormatee formate en HH:mm")
void testHeureFin() {
EvenementResponse r = EvenementResponse.builder().heureFin(java.time.LocalTime.of(18, 0)).build();
assertThat(r.getHeureFinFormatee()).isEqualTo("18:00");
}
@Test
@DisplayName("getBudgetFormate retourne — quand budget null")
void testBudgetNull() {
EvenementResponse r = EvenementResponse.builder().build();
assertThat(r.getBudgetFormate()).isEqualTo("");
}
@Test
@DisplayName("getBudgetFormate formate avec devise par défaut FCFA")
void testBudgetSansDevise() {
EvenementResponse r = EvenementResponse.builder().budget(java.math.BigDecimal.valueOf(50000)).build();
assertThat(r.getBudgetFormate()).isEqualTo("50,000 FCFA");
}
@Test
@DisplayName("getBudgetFormate formate avec codeDevise fourni")
void testBudgetAvecDevise() {
EvenementResponse r = EvenementResponse.builder().budget(java.math.BigDecimal.valueOf(50000)).codeDevise("EUR").build();
assertThat(r.getBudgetFormate()).isEqualTo("50,000 EUR");
}
}
} }

View File

@@ -23,7 +23,7 @@ class MembreSearchResultDTOTest {
private static MembreSummaryResponse unMembre() { private static MembreSummaryResponse unMembre() {
return new MembreSummaryResponse( return new MembreSummaryResponse(
UUID.randomUUID(), null, "Prenom", "Nom", null, null, null, null, null, null, true, List.of(), null, null); UUID.randomUUID(), null, "Prenom", "Nom", null, null, null, null, null, null, true, List.of(), null, null, null);
} }
@Nested @Nested

View File

@@ -0,0 +1,266 @@
package dev.lions.unionflow.server.api.dto.membre;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse;
import java.time.LocalDate;
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 MembreSummaryResponse — méthodes calculées")
class MembreSummaryResponseTest {
private static MembreSummaryResponse make(String statut, List<String> roles) {
return new MembreSummaryResponse(
UUID.randomUUID(), "UF-001", "Jean", "Dupont", "jean@test.com",
"0100000000", "Dev", statut, statut + "_libelle", statut + "_severity",
"ACTIF".equals(statut), roles, null, null, null);
}
// ── nomComplet ─────────────────────────────────────────────────────────
@Nested
@DisplayName("nomComplet()")
class NomComplet {
@Test
@DisplayName("prenom + nom concaténés")
void nominal() {
MembreSummaryResponse r = make("ACTIF", List.of());
assertThat(r.nomComplet()).isEqualTo("Jean Dupont");
}
@Test
@DisplayName("prenom null → uniquement le nom")
void prenomNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, "Dupont", null,
null, null, null, null, null, false, List.of(), null, null, null);
assertThat(r.nomComplet()).isEqualTo("Dupont");
}
@Test
@DisplayName("nom null → uniquement le prenom")
void nomNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, "Jean", null, null,
null, null, null, null, null, false, List.of(), null, null, null);
assertThat(r.nomComplet()).isEqualTo("Jean");
}
@Test
@DisplayName("prenom et nom null → chaîne vide")
void tousNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, null, null,
null, null, null, null, null, false, List.of(), null, null, null);
assertThat(r.nomComplet()).isEmpty();
}
}
// ── Alias statut ───────────────────────────────────────────────────────
@Nested
@DisplayName("aliases statut*()")
class AliasStatut {
@Test
@DisplayName("statut() retourne statutCompte")
void statut() {
MembreSummaryResponse r = make("ACTIF", List.of());
assertThat(r.statut()).isEqualTo(r.statutCompte());
}
@Test
@DisplayName("statutLibelle() retourne statutCompteLibelle")
void statutLibelle() {
MembreSummaryResponse r = make("ACTIF", List.of());
assertThat(r.statutLibelle()).isEqualTo(r.statutCompteLibelle());
}
@Test
@DisplayName("statutSeverity() retourne statutCompteSeverity")
void statutSeverity() {
MembreSummaryResponse r = make("ACTIF", List.of());
assertThat(r.statutSeverity()).isEqualTo(r.statutCompteSeverity());
}
}
// ── statutIcon ─────────────────────────────────────────────────────────
@Nested
@DisplayName("statutIcon()")
class StatutIcon {
@Test void actif() { assertThat(make("ACTIF", List.of()).statutIcon()).isEqualTo("pi pi-check-circle"); }
@Test void inactif() { assertThat(make("INACTIF", List.of()).statutIcon()).isEqualTo("pi pi-pause-circle"); }
@Test void suspendu() { assertThat(make("SUSPENDU", List.of()).statutIcon()).isEqualTo("pi pi-ban"); }
@Test void radie() { assertThat(make("RADIE", List.of()).statutIcon()).isEqualTo("pi pi-times-circle"); }
@Test
@DisplayName("statut inconnu → pi pi-question-circle")
void inconnu() {
assertThat(make("AUTRE", List.of()).statutIcon()).isEqualTo("pi pi-question-circle");
}
@Test
@DisplayName("statut null → pi pi-question-circle")
void statutNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, null, null,
null, null, null, null, null, false, List.of(), null, null, null);
assertThat(r.statutIcon()).isEqualTo("pi pi-question-circle");
}
}
// ── typeMembre ─────────────────────────────────────────────────────────
@Nested
@DisplayName("typeMembre()")
class TypeMembre {
@Test void president() { assertThat(make("ACTIF", List.of("PRESIDENT")).typeMembre()).isEqualTo("Président"); }
@Test void vicePresident() { assertThat(make("ACTIF", List.of("VICE_PRESIDENT")).typeMembre()).isEqualTo("Vice-Président"); }
@Test void secretaire() { assertThat(make("ACTIF", List.of("SECRETAIRE")).typeMembre()).isEqualTo("Secrétaire"); }
@Test void tresorier() { assertThat(make("ACTIF", List.of("TRESORIER")).typeMembre()).isEqualTo("Trésorier"); }
@Test void adminOrg() { assertThat(make("ACTIF", List.of("ADMIN_ORGANISATION")).typeMembre()).isEqualTo("Administrateur"); }
@Test void moderateur() { assertThat(make("ACTIF", List.of("MODERATEUR")).typeMembre()).isEqualTo("Modérateur"); }
@Test void membreActif() { assertThat(make("ACTIF", List.of("MEMBRE_ACTIF")).typeMembre()).isEqualTo("Membre"); }
@Test void rolesVide() { assertThat(make("ACTIF", List.of()).typeMembre()).isEqualTo("Membre"); }
@Test void rolesNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, null, null,
null, null, null, null, null, false, null, null, null, null);
assertThat(r.typeMembre()).isEqualTo("Membre");
}
}
// ── typeSeverity ───────────────────────────────────────────────────────
@Nested
@DisplayName("typeSeverity()")
class TypeSeverity {
@Test void president() { assertThat(make("ACTIF", List.of("PRESIDENT")).typeSeverity()).isEqualTo("primary"); }
@Test void vicePresident() { assertThat(make("ACTIF", List.of("VICE_PRESIDENT")).typeSeverity()).isEqualTo("primary"); }
@Test void secretaire() { assertThat(make("ACTIF", List.of("SECRETAIRE")).typeSeverity()).isEqualTo("info"); }
@Test void tresorier() { assertThat(make("ACTIF", List.of("TRESORIER")).typeSeverity()).isEqualTo("warning"); }
@Test void adminOrg() { assertThat(make("ACTIF", List.of("ADMIN_ORGANISATION")).typeSeverity()).isEqualTo("danger"); }
@Test void moderateur() { assertThat(make("ACTIF", List.of("MODERATEUR")).typeSeverity()).isEqualTo("warning"); }
@Test void roleDefault() { assertThat(make("ACTIF", List.of("MEMBRE_ACTIF")).typeSeverity()).isEqualTo("secondary"); }
@Test void rolesVide() { assertThat(make("ACTIF", List.of()).typeSeverity()).isEqualTo("secondary"); }
@Test void rolesNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, null, null,
null, null, null, null, null, false, null, null, null, null);
assertThat(r.typeSeverity()).isEqualTo("secondary");
}
}
// ── typeIcon ───────────────────────────────────────────────────────────
@Nested
@DisplayName("typeIcon()")
class TypeIcon {
@Test void president() { assertThat(make("ACTIF", List.of("PRESIDENT")).typeIcon()).isEqualTo("pi pi-star"); }
@Test void vicePresident() { assertThat(make("ACTIF", List.of("VICE_PRESIDENT")).typeIcon()).isEqualTo("pi pi-star"); }
@Test void secretaire() { assertThat(make("ACTIF", List.of("SECRETAIRE")).typeIcon()).isEqualTo("pi pi-file-edit"); }
@Test void tresorier() { assertThat(make("ACTIF", List.of("TRESORIER")).typeIcon()).isEqualTo("pi pi-wallet"); }
@Test void adminOrg() { assertThat(make("ACTIF", List.of("ADMIN_ORGANISATION")).typeIcon()).isEqualTo("pi pi-shield"); }
@Test void moderateur() { assertThat(make("ACTIF", List.of("MODERATEUR")).typeIcon()).isEqualTo("pi pi-wrench"); }
@Test void roleDefault() { assertThat(make("ACTIF", List.of("MEMBRE_ACTIF")).typeIcon()).isEqualTo("pi pi-user"); }
@Test void rolesVide() { assertThat(make("ACTIF", List.of()).typeIcon()).isEqualTo("pi pi-user"); }
@Test void rolesNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, null, null,
null, null, null, null, null, false, null, null, null, null);
assertThat(r.typeIcon()).isEqualTo("pi pi-user");
}
}
// ── dateAdhesion ───────────────────────────────────────────────────────
@Nested
@DisplayName("dateAdhesion()")
class DateAdhesion {
@Test
@DisplayName("dateAdhesion est accessible via le composant record")
void accesseur() {
LocalDate date = LocalDate.of(2024, 3, 15);
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, "Jean", "Dupont", null,
null, null, "ACTIF", null, null, true, List.of(), null, null, date);
assertThat(r.dateAdhesion()).isEqualTo(date);
}
@Test
@DisplayName("dateAdhesion null par défaut")
void nullParDefaut() {
assertThat(make("ACTIF", List.of()).dateAdhesion()).isNull();
}
}
// ── Getters JavaBean ───────────────────────────────────────────────────
@Nested
@DisplayName("getters JavaBean (compatibilité JSF EL)")
class GettersJavaBean {
@Test
@DisplayName("getId/getNumeroMembre/getPrenom/getNom/getEmail/getTelephone/getProfession")
void champsSimples() {
LocalDate date = LocalDate.of(2024, 1, 1);
UUID orgId = UUID.randomUUID();
UUID id = UUID.randomUUID();
MembreSummaryResponse r = new MembreSummaryResponse(
id, "UF-001", "Jean", "Dupont", "jean@test.com",
"0100000000", "Dev", "ACTIF", "Actif", "success",
true, List.of("MEMBRE_ACTIF"), orgId, "Org Test", date);
assertThat(r.getId()).isEqualTo(id);
assertThat(r.getNumeroMembre()).isEqualTo("UF-001");
assertThat(r.getPrenom()).isEqualTo("Jean");
assertThat(r.getNom()).isEqualTo("Dupont");
assertThat(r.getEmail()).isEqualTo("jean@test.com");
assertThat(r.getTelephone()).isEqualTo("0100000000");
assertThat(r.getProfession()).isEqualTo("Dev");
assertThat(r.getStatutCompte()).isEqualTo("ACTIF");
assertThat(r.getStatutCompteLibelle()).isEqualTo("Actif");
assertThat(r.getStatutCompteSeverity()).isEqualTo("success");
assertThat(r.getActif()).isTrue();
assertThat(r.isActif()).isTrue();
assertThat(r.getRoles()).containsExactly("MEMBRE_ACTIF");
assertThat(r.getOrganisationId()).isEqualTo(orgId);
assertThat(r.getOrganisationNom()).isEqualTo("Org Test");
assertThat(r.getDateAdhesion()).isEqualTo(date);
}
@Test
@DisplayName("isActif false quand actif null")
void isActifNull() {
MembreSummaryResponse r = new MembreSummaryResponse(
UUID.randomUUID(), null, null, null, null,
null, null, null, null, null, null, null, null, null, null);
assertThat(r.isActif()).isFalse();
assertThat(r.getActif()).isNull();
}
@Test
@DisplayName("getters calculés délèguent aux méthodes calculées")
void gettersCalcules() {
MembreSummaryResponse r = make("ACTIF", List.of("PRESIDENT"));
assertThat(r.getNomComplet()).isEqualTo(r.nomComplet());
assertThat(r.getStatut()).isEqualTo(r.statut());
assertThat(r.getStatutLibelle()).isEqualTo(r.statutLibelle());
assertThat(r.getStatutSeverity()).isEqualTo(r.statutSeverity());
assertThat(r.getStatutIcon()).isEqualTo(r.statutIcon());
assertThat(r.getTypeMembre()).isEqualTo(r.typeMembre());
assertThat(r.getTypeSeverity()).isEqualTo(r.typeSeverity());
assertThat(r.getTypeIcon()).isEqualTo(r.typeIcon());
}
}
}

View File

@@ -158,7 +158,7 @@ class CreateMembreRequestTest {
.nom("User") .nom("User")
.email("test@example.com") .email("test@example.com")
.dateNaissance(LocalDate.of(1990, 1, 1)) .dateNaissance(LocalDate.of(1990, 1, 1))
.telephoneWave("+22177123456789") .telephoneWave("+221771234567890123456") // 22 chars > max 20
.build(); .build();
Set<ConstraintViolation<CreateMembreRequest>> violations = validator.validate(request); Set<ConstraintViolation<CreateMembreRequest>> violations = validator.validate(request);

View File

@@ -52,6 +52,13 @@ class CreateOrganisationRequestTest {
.notes("Organisation de référence dans le secteur") .notes("Organisation de référence dans le secteur")
.latitude(new BigDecimal("14.6937")) .latitude(new BigDecimal("14.6937"))
.longitude(new BigDecimal("-17.4441")) .longitude(new BigDecimal("-17.4441"))
.adresse("123 Rue des Entreprises, Plateau")
.ville("Dakar")
.region("Dakar")
.pays("Sénégal")
.codePostal("BP 3456")
.organisationPublique(true)
.accepteNouveauxMembres(false)
.build(); .build();
assertThat(request).isNotNull(); assertThat(request).isNotNull();
@@ -76,6 +83,13 @@ class CreateOrganisationRequestTest {
assertThat(request.certifications()).isEqualTo("ISO 9001"); assertThat(request.certifications()).isEqualTo("ISO 9001");
assertThat(request.latitude()).isEqualByComparingTo(new BigDecimal("14.6937")); assertThat(request.latitude()).isEqualByComparingTo(new BigDecimal("14.6937"));
assertThat(request.longitude()).isEqualByComparingTo(new BigDecimal("-17.4441")); assertThat(request.longitude()).isEqualByComparingTo(new BigDecimal("-17.4441"));
assertThat(request.adresse()).isEqualTo("123 Rue des Entreprises, Plateau");
assertThat(request.ville()).isEqualTo("Dakar");
assertThat(request.region()).isEqualTo("Dakar");
assertThat(request.pays()).isEqualTo("Sénégal");
assertThat(request.codePostal()).isEqualTo("BP 3456");
assertThat(request.organisationPublique()).isTrue();
assertThat(request.accepteNouveauxMembres()).isFalse();
} }
@Test @Test
@@ -191,6 +205,59 @@ class CreateOrganisationRequestTest {
assertThat(violations).isEmpty(); assertThat(violations).isEmpty();
} }
@Test
void testBuilder_AdresseFields() {
CreateOrganisationRequest request = CreateOrganisationRequest.builder()
.nom("ONG Dakar Centre")
.email("contact@ongdc.sn")
.adresse("Rue 10, Médina")
.ville("Dakar")
.region("Dakar")
.pays("Sénégal")
.codePostal("BP 1234")
.organisationPublique(false)
.accepteNouveauxMembres(true)
.build();
assertThat(request.adresse()).isEqualTo("Rue 10, Médina");
assertThat(request.ville()).isEqualTo("Dakar");
assertThat(request.region()).isEqualTo("Dakar");
assertThat(request.pays()).isEqualTo("Sénégal");
assertThat(request.codePostal()).isEqualTo("BP 1234");
assertThat(request.organisationPublique()).isFalse();
assertThat(request.accepteNouveauxMembres()).isTrue();
}
@Test
void testBuilder_AdresseFieldsNull_WhenNotProvided() {
CreateOrganisationRequest request = CreateOrganisationRequest.builder()
.nom("Org Minimal")
.email("min@org.sn")
.build();
assertThat(request.adresse()).isNull();
assertThat(request.ville()).isNull();
assertThat(request.region()).isNull();
assertThat(request.pays()).isNull();
assertThat(request.codePostal()).isNull();
assertThat(request.organisationPublique()).isNull();
assertThat(request.accepteNouveauxMembres()).isNull();
}
@Test
void testValidation_CodePostalTooLong() {
CreateOrganisationRequest request = CreateOrganisationRequest.builder()
.nom("Organisation Test")
.email("test@org.sn")
.codePostal("A".repeat(21))
.build();
Set<ConstraintViolation<CreateOrganisationRequest>> violations = validator.validate(request);
assertThat(violations).isNotEmpty();
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("codePostal"));
}
@Test @Test
void testEquals() { void testEquals() {
CreateOrganisationRequest request1 = CreateOrganisationRequest.builder() CreateOrganisationRequest request1 = CreateOrganisationRequest.builder()

View File

@@ -52,6 +52,13 @@ class UpdateOrganisationRequestTest {
.notes("Notes mises à jour") .notes("Notes mises à jour")
.latitude(new BigDecimal("12.5")) .latitude(new BigDecimal("12.5"))
.longitude(new BigDecimal("-15.5")) .longitude(new BigDecimal("-15.5"))
.adresse("Avenue Cheikh Anta Diop, Fann")
.ville("Dakar")
.region("Dakar")
.pays("Sénégal")
.codePostal("BP 5000")
.organisationPublique(false)
.accepteNouveauxMembres(true)
.build(); .build();
assertThat(request).isNotNull(); assertThat(request).isNotNull();
@@ -69,6 +76,13 @@ class UpdateOrganisationRequestTest {
assertThat(request.budgetAnnuel()).isEqualByComparingTo(new BigDecimal("75000000.00")); assertThat(request.budgetAnnuel()).isEqualByComparingTo(new BigDecimal("75000000.00"));
assertThat(request.cotisationObligatoire()).isFalse(); assertThat(request.cotisationObligatoire()).isFalse();
assertThat(request.certifications()).isEqualTo("ISO 14001"); assertThat(request.certifications()).isEqualTo("ISO 14001");
assertThat(request.adresse()).isEqualTo("Avenue Cheikh Anta Diop, Fann");
assertThat(request.ville()).isEqualTo("Dakar");
assertThat(request.region()).isEqualTo("Dakar");
assertThat(request.pays()).isEqualTo("Sénégal");
assertThat(request.codePostal()).isEqualTo("BP 5000");
assertThat(request.organisationPublique()).isFalse();
assertThat(request.accepteNouveauxMembres()).isTrue();
} }
@Test @Test
@@ -168,6 +182,43 @@ class UpdateOrganisationRequestTest {
assertThat(violations).isEmpty(); assertThat(violations).isEmpty();
} }
@Test
void testBuilder_AdresseFields() {
UpdateOrganisationRequest request = UpdateOrganisationRequest.builder()
.nom("Association Abidjan Nord")
.email("contact@abn.ci")
.adresse("Quartier Deux Plateaux, Rue des Jardins")
.ville("Abidjan")
.region("Lagunes")
.pays("Côte d'Ivoire")
.codePostal("01 BP 1234")
.organisationPublique(true)
.accepteNouveauxMembres(true)
.build();
assertThat(request.adresse()).isEqualTo("Quartier Deux Plateaux, Rue des Jardins");
assertThat(request.ville()).isEqualTo("Abidjan");
assertThat(request.region()).isEqualTo("Lagunes");
assertThat(request.pays()).isEqualTo("Côte d'Ivoire");
assertThat(request.codePostal()).isEqualTo("01 BP 1234");
assertThat(request.organisationPublique()).isTrue();
assertThat(request.accepteNouveauxMembres()).isTrue();
}
@Test
void testValidation_VilleTooLong() {
UpdateOrganisationRequest request = UpdateOrganisationRequest.builder()
.nom("Test Org")
.email("test@org.ci")
.ville("A".repeat(101))
.build();
Set<ConstraintViolation<UpdateOrganisationRequest>> violations = validator.validate(request);
assertThat(violations).isNotEmpty();
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("ville"));
}
@Test @Test
void testEquals() { void testEquals() {
UpdateOrganisationRequest request1 = UpdateOrganisationRequest.builder() UpdateOrganisationRequest request1 = UpdateOrganisationRequest.builder()

View File

@@ -65,10 +65,12 @@ class InitierPaiementEnLigneRequestTest {
Set<ConstraintViolation<InitierPaiementEnLigneRequest>> violations = validator.validate(request); Set<ConstraintViolation<InitierPaiementEnLigneRequest>> violations = validator.validate(request);
// cotisationId et methodePaiement sont obligatoires
// numeroTelephone est optionnel (web QR sans restriction de payeur)
assertThat(violations).isNotEmpty(); assertThat(violations).isNotEmpty();
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("cotisationId")); assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("cotisationId"));
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement")); assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone")); assertThat(violations).noneMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
} }
@Test @Test

View File

@@ -0,0 +1,112 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
import static org.assertj.core.api.Assertions.assertThat;
import java.math.BigDecimal;
import java.util.UUID;
import org.junit.jupiter.api.Test;
class IntentionStatutResponseTest {
@Test
void testBuilder_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();
assertThat(response).isNotNull();
assertThat(response.intentionId()).isEqualTo(intentionId);
assertThat(response.statut()).isEqualTo("COMPLETEE");
assertThat(response.waveLaunchUrl()).isEqualTo("https://pay.wave.com/c/cos-abc123");
assertThat(response.waveCheckoutSessionId()).isEqualTo("cos-abc123");
assertThat(response.waveTransactionId()).isEqualTo("TCN4Y4ZC3FM");
assertThat(response.montant()).isEqualByComparingTo(new BigDecimal("5000"));
assertThat(response.referenceCotisation()).isEqualTo("COT-2025-001");
assertThat(response.message()).isEqualTo("Paiement confirmé !");
}
@Test
void testBuilder_EnCours() {
UUID intentionId = UUID.randomUUID();
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(response.intentionId()).isEqualTo(intentionId);
assertThat(response.statut()).isEqualTo("EN_COURS");
assertThat(response.waveLaunchUrl()).isEqualTo("https://pay.wave.com/c/cos-xyz789");
assertThat(response.waveTransactionId()).isNull();
assertThat(response.referenceCotisation()).isNull();
}
@Test
void testBuilder_Expiree() {
UUID intentionId = UUID.randomUUID();
IntentionStatutResponse response = IntentionStatutResponse.builder()
.intentionId(intentionId)
.statut("EXPIREE")
.montant(new BigDecimal("2500"))
.message("Session Wave expirée")
.build();
assertThat(response.statut()).isEqualTo("EXPIREE");
assertThat(response.waveLaunchUrl()).isNull();
assertThat(response.waveCheckoutSessionId()).isNull();
assertThat(response.waveTransactionId()).isNull();
}
@Test
void testEquals_SameFields() {
UUID intentionId = UUID.randomUUID();
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();
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();
assertThat(r1).isEqualTo(r2);
assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
}
@Test
void testToString() {
IntentionStatutResponse response = IntentionStatutResponse.builder()
.intentionId(UUID.randomUUID())
.statut("COMPLETEE")
.waveTransactionId("TCN4Y4ZC3FM")
.build();
String str = response.toString();
assertThat(str).isNotNull();
assertThat(str).contains("IntentionStatutResponse");
assertThat(str).contains("COMPLETEE");
assertThat(str).contains("TCN4Y4ZC3FM");
}
}

View File

@@ -0,0 +1,172 @@
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.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@DisplayName("Tests des DTOs souscription")
class SouscriptionDtosTest {
@Nested
@DisplayName("SouscriptionDemandeRequest")
class SouscriptionDemandeRequestTest {
@Test
@DisplayName("Getters/Setters fonctionnent correctement")
void testGettersSetters() {
SouscriptionDemandeRequest req = new SouscriptionDemandeRequest();
req.setTypeFormule("BASIC");
req.setPlageMembres("PETITE");
req.setTypePeriode("MENSUEL");
req.setTypeOrganisation("ASSOCIATION");
req.setOrganisationId("org-uuid-123");
assertThat(req.getTypeFormule()).isEqualTo("BASIC");
assertThat(req.getPlageMembres()).isEqualTo("PETITE");
assertThat(req.getTypePeriode()).isEqualTo("MENSUEL");
assertThat(req.getTypeOrganisation()).isEqualTo("ASSOCIATION");
assertThat(req.getOrganisationId()).isEqualTo("org-uuid-123");
}
}
@Nested
@DisplayName("SouscriptionStatutResponse")
class SouscriptionStatutResponseTest {
@Test
@DisplayName("Getters/Setters fonctionnent correctement")
void testGettersSetters() {
LocalDate today = LocalDate.now();
SouscriptionStatutResponse resp = new SouscriptionStatutResponse();
resp.setSouscriptionId("sous-uuid-456");
resp.setStatutValidation("EN_ATTENTE_PAIEMENT");
resp.setStatutLibelle("En attente de paiement");
resp.setTypeFormule("BASIC");
resp.setPlageMembres("PETITE");
resp.setPlageLibelle("Petite structure (1100 membres)");
resp.setTypePeriode("MENSUEL");
resp.setTypeOrganisation("ASSOCIATION");
resp.setMontantTotal(new BigDecimal("3000"));
resp.setMontantMensuelBase(new BigDecimal("3000"));
resp.setCoefficientApplique(new BigDecimal("1.0"));
resp.setWaveSessionId("wave-session-789");
resp.setWaveLaunchUrl("https://pay.wave.com/c/session-789");
resp.setDateDebut(today);
resp.setDateFin(today.plusMonths(1));
resp.setDateValidation(null);
resp.setCommentaireRejet(null);
resp.setOrganisationId("org-uuid-123");
resp.setOrganisationNom("Association Test");
resp.setStatut("ACTIVE");
assertThat(resp.getSouscriptionId()).isEqualTo("sous-uuid-456");
assertThat(resp.getStatutValidation()).isEqualTo("EN_ATTENTE_PAIEMENT");
assertThat(resp.getStatutLibelle()).isEqualTo("En attente de paiement");
assertThat(resp.getTypeFormule()).isEqualTo("BASIC");
assertThat(resp.getPlageMembres()).isEqualTo("PETITE");
assertThat(resp.getPlageLibelle()).isEqualTo("Petite structure (1100 membres)");
assertThat(resp.getTypePeriode()).isEqualTo("MENSUEL");
assertThat(resp.getTypeOrganisation()).isEqualTo("ASSOCIATION");
assertThat(resp.getMontantTotal()).isEqualByComparingTo(new BigDecimal("3000"));
assertThat(resp.getMontantMensuelBase()).isEqualByComparingTo(new BigDecimal("3000"));
assertThat(resp.getCoefficientApplique()).isEqualByComparingTo(new BigDecimal("1.0"));
assertThat(resp.getWaveSessionId()).isEqualTo("wave-session-789");
assertThat(resp.getWaveLaunchUrl()).isEqualTo("https://pay.wave.com/c/session-789");
assertThat(resp.getDateDebut()).isEqualTo(today);
assertThat(resp.getDateFin()).isEqualTo(today.plusMonths(1));
assertThat(resp.getDateValidation()).isNull();
assertThat(resp.getCommentaireRejet()).isNull();
assertThat(resp.getOrganisationId()).isEqualTo("org-uuid-123");
assertThat(resp.getOrganisationNom()).isEqualTo("Association Test");
assertThat(resp.getStatut()).isEqualTo("ACTIVE");
}
@Test
@DisplayName("Champs Option C (quota + plan commercial) fonctionnent correctement")
void testOptionCFields() {
SouscriptionStatutResponse resp = new SouscriptionStatutResponse();
resp.setQuotaMax(200);
resp.setQuotaUtilise(75);
resp.setQuotaRestant(125);
resp.setQuotaDepasse(false);
resp.setPlanCommercial("ENTERPRISE");
resp.setApiAccess(true);
resp.setFederationAccess(true);
resp.setSupportPrioritaire(true);
resp.setSlaGaranti("99.9%");
resp.setMaxAdmins(10);
resp.setNiveauReporting("AVANCE");
resp.setJoursAvantExpiration(180L);
assertThat(resp.getQuotaMax()).isEqualTo(200);
assertThat(resp.getQuotaUtilise()).isEqualTo(75);
assertThat(resp.getQuotaRestant()).isEqualTo(125);
assertThat(resp.isQuotaDepasse()).isFalse();
assertThat(resp.getPlanCommercial()).isEqualTo("ENTERPRISE");
assertThat(resp.isApiAccess()).isTrue();
assertThat(resp.isFederationAccess()).isTrue();
assertThat(resp.isSupportPrioritaire()).isTrue();
assertThat(resp.getSlaGaranti()).isEqualTo("99.9%");
assertThat(resp.getMaxAdmins()).isEqualTo(10);
assertThat(resp.getNiveauReporting()).isEqualTo("AVANCE");
assertThat(resp.getJoursAvantExpiration()).isEqualTo(180L);
}
}
@Nested
@DisplayName("FormuleAbonnementResponse")
class FormuleAbonnementResponseTest {
@Test
@DisplayName("Getters/Setters fonctionnent correctement")
void testGettersSetters() {
FormuleAbonnementResponse resp = new FormuleAbonnementResponse();
resp.setCode("BASIC");
resp.setLibelle("Basic");
resp.setDescription("Formule de base pour petites structures");
resp.setPlage("PETITE");
resp.setPlageLibelle("Petite structure (1100 membres)");
resp.setMinMembres(1);
resp.setMaxMembres(100);
resp.setPrixMensuel(new BigDecimal("3000"));
resp.setPrixAnnuel(new BigDecimal("28800"));
resp.setOrdreAffichage(1);
assertThat(resp.getCode()).isEqualTo("BASIC");
assertThat(resp.getLibelle()).isEqualTo("Basic");
assertThat(resp.getDescription()).isEqualTo("Formule de base pour petites structures");
assertThat(resp.getPlage()).isEqualTo("PETITE");
assertThat(resp.getPlageLibelle()).isEqualTo("Petite structure (1100 membres)");
assertThat(resp.getMinMembres()).isEqualTo(1);
assertThat(resp.getMaxMembres()).isEqualTo(100);
assertThat(resp.getPrixMensuel()).isEqualByComparingTo(new BigDecimal("3000"));
assertThat(resp.getPrixAnnuel()).isEqualByComparingTo(new BigDecimal("28800"));
assertThat(resp.getOrdreAffichage()).isEqualTo(1);
}
@Test
@DisplayName("Champs Option C fonctionnent correctement")
void testOptionCFields() {
FormuleAbonnementResponse resp = new FormuleAbonnementResponse();
resp.setPlanCommercial("ENTERPRISE");
resp.setNiveauReporting("AVANCE");
resp.setApiAccess(true);
resp.setFederationAccess(true);
resp.setSupportPrioritaire(true);
resp.setSlaGaranti("99.9%");
resp.setMaxAdmins(10);
assertThat(resp.getPlanCommercial()).isEqualTo("ENTERPRISE");
assertThat(resp.getNiveauReporting()).isEqualTo("AVANCE");
assertThat(resp.isApiAccess()).isTrue();
assertThat(resp.isFederationAccess()).isTrue();
assertThat(resp.isSupportPrioritaire()).isTrue();
assertThat(resp.getSlaGaranti()).isEqualTo("99.9%");
assertThat(resp.getMaxAdmins()).isEqualTo(10);
}
}
}

View File

@@ -139,10 +139,9 @@ class EnumsRefactoringTest {
@DisplayName("TypeFormule - Tous les types disponibles") @DisplayName("TypeFormule - Tous les types disponibles")
void testTypeFormuleTousLesTypes() { void testTypeFormuleTousLesTypes() {
// Given & When & Then // Given & When & Then
assertThat(TypeFormule.STARTER.getLibelle()).contains("Starter"); assertThat(TypeFormule.BASIC.getLibelle()).contains("Basic");
assertThat(TypeFormule.STANDARD.getLibelle()).contains("Standard"); assertThat(TypeFormule.STANDARD.getLibelle()).contains("Standard");
assertThat(TypeFormule.PREMIUM.getLibelle()).contains("Premium"); assertThat(TypeFormule.PREMIUM.getLibelle()).contains("Premium");
assertThat(TypeFormule.CRYSTAL.getLibelle()).contains("Crystal");
} }
@Test @Test

View File

@@ -0,0 +1,125 @@
package dev.lions.unionflow.server.api.enums.abonnement;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@DisplayName("Tests pour PlageMembres")
class PlageMembresTest {
@Test
@DisplayName("Test de base - enum peut être utilisé")
void testEnumUtilisable() {
assertThat(PlageMembres.PETITE).isNotNull();
assertThat(PlageMembres.TRES_GRANDE).isNotNull();
}
@Nested
@DisplayName("Tests des valeurs enum")
class TestsValeursEnum {
@Test
@DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() {
PlageMembres[] values = PlageMembres.values();
assertThat(values).hasSize(4);
assertThat(values).containsExactly(
PlageMembres.PETITE,
PlageMembres.MOYENNE,
PlageMembres.GRANDE,
PlageMembres.TRES_GRANDE);
}
@Test
@DisplayName("Test valueOf - toutes les constantes")
void testValueOf() {
assertThat(PlageMembres.valueOf("PETITE")).isEqualTo(PlageMembres.PETITE);
assertThat(PlageMembres.valueOf("MOYENNE")).isEqualTo(PlageMembres.MOYENNE);
assertThat(PlageMembres.valueOf("GRANDE")).isEqualTo(PlageMembres.GRANDE);
assertThat(PlageMembres.valueOf("TRES_GRANDE")).isEqualTo(PlageMembres.TRES_GRANDE);
assertThatThrownBy(() -> PlageMembres.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@ParameterizedTest
@EnumSource(PlageMembres.class)
@DisplayName("Test getLibelle pour toutes les valeurs - non null et non vide")
void testGetLibelle(PlageMembres plage) {
assertThat(plage.getLibelle()).isNotNull().isNotEmpty();
}
@Test
@DisplayName("Test bornes min/max de chaque plage")
void testBornesMinMax() {
assertThat(PlageMembres.PETITE.getMin()).isEqualTo(1);
assertThat(PlageMembres.PETITE.getMax()).isEqualTo(100);
assertThat(PlageMembres.MOYENNE.getMin()).isEqualTo(101);
assertThat(PlageMembres.MOYENNE.getMax()).isEqualTo(500);
assertThat(PlageMembres.GRANDE.getMin()).isEqualTo(501);
assertThat(PlageMembres.GRANDE.getMax()).isEqualTo(2000);
assertThat(PlageMembres.TRES_GRANDE.getMin()).isEqualTo(2001);
assertThat(PlageMembres.TRES_GRANDE.getMax()).isEqualTo(Integer.MAX_VALUE);
}
@Test
@DisplayName("Test getMaxAffichage - TRES_GRANDE retourne -1")
void testGetMaxAffichage() {
assertThat(PlageMembres.PETITE.getMaxAffichage()).isEqualTo(100);
assertThat(PlageMembres.MOYENNE.getMaxAffichage()).isEqualTo(500);
assertThat(PlageMembres.GRANDE.getMaxAffichage()).isEqualTo(2000);
assertThat(PlageMembres.TRES_GRANDE.getMaxAffichage()).isEqualTo(-1);
}
}
@Nested
@DisplayName("Tests de fromNombreMembres")
class TestsFromNombreMembres {
@Test
@DisplayName("Valeurs limites - PETITE (1-100)")
void testPetite() {
assertThat(PlageMembres.fromNombreMembres(1)).isEqualTo(PlageMembres.PETITE);
assertThat(PlageMembres.fromNombreMembres(50)).isEqualTo(PlageMembres.PETITE);
assertThat(PlageMembres.fromNombreMembres(100)).isEqualTo(PlageMembres.PETITE);
}
@Test
@DisplayName("Valeurs limites - MOYENNE (101-500)")
void testMoyenne() {
assertThat(PlageMembres.fromNombreMembres(101)).isEqualTo(PlageMembres.MOYENNE);
assertThat(PlageMembres.fromNombreMembres(300)).isEqualTo(PlageMembres.MOYENNE);
assertThat(PlageMembres.fromNombreMembres(500)).isEqualTo(PlageMembres.MOYENNE);
}
@Test
@DisplayName("Valeurs limites - GRANDE (501-2000)")
void testGrande() {
assertThat(PlageMembres.fromNombreMembres(501)).isEqualTo(PlageMembres.GRANDE);
assertThat(PlageMembres.fromNombreMembres(1000)).isEqualTo(PlageMembres.GRANDE);
assertThat(PlageMembres.fromNombreMembres(2000)).isEqualTo(PlageMembres.GRANDE);
}
@Test
@DisplayName("Valeurs limites - TRES_GRANDE (2001+)")
void testTresGrande() {
assertThat(PlageMembres.fromNombreMembres(2001)).isEqualTo(PlageMembres.TRES_GRANDE);
assertThat(PlageMembres.fromNombreMembres(10000)).isEqualTo(PlageMembres.TRES_GRANDE);
assertThat(PlageMembres.fromNombreMembres(Integer.MAX_VALUE)).isEqualTo(PlageMembres.TRES_GRANDE);
}
@Test
@DisplayName("Nombre négatif - retourne TRES_GRANDE par défaut")
void testNombreNegatif() {
assertThat(PlageMembres.fromNombreMembres(-1)).isEqualTo(PlageMembres.TRES_GRANDE);
}
}
}

View File

@@ -27,8 +27,9 @@ class StatutSouscriptionTest {
@DisplayName("Test toutes les valeurs enum") @DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() { void testToutesValeurs() {
StatutSouscription[] values = StatutSouscription.values(); StatutSouscription[] values = StatutSouscription.values();
assertThat(values).hasSize(4); assertThat(values).hasSize(5);
assertThat(values).containsExactly( assertThat(values).containsExactly(
StatutSouscription.EN_ATTENTE,
StatutSouscription.ACTIVE, StatutSouscription.ACTIVE,
StatutSouscription.EXPIREE, StatutSouscription.EXPIREE,
StatutSouscription.SUSPENDUE, StatutSouscription.SUSPENDUE,
@@ -38,6 +39,7 @@ class StatutSouscriptionTest {
@Test @Test
@DisplayName("Test valueOf - toutes les constantes") @DisplayName("Test valueOf - toutes les constantes")
void testValueOf() { void testValueOf() {
assertThat(StatutSouscription.valueOf("EN_ATTENTE")).isEqualTo(StatutSouscription.EN_ATTENTE);
assertThat(StatutSouscription.valueOf("ACTIVE")).isEqualTo(StatutSouscription.ACTIVE); assertThat(StatutSouscription.valueOf("ACTIVE")).isEqualTo(StatutSouscription.ACTIVE);
assertThat(StatutSouscription.valueOf("EXPIREE")).isEqualTo(StatutSouscription.EXPIREE); assertThat(StatutSouscription.valueOf("EXPIREE")).isEqualTo(StatutSouscription.EXPIREE);
assertThat(StatutSouscription.valueOf("SUSPENDUE")).isEqualTo(StatutSouscription.SUSPENDUE); assertThat(StatutSouscription.valueOf("SUSPENDUE")).isEqualTo(StatutSouscription.SUSPENDUE);

View File

@@ -0,0 +1,89 @@
package dev.lions.unionflow.server.api.enums.abonnement;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@DisplayName("Tests pour StatutValidationSouscription")
class StatutValidationSouscriptionTest {
@Test
@DisplayName("Test de base - enum peut être utilisé")
void testEnumUtilisable() {
assertThat(StatutValidationSouscription.EN_ATTENTE_PAIEMENT).isNotNull();
assertThat(StatutValidationSouscription.VALIDEE).isNotNull();
}
@Nested
@DisplayName("Tests des valeurs enum")
class TestsValeursEnum {
@Test
@DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() {
StatutValidationSouscription[] values = StatutValidationSouscription.values();
assertThat(values).hasSize(5);
assertThat(values).containsExactly(
StatutValidationSouscription.EN_ATTENTE_PAIEMENT,
StatutValidationSouscription.PAIEMENT_INITIE,
StatutValidationSouscription.PAIEMENT_CONFIRME,
StatutValidationSouscription.VALIDEE,
StatutValidationSouscription.REJETEE);
}
@Test
@DisplayName("Test valueOf - toutes les constantes")
void testValueOf() {
assertThat(StatutValidationSouscription.valueOf("EN_ATTENTE_PAIEMENT"))
.isEqualTo(StatutValidationSouscription.EN_ATTENTE_PAIEMENT);
assertThat(StatutValidationSouscription.valueOf("PAIEMENT_INITIE"))
.isEqualTo(StatutValidationSouscription.PAIEMENT_INITIE);
assertThat(StatutValidationSouscription.valueOf("PAIEMENT_CONFIRME"))
.isEqualTo(StatutValidationSouscription.PAIEMENT_CONFIRME);
assertThat(StatutValidationSouscription.valueOf("VALIDEE"))
.isEqualTo(StatutValidationSouscription.VALIDEE);
assertThat(StatutValidationSouscription.valueOf("REJETEE"))
.isEqualTo(StatutValidationSouscription.REJETEE);
assertThatThrownBy(() -> StatutValidationSouscription.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@ParameterizedTest
@EnumSource(StatutValidationSouscription.class)
@DisplayName("Test getLibelle pour toutes les valeurs - non null et non vide")
void testGetLibelle(StatutValidationSouscription statut) {
assertThat(statut.getLibelle()).isNotNull().isNotEmpty();
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class TestsMethodesMetier {
@Test
@DisplayName("isTerminal - seuls VALIDEE et REJETEE sont terminaux")
void testIsTerminal() {
assertThat(StatutValidationSouscription.EN_ATTENTE_PAIEMENT.isTerminal()).isFalse();
assertThat(StatutValidationSouscription.PAIEMENT_INITIE.isTerminal()).isFalse();
assertThat(StatutValidationSouscription.PAIEMENT_CONFIRME.isTerminal()).isFalse();
assertThat(StatutValidationSouscription.VALIDEE.isTerminal()).isTrue();
assertThat(StatutValidationSouscription.REJETEE.isTerminal()).isTrue();
}
@Test
@DisplayName("peutInitierPaiement - seul EN_ATTENTE_PAIEMENT permet d'initier")
void testPeutInitierPaiement() {
assertThat(StatutValidationSouscription.EN_ATTENTE_PAIEMENT.peutInitierPaiement()).isTrue();
assertThat(StatutValidationSouscription.PAIEMENT_INITIE.peutInitierPaiement()).isFalse();
assertThat(StatutValidationSouscription.PAIEMENT_CONFIRME.peutInitierPaiement()).isFalse();
assertThat(StatutValidationSouscription.VALIDEE.peutInitierPaiement()).isFalse();
assertThat(StatutValidationSouscription.REJETEE.peutInitierPaiement()).isFalse();
}
}
}

View File

@@ -15,7 +15,7 @@ class TypeFormuleTest {
@Test @Test
@DisplayName("Test de base - enum peut être utilisé") @DisplayName("Test de base - enum peut être utilisé")
void testEnumUtilisable() { void testEnumUtilisable() {
assertThat(TypeFormule.STARTER).isNotNull(); assertThat(TypeFormule.BASIC).isNotNull();
} }
@Nested @Nested
@@ -26,21 +26,19 @@ class TypeFormuleTest {
@DisplayName("Test toutes les valeurs enum") @DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() { void testToutesValeurs() {
TypeFormule[] values = TypeFormule.values(); TypeFormule[] values = TypeFormule.values();
assertThat(values).hasSize(4); assertThat(values).hasSize(3);
assertThat(values).containsExactly( assertThat(values).containsExactly(
TypeFormule.STARTER, TypeFormule.BASIC,
TypeFormule.STANDARD, TypeFormule.STANDARD,
TypeFormule.PREMIUM, TypeFormule.PREMIUM);
TypeFormule.CRYSTAL);
} }
@Test @Test
@DisplayName("Test valueOf") @DisplayName("Test valueOf")
void testValueOf() { void testValueOf() {
assertThat(TypeFormule.valueOf("STARTER")).isEqualTo(TypeFormule.STARTER); assertThat(TypeFormule.valueOf("BASIC")).isEqualTo(TypeFormule.BASIC);
assertThat(TypeFormule.valueOf("STANDARD")).isEqualTo(TypeFormule.STANDARD); assertThat(TypeFormule.valueOf("STANDARD")).isEqualTo(TypeFormule.STANDARD);
assertThat(TypeFormule.valueOf("PREMIUM")).isEqualTo(TypeFormule.PREMIUM); assertThat(TypeFormule.valueOf("PREMIUM")).isEqualTo(TypeFormule.PREMIUM);
assertThat(TypeFormule.valueOf("CRYSTAL")).isEqualTo(TypeFormule.CRYSTAL);
assertThatThrownBy(() -> TypeFormule.valueOf("INEXISTANT")) assertThatThrownBy(() -> TypeFormule.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class); .isInstanceOf(IllegalArgumentException.class);

View File

@@ -0,0 +1,124 @@
package dev.lions.unionflow.server.api.enums.abonnement;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.math.BigDecimal;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@DisplayName("Tests pour TypeOrganisationFacturation")
class TypeOrganisationFacturationTest {
@Test
@DisplayName("Test de base - enum peut être utilisé")
void testEnumUtilisable() {
assertThat(TypeOrganisationFacturation.ASSOCIATION).isNotNull();
assertThat(TypeOrganisationFacturation.FEDERATION).isNotNull();
}
@Nested
@DisplayName("Tests des valeurs enum")
class TestsValeursEnum {
@Test
@DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() {
TypeOrganisationFacturation[] values = TypeOrganisationFacturation.values();
assertThat(values).hasSize(4);
assertThat(values).containsExactly(
TypeOrganisationFacturation.ASSOCIATION,
TypeOrganisationFacturation.MUTUELLE,
TypeOrganisationFacturation.COOPERATIVE,
TypeOrganisationFacturation.FEDERATION);
}
@Test
@DisplayName("Test valueOf - toutes les constantes")
void testValueOf() {
assertThat(TypeOrganisationFacturation.valueOf("ASSOCIATION"))
.isEqualTo(TypeOrganisationFacturation.ASSOCIATION);
assertThat(TypeOrganisationFacturation.valueOf("MUTUELLE"))
.isEqualTo(TypeOrganisationFacturation.MUTUELLE);
assertThat(TypeOrganisationFacturation.valueOf("COOPERATIVE"))
.isEqualTo(TypeOrganisationFacturation.COOPERATIVE);
assertThat(TypeOrganisationFacturation.valueOf("FEDERATION"))
.isEqualTo(TypeOrganisationFacturation.FEDERATION);
assertThatThrownBy(() -> TypeOrganisationFacturation.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@ParameterizedTest
@EnumSource(TypeOrganisationFacturation.class)
@DisplayName("Test getLibelle pour toutes les valeurs - non null et non vide")
void testGetLibelle(TypeOrganisationFacturation type) {
assertThat(type.getLibelle()).isNotNull().isNotEmpty();
}
@ParameterizedTest
@EnumSource(TypeOrganisationFacturation.class)
@DisplayName("Test coefficients - toujours positifs")
void testCoefficientsPositifs(TypeOrganisationFacturation type) {
assertThat(type.getCoefficientBase()).isGreaterThan(BigDecimal.ZERO);
assertThat(type.getCoefficientPremium()).isGreaterThan(BigDecimal.ZERO);
}
}
@Nested
@DisplayName("Tests de getCoefficient")
class TestsGetCoefficient {
@Test
@DisplayName("ASSOCIATION - coefficient 1.0 pour toutes les formules")
void testAssociation() {
assertThat(TypeOrganisationFacturation.ASSOCIATION.getCoefficient("BASIC"))
.isEqualByComparingTo(new BigDecimal("1.0"));
assertThat(TypeOrganisationFacturation.ASSOCIATION.getCoefficient("STANDARD"))
.isEqualByComparingTo(new BigDecimal("1.0"));
assertThat(TypeOrganisationFacturation.ASSOCIATION.getCoefficient("PREMIUM"))
.isEqualByComparingTo(new BigDecimal("1.0"));
}
@Test
@DisplayName("MUTUELLE - coefficient 1.2 pour toutes les formules")
void testMutuelle() {
assertThat(TypeOrganisationFacturation.MUTUELLE.getCoefficient("BASIC"))
.isEqualByComparingTo(new BigDecimal("1.2"));
assertThat(TypeOrganisationFacturation.MUTUELLE.getCoefficient("PREMIUM"))
.isEqualByComparingTo(new BigDecimal("1.2"));
}
@Test
@DisplayName("COOPERATIVE - coefficient 1.3 pour toutes les formules")
void testCooperative() {
assertThat(TypeOrganisationFacturation.COOPERATIVE.getCoefficient("BASIC"))
.isEqualByComparingTo(new BigDecimal("1.3"));
assertThat(TypeOrganisationFacturation.COOPERATIVE.getCoefficient("PREMIUM"))
.isEqualByComparingTo(new BigDecimal("1.3"));
}
@Test
@DisplayName("FEDERATION - coefficient 1.0 en BASIC/STANDARD, 1.5 en PREMIUM")
void testFederation() {
assertThat(TypeOrganisationFacturation.FEDERATION.getCoefficient("BASIC"))
.isEqualByComparingTo(new BigDecimal("1.0"));
assertThat(TypeOrganisationFacturation.FEDERATION.getCoefficient("STANDARD"))
.isEqualByComparingTo(new BigDecimal("1.0"));
assertThat(TypeOrganisationFacturation.FEDERATION.getCoefficient("PREMIUM"))
.isEqualByComparingTo(new BigDecimal("1.5"));
}
@Test
@DisplayName("Formule inconnue - utilise coefficientBase")
void testFormuleInconnue() {
assertThat(TypeOrganisationFacturation.FEDERATION.getCoefficient("STARTER"))
.isEqualByComparingTo(new BigDecimal("1.0"));
assertThat(TypeOrganisationFacturation.MUTUELLE.getCoefficient("INCONNU"))
.isEqualByComparingTo(new BigDecimal("1.2"));
}
}
}

View File

@@ -27,9 +27,11 @@ class TypePeriodeAbonnementTest {
@DisplayName("Test toutes les valeurs enum") @DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() { void testToutesValeurs() {
TypePeriodeAbonnement[] values = TypePeriodeAbonnement.values(); TypePeriodeAbonnement[] values = TypePeriodeAbonnement.values();
assertThat(values).hasSize(2); assertThat(values).hasSize(4);
assertThat(values).containsExactly( assertThat(values).containsExactly(
TypePeriodeAbonnement.MENSUEL, TypePeriodeAbonnement.MENSUEL,
TypePeriodeAbonnement.TRIMESTRIEL,
TypePeriodeAbonnement.SEMESTRIEL,
TypePeriodeAbonnement.ANNUEL); TypePeriodeAbonnement.ANNUEL);
} }
@@ -37,6 +39,8 @@ class TypePeriodeAbonnementTest {
@DisplayName("Test valueOf - toutes les constantes") @DisplayName("Test valueOf - toutes les constantes")
void testValueOf() { void testValueOf() {
assertThat(TypePeriodeAbonnement.valueOf("MENSUEL")).isEqualTo(TypePeriodeAbonnement.MENSUEL); assertThat(TypePeriodeAbonnement.valueOf("MENSUEL")).isEqualTo(TypePeriodeAbonnement.MENSUEL);
assertThat(TypePeriodeAbonnement.valueOf("TRIMESTRIEL")).isEqualTo(TypePeriodeAbonnement.TRIMESTRIEL);
assertThat(TypePeriodeAbonnement.valueOf("SEMESTRIEL")).isEqualTo(TypePeriodeAbonnement.SEMESTRIEL);
assertThat(TypePeriodeAbonnement.valueOf("ANNUEL")).isEqualTo(TypePeriodeAbonnement.ANNUEL); assertThat(TypePeriodeAbonnement.valueOf("ANNUEL")).isEqualTo(TypePeriodeAbonnement.ANNUEL);
assertThatThrownBy(() -> TypePeriodeAbonnement.valueOf("INEXISTANT")) assertThatThrownBy(() -> TypePeriodeAbonnement.valueOf("INEXISTANT"))
@@ -54,14 +58,36 @@ class TypePeriodeAbonnementTest {
@DisplayName("Test getLibelle valeurs exactes") @DisplayName("Test getLibelle valeurs exactes")
void testGetLibelleValeursExactes() { void testGetLibelleValeursExactes() {
assertThat(TypePeriodeAbonnement.MENSUEL.getLibelle()).isEqualTo("Mensuel"); assertThat(TypePeriodeAbonnement.MENSUEL.getLibelle()).isEqualTo("Mensuel");
assertThat(TypePeriodeAbonnement.ANNUEL.getLibelle()).isEqualTo("Annuel — 2 mois offerts"); assertThat(TypePeriodeAbonnement.TRIMESTRIEL.getLibelle()).contains("Trimestriel");
assertThat(TypePeriodeAbonnement.SEMESTRIEL.getLibelle()).contains("Semestriel");
assertThat(TypePeriodeAbonnement.ANNUEL.getLibelle()).contains("Annuel");
} }
@Test @Test
@DisplayName("Test name()") @DisplayName("Test name()")
void testName() { void testName() {
assertThat(TypePeriodeAbonnement.MENSUEL.name()).isEqualTo("MENSUEL"); assertThat(TypePeriodeAbonnement.MENSUEL.name()).isEqualTo("MENSUEL");
assertThat(TypePeriodeAbonnement.TRIMESTRIEL.name()).isEqualTo("TRIMESTRIEL");
assertThat(TypePeriodeAbonnement.SEMESTRIEL.name()).isEqualTo("SEMESTRIEL");
assertThat(TypePeriodeAbonnement.ANNUEL.name()).isEqualTo("ANNUEL"); assertThat(TypePeriodeAbonnement.ANNUEL.name()).isEqualTo("ANNUEL");
} }
@Test
@DisplayName("Test getNombreMois - durée en mois de chaque période")
void testGetNombreMois() {
assertThat(TypePeriodeAbonnement.MENSUEL.getNombreMois()).isEqualTo(1);
assertThat(TypePeriodeAbonnement.TRIMESTRIEL.getNombreMois()).isEqualTo(3);
assertThat(TypePeriodeAbonnement.SEMESTRIEL.getNombreMois()).isEqualTo(6);
assertThat(TypePeriodeAbonnement.ANNUEL.getNombreMois()).isEqualTo(12);
}
@Test
@DisplayName("Test getCoefficient - remise appliquée par période")
void testGetCoefficient() {
assertThat(TypePeriodeAbonnement.MENSUEL.getCoefficient()).isEqualByComparingTo("1.00");
assertThat(TypePeriodeAbonnement.TRIMESTRIEL.getCoefficient()).isEqualByComparingTo("0.95");
assertThat(TypePeriodeAbonnement.SEMESTRIEL.getCoefficient()).isEqualByComparingTo("0.90");
assertThat(TypePeriodeAbonnement.ANNUEL.getCoefficient()).isEqualByComparingTo("0.80");
}
} }
} }

View File

@@ -27,8 +27,9 @@ class StatutMembreTest {
@DisplayName("Test toutes les valeurs enum") @DisplayName("Test toutes les valeurs enum")
void testToutesValeurs() { void testToutesValeurs() {
StatutMembre[] values = StatutMembre.values(); StatutMembre[] values = StatutMembre.values();
assertThat(values).hasSize(8); assertThat(values).hasSize(10);
assertThat(values).contains( assertThat(values).contains(
StatutMembre.INVITE,
StatutMembre.EN_ATTENTE_VALIDATION, StatutMembre.EN_ATTENTE_VALIDATION,
StatutMembre.ACTIF, StatutMembre.ACTIF,
StatutMembre.INACTIF, StatutMembre.INACTIF,
@@ -36,7 +37,8 @@ class StatutMembreTest {
StatutMembre.DEMISSIONNAIRE, StatutMembre.DEMISSIONNAIRE,
StatutMembre.RADIE, StatutMembre.RADIE,
StatutMembre.HONORAIRE, StatutMembre.HONORAIRE,
StatutMembre.DECEDE); StatutMembre.DECEDE,
StatutMembre.ARCHIVE);
} }
@Test @Test

View File

@@ -7,7 +7,6 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;
@DisplayName("Tests pour TypeOrganisation") @DisplayName("Tests pour TypeOrganisation")
@@ -75,20 +74,6 @@ class TypeOrganisationTest {
assertThat(type.getLibelle()).isNotNull().isNotEmpty(); assertThat(type.getLibelle()).isNotNull().isNotEmpty();
} }
@ParameterizedTest
@CsvSource({
"LIONS_CLUB, Lions Club",
"ASSOCIATION, Association",
"ONG, ONG / Association humanitaire",
"ORGANISATION_RELIGIEUSE, Organisation religieuse",
"FEDERATION, Fédération / Union d'associations",
"AUTRE, Autre"
})
@DisplayName("Test getLibelle avec valeurs exactes")
void testGetLibelleValeursExactes(String name, String expectedLibelle) {
assertThat(TypeOrganisation.valueOf(name).getLibelle()).isEqualTo(expectedLibelle);
}
@Test @Test
@DisplayName("Test name() pour toutes les constantes") @DisplayName("Test name() pour toutes les constantes")
void testOrdinalEtName() { void testOrdinalEtName() {
@@ -101,4 +86,3 @@ class TypeOrganisationTest {
} }
} }
} }