package dev.lions.unionflow.server.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import dev.lions.unionflow.server.api.enums.membre.StatutMembre; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.UUID; import lombok.*; /** * Lien entre un utilisateur et une organisation. * *

Un utilisateur peut adhérer à plusieurs organisations simultanément. * Chaque adhésion a son propre statut, date et unité d'affectation. * *

Table : {@code membres_organisations} */ @Entity @Table( name = "membres_organisations", indexes = { @Index(name = "idx_mo_utilisateur", columnList = "utilisateur_id"), @Index(name = "idx_mo_organisation", columnList = "organisation_id"), @Index(name = "idx_mo_statut", columnList = "statut_membre"), @Index(name = "idx_mo_unite", columnList = "unite_id") }, uniqueConstraints = { @UniqueConstraint( name = "uk_mo_utilisateur_organisation", columnNames = {"utilisateur_id", "organisation_id"}) }) @Data @NoArgsConstructor @AllArgsConstructor @Builder @EqualsAndHashCode(callSuper = true) public class MembreOrganisation extends BaseEntity { /** L'utilisateur (identité globale) */ @NotNull @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "utilisateur_id", nullable = false) private Membre membre; /** L'organisation racine à laquelle appartient ce membre */ @NotNull @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "organisation_id", nullable = false) private Organisation organisation; /** * Unité d'affectation (agence/bureau). * NULL = affecté au siège. */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "unite_id") private Organisation unite; @Enumerated(EnumType.STRING) @Builder.Default @Column(name = "statut_membre", nullable = false, length = 30) private StatutMembre statutMembre = StatutMembre.EN_ATTENTE_VALIDATION; @Column(name = "date_adhesion") private LocalDate dateAdhesion; @Column(name = "date_changement_statut") private LocalDate dateChangementStatut; @Column(name = "motif_statut", length = 500) private String motifStatut; /** Utilisateur qui a approuvé ou traité ce changement de statut */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "approuve_par_id") private Membre approuvePar; // ── Champs d'invitation (StatutMembre.INVITE) ────────────────────────────── /** Date à laquelle l'invitation a été envoyée. */ @Column(name = "date_invitation") private LocalDateTime dateInvitation; /** Date d'expiration de l'invitation (null = pas d'expiration). */ @Column(name = "date_expiration_invitation") private LocalDateTime dateExpirationInvitation; /** Token opaque utilisé dans le lien d'invitation envoyé par email. */ @Column(name = "token_invitation", length = 64) private String tokenInvitation; /** ID de l'administrateur qui a envoyé l'invitation. */ @Column(name = "invite_par") private UUID invitePar; /** Motif d'archivage (pour StatutMembre.ARCHIVE). */ @Column(name = "motif_archivage", length = 500) private String motifArchivage; // ── Rôle fonctionnel dans l'organisation ───────────────────────────────── /** Rôle de ce membre dans l'organisation (ex: PRESIDENT, TRESORIER...). */ @Column(name = "role_org", length = 50) private String roleOrg; // ── Relations ───────────────────────────────────────────────────────────── /** Rôles de ce membre dans cette organisation */ @JsonIgnore @OneToMany(mappedBy = "membreOrganisation", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @Builder.Default private List roles = new ArrayList<>(); /** Ayants droit (mutuelles de santé uniquement) */ @JsonIgnore @OneToMany(mappedBy = "membreOrganisation", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @Builder.Default private List ayantsDroit = new ArrayList<>(); // ── Méthodes métier ──────────────────────────────────────────────────────── public boolean isActif() { return StatutMembre.ACTIF.equals(statutMembre) && Boolean.TRUE.equals(getActif()); } public boolean peutDemanderAide() { return StatutMembre.ACTIF.equals(statutMembre); } @PrePersist protected void onCreate() { super.onCreate(); if (statutMembre == null) { statutMembre = StatutMembre.EN_ATTENTE_VALIDATION; } } }