feat(v3.0): implémentation Phases 0-8 — RBAC, lifecycle, multi-org, plans, dashboards
Phase 0 : @RolesAllowed SUPER_ADMIN sur POST/DELETE organisations ; AuthenticationFilter pages super-admin Phase 2 : OrganisationModuleService, @RequiresModule, ModuleAccessFilter, RoleService, PermissionChecker Phase 3 : multi-org context switching (OrganisationContextFilter, headers X-Active-Organisation-Id / X-Active-Role) Phase 4 : feature-gating navigation par typeOrganisation (web MenuBean + mobile MorePage) Phase 5 : MemberLifecycleService — 8 transitions (activer/suspendre/radier/archiver/inviter/accepter/expirer/rappels) Phase 6 : FormuleAbonnement Option C (planCommercial, apiAccess, federationAccess, quotas) + SouscriptionOrganisation méthodes quota Phase 7 : DashboardResource SUPER_ADMIN ajouté ; DashboardBean.checkAccessAndRedirect() ; dashboards distincts par rôle Phase 8 : MembreResourceLifecycleRbacTest, SouscriptionQuotaOptionCTest, OrganisationContextHolderTest, OrganisationContextFilterMultiOrgTest, MemberLifecycleServiceTest
This commit is contained in:
@@ -77,6 +77,39 @@ public class FormuleAbonnement extends BaseEntity {
|
||||
@Column(name = "ordre_affichage", nullable = false)
|
||||
private Integer ordreAffichage = 0;
|
||||
|
||||
// ── Champs Option C (ajoutés en V19) ──────────────────────────────────────
|
||||
|
||||
/** Nom commercial du plan (MICRO, DECOUVERTE, ESSENTIEL, AVANCE, PROFESSIONNEL, ENTERPRISE) */
|
||||
@Column(name = "plan_commercial", length = 30)
|
||||
private String planCommercial;
|
||||
|
||||
/** Niveau de reporting disponible (BASIQUE, STANDARD, AVANCE) */
|
||||
@Column(name = "niveau_reporting", length = 20)
|
||||
private String niveauReporting;
|
||||
|
||||
/** Accès à l'API REST (false pour les plans de base) */
|
||||
@Builder.Default
|
||||
@Column(name = "api_access", nullable = false)
|
||||
private Boolean apiAccess = false;
|
||||
|
||||
/** Accès au module de fédération multi-org (ENTERPRISE uniquement) */
|
||||
@Builder.Default
|
||||
@Column(name = "federation_access", nullable = false)
|
||||
private Boolean federationAccess = false;
|
||||
|
||||
/** Support prioritaire inclus */
|
||||
@Builder.Default
|
||||
@Column(name = "support_prioritaire", nullable = false)
|
||||
private Boolean supportPrioritaire = false;
|
||||
|
||||
/** SLA garanti (ex: "99.0%", "99.9%") */
|
||||
@Column(name = "sla_garanti", length = 10)
|
||||
private String slaGaranti;
|
||||
|
||||
/** Nombre maximum d'administrateurs. NULL = illimité */
|
||||
@Column(name = "max_admins")
|
||||
private Integer maxAdmins;
|
||||
|
||||
public boolean isIllimitee() {
|
||||
return maxMembres == null;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ 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.*;
|
||||
|
||||
/**
|
||||
@@ -77,6 +79,34 @@ public class MembreOrganisation extends BaseEntity {
|
||||
@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 */
|
||||
|
||||
@@ -197,6 +197,14 @@ public class Organisation extends BaseEntity {
|
||||
@Column(name = "accepte_nouveaux_membres", nullable = false)
|
||||
private Boolean accepteNouveauxMembres = true;
|
||||
|
||||
/** Catégorie du type d'organisation (ASSOCIATIF, FINANCIER_SOLIDAIRE, RELIGIEUX, PROFESSIONNEL, RESEAU_FEDERATION) */
|
||||
@Column(name = "categorie_type", length = 50)
|
||||
private String categorieType;
|
||||
|
||||
/** Modules activés pour cette organisation (liste CSV, ex: "MEMBRES,COTISATIONS,TONTINE") */
|
||||
@Column(name = "modules_actifs", length = 1000)
|
||||
private String modulesActifs;
|
||||
|
||||
// Relations
|
||||
|
||||
/** Adhésions des membres à cette organisation */
|
||||
|
||||
@@ -56,6 +56,11 @@ public class Role extends BaseEntity {
|
||||
@Column(name = "type_role", nullable = false, length = 50)
|
||||
private String typeRole;
|
||||
|
||||
/** Catégorie du rôle (PLATEFORME, FONCTIONNEL, METIER) */
|
||||
@Column(name = "categorie", length = 30)
|
||||
@Builder.Default
|
||||
private String categorie = "FONCTIONNEL";
|
||||
|
||||
/** Organisation propriétaire (null pour rôles système) */
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "organisation_id")
|
||||
|
||||
Reference in New Issue
Block a user