Files
unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/service/OrganisationService.java
dahoud 78d8fd7cd8 feat(sync): MembreRoleSyncService + count admins dynamique
- Nouveau MembreRoleSyncService.ensureOrgAdminRole : auto-crée un MembreRole ORGADMIN
  quand un user avec rôle Keycloak ADMIN_ORGANISATION se connecte sans entrée DB
  (couvre les comptes créés directement dans Keycloak).
- OrganisationContextFilter appelle syncService.ensureOrgAdminRole quand le rôle
  Keycloak est présent mais MembreRole absent (non bloquant sur erreur).
- MembreRoleRepository.countAdminsByOrganisationId : count strict (ORGADMIN + actif
  + dateDebut/dateFin valides) avec fallback sur codes alternatifs si strict=0.
- OrganisationService.convertToResponse : nombreAdministrateurs dynamique via
  MembreRoleRepository (remplace le champ Organisation jamais mis à jour).
2026-04-15 20:05:49 +00:00

778 lines
32 KiB
Java

package dev.lions.unionflow.server.service;
import dev.lions.unionflow.server.api.dto.organisation.request.CreateOrganisationRequest;
import dev.lions.unionflow.server.api.dto.organisation.request.UpdateOrganisationRequest;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse;
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.MembreOrganisation;
import dev.lions.unionflow.server.repository.AdresseRepository;
import dev.lions.unionflow.server.repository.EvenementRepository;
import dev.lions.unionflow.server.repository.MembreOrganisationRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.MembreRoleRepository;
import dev.lions.unionflow.server.repository.TypeReferenceRepository;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;
/**
* Service métier pour la gestion des organisations
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-15
*/
@ApplicationScoped
public class OrganisationService {
private static final Logger LOG = Logger.getLogger(OrganisationService.class);
@Inject
OrganisationRepository organisationRepository;
@Inject
MembreRepository membreRepository;
@Inject
DefaultsService defaultsService;
@Inject
TypeReferenceRepository typeReferenceRepository;
@Inject
MembreOrganisationRepository membreOrganisationRepository;
@Inject
AdresseRepository adresseRepository;
@Inject
EvenementRepository evenementRepository;
@Inject
MembreRoleRepository membreRoleRepository;
/**
* Crée une nouvelle organisation
*
* @param organisation l'organisation à créer
* @param utilisateur identifiant de l'utilisateur effectuant la création
* (email ou "system")
* @return l'organisation créée
*/
@Transactional
public Organisation creerOrganisation(Organisation organisation, String utilisateur) {
LOG.infof("Création d'une nouvelle organisation: %s", organisation.getNom());
// Vérifier l'unicité de l'email
if (organisationRepository.findByEmail(organisation.getEmail()).isPresent()) {
throw new IllegalStateException("Une organisation avec cet email existe déjà");
}
// Vérifier l'unicité du nom
if (organisationRepository.findByNom(organisation.getNom()).isPresent()) {
throw new IllegalArgumentException("Une organisation avec ce nom existe déjà");
}
// Vérifier l'unicité du numéro d'enregistrement si fourni
if (organisation.getNumeroEnregistrement() != null
&& !organisation.getNumeroEnregistrement().isEmpty()) {
if (organisationRepository
.findByNumeroEnregistrement(organisation.getNumeroEnregistrement())
.isPresent()) {
throw new IllegalArgumentException(
"Une organisation avec ce numéro d'enregistrement existe déjà");
}
}
// Définir les valeurs par défaut
if (organisation.getStatut() == null) {
organisation.setStatut("ACTIVE");
}
if (organisation.getTypeOrganisation() == null) {
organisation.setTypeOrganisation("ASSOCIATION");
}
// Initialiser modulesActifs et categorieType depuis types_reference
// Cela permet aux types créés via CRUD (ex: "TANTANPION") d'hériter
// automatiquement de leurs modules_requis sans modifier le code Java.
if (organisation.getModulesActifs() == null || organisation.getModulesActifs().isBlank()) {
typeReferenceRepository
.findByDomaineAndCode("TYPE_ORGANISATION", organisation.getTypeOrganisation())
.ifPresentOrElse(
tr -> {
if (tr.getModulesRequis() != null && !tr.getModulesRequis().isBlank()) {
organisation.setModulesActifs(tr.getModulesRequis());
LOG.infof("Modules initialisés depuis types_reference pour le type '%s': %s",
organisation.getTypeOrganisation(), tr.getModulesRequis());
}
if (tr.getCategorie() != null && organisation.getCategorieType() == null) {
organisation.setCategorieType(tr.getCategorie());
}
},
() -> LOG.warnf(
"Type d'organisation '%s' absent de types_reference — modules non initialisés. " +
"Ajoutez ce type via l'administration pour activer les modules métier.",
organisation.getTypeOrganisation()));
}
// Audit : créé par / modifié par (BaseEntity n'initialise pas creePar dans
// @PrePersist)
String auditUser = utilisateur != null && !utilisateur.isBlank() ? utilisateur : "system";
organisation.setCreePar(auditUser);
organisation.setModifiePar(auditUser);
if (organisation.getDateCreation() == null) {
organisation.setDateCreation(LocalDateTime.now());
}
organisation.setDateModification(organisation.getDateCreation());
organisationRepository.persist(organisation);
LOG.infof(
"Organisation créée avec succès: ID=%s, Nom=%s", organisation.getId(), organisation.getNom());
return organisation;
}
/**
* Met à jour une organisation existante
*
* @param id l'ID de l'organisation
* @param organisationMiseAJour les données de mise à jour
* @param utilisateur l'utilisateur effectuant la modification
* @return l'organisation mise à jour
*/
@Transactional
public Organisation mettreAJourOrganisation(
UUID id, Organisation organisationMiseAJour, String utilisateur) {
LOG.infof("Mise à jour de l'organisation ID: %s", id);
Organisation organisation = organisationRepository
.findByIdOptional(id)
.orElseThrow(() -> new NotFoundException("Organisation non trouvée avec l'ID: " + id));
// Vérifier l'unicité de l'email si modifié
if (!organisation.getEmail().equals(organisationMiseAJour.getEmail())) {
if (organisationRepository.findByEmail(organisationMiseAJour.getEmail()).isPresent()) {
throw new IllegalStateException("Une organisation avec cet email existe déjà");
}
organisation.setEmail(organisationMiseAJour.getEmail());
}
// Vérifier l'unicité du nom si modifié
if (!organisation.getNom().equals(organisationMiseAJour.getNom())) {
if (organisationRepository.findByNom(organisationMiseAJour.getNom()).isPresent()) {
throw new IllegalArgumentException("Une organisation avec ce nom existe déjà");
}
organisation.setNom(organisationMiseAJour.getNom());
}
// Mettre à jour tous les champs métier (alignés sur detail.xhtml et
// organisation-form)
organisation.setNomCourt(organisationMiseAJour.getNomCourt());
organisation.setDescription(organisationMiseAJour.getDescription());
organisation.setDateFondation(organisationMiseAJour.getDateFondation());
organisation.setNumeroEnregistrement(organisationMiseAJour.getNumeroEnregistrement());
organisation.setTelephone(organisationMiseAJour.getTelephone());
organisation.setTelephoneSecondaire(organisationMiseAJour.getTelephoneSecondaire());
organisation.setEmailSecondaire(organisationMiseAJour.getEmailSecondaire());
organisation.setAdresse(organisationMiseAJour.getAdresse());
organisation.setVille(organisationMiseAJour.getVille());
organisation.setRegion(organisationMiseAJour.getRegion());
organisation.setPays(organisationMiseAJour.getPays());
organisation.setCodePostal(organisationMiseAJour.getCodePostal());
organisation.setLatitude(organisationMiseAJour.getLatitude());
organisation.setLongitude(organisationMiseAJour.getLongitude());
organisation.setSiteWeb(organisationMiseAJour.getSiteWeb());
organisation.setLogo(organisationMiseAJour.getLogo());
organisation.setReseauxSociaux(organisationMiseAJour.getReseauxSociaux());
organisation.setObjectifs(organisationMiseAJour.getObjectifs());
organisation.setActivitesPrincipales(organisationMiseAJour.getActivitesPrincipales());
organisation.setCertifications(organisationMiseAJour.getCertifications());
organisation.setPartenaires(organisationMiseAJour.getPartenaires());
organisation.setNotes(organisationMiseAJour.getNotes());
if (organisationMiseAJour.getStatut() != null) {
organisation.setStatut(organisationMiseAJour.getStatut());
}
organisation.setTypeOrganisation(organisationMiseAJour.getTypeOrganisation());
organisation.setNiveauHierarchique(
organisationMiseAJour.getNiveauHierarchique() != null ? organisationMiseAJour.getNiveauHierarchique() : 0);
organisation.setNombreMembres(
organisationMiseAJour.getNombreMembres() != null ? organisationMiseAJour.getNombreMembres() : 0);
organisation.setNombreAdministrateurs(
organisationMiseAJour.getNombreAdministrateurs() != null ? organisationMiseAJour.getNombreAdministrateurs()
: 0);
// Budget & Finances
organisation.setBudgetAnnuel(organisationMiseAJour.getBudgetAnnuel());
organisation.setDevise(
organisationMiseAJour.getDevise() != null ? organisationMiseAJour.getDevise() : defaultsService.getDevise());
organisation.setCotisationObligatoire(
organisationMiseAJour.getCotisationObligatoire() != null ? organisationMiseAJour.getCotisationObligatoire()
: false);
organisation.setMontantCotisationAnnuelle(organisationMiseAJour.getMontantCotisationAnnuelle());
organisation.setOrganisationPublique(
organisationMiseAJour.getOrganisationPublique() != null ? organisationMiseAJour.getOrganisationPublique()
: true);
organisation.setAccepteNouveauxMembres(
organisationMiseAJour.getAccepteNouveauxMembres() != null ? organisationMiseAJour.getAccepteNouveauxMembres()
: true);
// Hiérarchie
organisation.setOrganisationParente(organisationMiseAJour.getOrganisationParente());
organisation.marquerCommeModifie(utilisateur);
LOG.infof("Organisation mise à jour avec succès: ID=%s", id);
return organisation;
}
/**
* Supprime une organisation
*
* @param id l'UUID de l'organisation
* @param utilisateur l'utilisateur effectuant la suppression
*/
@Transactional
public void supprimerOrganisation(UUID id, String utilisateur) {
LOG.infof("Suppression de l'organisation ID: %s", id);
Organisation organisation = organisationRepository
.findByIdOptional(id)
.orElseThrow(() -> new NotFoundException("Organisation non trouvée avec l'ID: " + id));
// Vérifier qu'il n'y a pas de membres actifs
if (organisation.getNombreMembres() > 0) {
throw new IllegalStateException(
"Impossible de supprimer une organisation avec des membres actifs");
}
// Soft delete - marquer comme inactive
organisation.setActif(false);
organisation.setStatut("DISSOUTE");
organisation.marquerCommeModifie(utilisateur);
LOG.infof("Organisation supprimée (soft delete) avec succès: ID=%s", id);
}
/**
* Trouve une organisation par son ID
*
* @param id l'UUID de l'organisation
* @return Optional contenant l'organisation si trouvée
*/
public Optional<Organisation> trouverParId(UUID id) {
return organisationRepository.findByIdOptional(id);
}
/**
* Trouve une organisation par son email
*
* @param email l'email de l'organisation
* @return Optional contenant l'organisation si trouvée
*/
public Optional<Organisation> trouverParEmail(String email) {
return organisationRepository.findByEmail(email);
}
/**
* Liste les organisations auxquelles l'utilisateur connecté (membre) appartient.
* Utilisé pour un administrateur d'organisation qui ne doit voir que son/ses organisation(s).
*
* @param emailUtilisateur email du principal (SecurityIdentity)
* @return liste des organisations du membre, ou liste vide si membre non trouvé
*/
@Transactional
public List<Organisation> listerOrganisationsPourUtilisateur(String emailUtilisateur) {
if (emailUtilisateur == null || emailUtilisateur.isBlank()) {
return List.of();
}
return membreRepository.findByEmail(emailUtilisateur)
.map(m -> m.getMembresOrganisations().stream()
.map(mo -> mo.getOrganisation())
.distinct()
.collect(Collectors.toList()))
.orElse(List.of());
}
/**
* Associe un utilisateur (par email) à une organisation.
* Réservé au SUPER_ADMIN. Crée un Membre minimal si aucun n'existe pour cet email,
* puis crée le lien MembreOrganisation (idempotent si déjà associé).
*
* @param email email de l'utilisateur (doit correspondre à un compte Keycloak / Membre)
* @param organisationId UUID de l'organisation
* @throws NotFoundException si l'organisation n'existe pas
*/
@Transactional
public void associerUtilisateurAOrganisation(String email, UUID organisationId) {
if (email == null || email.isBlank()) {
throw new IllegalArgumentException("L'email est obligatoire");
}
if (organisationId == null) {
throw new IllegalArgumentException("L'organisation est obligatoire");
}
Organisation organisation = organisationRepository.findByIdOptional(organisationId)
.orElseThrow(() -> new NotFoundException("Organisation non trouvée: " + organisationId));
String emailNorm = email.trim().toLowerCase();
Membre membre = membreRepository.findByEmail(emailNorm).orElseGet(() -> {
Membre nouveau = creerMembreMinimalPourEmail(emailNorm);
membreRepository.persist(nouveau);
LOG.infof("Membre minimal créé pour associer l'utilisateur %s à l'organisation %s", emailNorm, organisation.getNom());
return nouveau;
});
if (membreOrganisationRepository.findByMembreIdAndOrganisationId(membre.getId(), organisationId).isPresent()) {
LOG.infof("L'utilisateur %s est déjà associé à l'organisation %s", emailNorm, organisation.getNom());
return;
}
MembreOrganisation mo = MembreOrganisation.builder()
.membre(membre)
.organisation(organisation)
.statutMembre(StatutMembre.ACTIF)
.dateAdhesion(LocalDate.now())
.build();
membreOrganisationRepository.persist(mo);
organisation.ajouterMembre();
organisationRepository.persist(organisation);
LOG.infof("Utilisateur %s associé à l'organisation %s (MembreOrganisation créé)", emailNorm, organisation.getNom());
}
/**
* Crée un Membre minimal à partir d'un email (pour associer un compte Keycloak sans fiche membre).
*/
private Membre creerMembreMinimalPourEmail(String email) {
String partieLocale = email.contains("@") ? email.substring(0, email.indexOf('@')) : email;
String prenom = partieLocale.contains(".") ? partieLocale.substring(0, partieLocale.indexOf('.')) : "Admin";
String nom = partieLocale.contains(".") ? partieLocale.substring(partieLocale.indexOf('.') + 1) : partieLocale;
if (nom.isBlank()) nom = "Utilisateur";
if (prenom.isBlank()) prenom = "Admin";
prenom = prenom.substring(0, 1).toUpperCase() + (prenom.length() > 1 ? prenom.substring(1).toLowerCase() : "");
nom = nom.substring(0, 1).toUpperCase() + (nom.length() > 1 ? nom.substring(1).toLowerCase() : "");
String numeroMembre = "UF-ADM-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
Membre m = Membre.builder()
.email(email)
.numeroMembre(numeroMembre)
.prenom(prenom)
.nom(nom)
.dateNaissance(LocalDate.now().minusYears(25))
.statutCompte("ACTIF")
.build();
m.setActif(Boolean.TRUE); // actif est dans BaseEntity, pas dans MembreBuilder
return m;
}
/**
* Liste toutes les organisations actives
*
* @return liste des organisations actives
*/
public List<Organisation> listerOrganisationsActives() {
return organisationRepository.findAllActives();
}
/**
* Liste toutes les organisations actives avec pagination
*
* @param page numéro de page
* @param size taille de la page
* @return liste paginée des organisations actives
*/
public List<Organisation> listerOrganisationsActives(int page, int size) {
return organisationRepository.findAllActives(Page.of(page, size), Sort.by("nom").ascending());
}
/**
* Compte le nombre d'organisations actives
*
* @return nombre total d'organisations actives
*/
public long compterOrganisationsActives() {
return organisationRepository.countActives();
}
/**
* Recherche d'organisations par nom
*
* @param recherche terme de recherche
* @param page numéro de page
* @param size taille de la page
* @return liste paginée des organisations correspondantes
*/
public List<Organisation> rechercherOrganisations(String recherche, int page, int size) {
return organisationRepository.findByNomOrNomCourt(
recherche, Page.of(page, size), Sort.by("nom").ascending());
}
public long rechercherOrganisationsCount(String recherche) {
if (recherche == null || recherche.trim().isEmpty()) {
return organisationRepository.count();
}
String pattern = "%" + recherche.trim().toLowerCase() + "%";
return organisationRepository.getEntityManager()
.createQuery(
"SELECT COUNT(o) FROM Organisation o WHERE LOWER(o.nom) LIKE :p OR LOWER(o.description) LIKE :p",
Long.class)
.setParameter("p", pattern)
.getSingleResult();
}
/**
* Recherche avancée d'organisations
*
* @param nom nom (optionnel)
* @param typeOrganisation type (optionnel)
* @param statut statut (optionnel)
* @param ville ville (optionnel)
* @param region région (optionnel)
* @param pays pays (optionnel)
* @param page numéro de page
* @param size taille de la page
* @return liste filtrée des organisations
*/
public List<Organisation> rechercheAvancee(
String nom,
String typeOrganisation,
String statut,
String ville,
String region,
String pays,
int page,
int size) {
return organisationRepository.rechercheAvancee(
nom, typeOrganisation, statut, ville, region, pays, Page.of(page, size));
}
/**
* Active une organisation
*
* @param id l'ID de l'organisation
* @param utilisateur l'utilisateur effectuant l'activation
* @return l'organisation activée
*/
@Transactional
public Organisation activerOrganisation(UUID id, String utilisateur) {
LOG.infof("Activation de l'organisation ID: %s", id);
Organisation organisation = organisationRepository
.findByIdOptional(id)
.orElseThrow(() -> new NotFoundException("Organisation non trouvée avec l'ID: " + id));
organisation.activer(utilisateur);
LOG.infof("Organisation activée avec succès: ID=%s", id);
return organisation;
}
/**
* Suspend une organisation
*
* @param id l'UUID de l'organisation
* @param utilisateur l'utilisateur effectuant la suspension
* @return l'organisation suspendue
*/
@Transactional
public Organisation suspendreOrganisation(UUID id, String utilisateur) {
LOG.infof("Suspension de l'organisation ID: %s", id);
Organisation organisation = organisationRepository
.findByIdOptional(id)
.orElseThrow(() -> new NotFoundException("Organisation non trouvée avec l'ID: " + id));
organisation.suspendre(utilisateur);
LOG.infof("Organisation suspendue avec succès: ID=%s", id);
return organisation;
}
/**
* Obtient les statistiques des organisations (clés compatibles client DTO
* StatistiquesAssociationDTO).
*
* @return map contenant les statistiques
*/
public Map<String, Object> obtenirStatistiques() {
LOG.info("Calcul des statistiques des organisations");
long total = organisationRepository.count();
long actives = organisationRepository.countActives();
long inactives = total - actives;
long suspendues = organisationRepository.countByStatut("SUSPENDUE");
long dissoutes = organisationRepository.countByStatut("DISSOLUE");
long nouvelles30Jours = organisationRepository.countNouvellesOrganisations(LocalDate.now().minusDays(30));
double tauxActivite = total > 0 ? (actives * 100.0 / total) : 0.0;
List<Organisation> all = organisationRepository.listAll();
Map<String, Long> repartitionType = all.stream()
.collect(Collectors.groupingBy(
o -> o.getTypeOrganisation() != null ? o.getTypeOrganisation() : "NON_DEFINI",
Collectors.counting()));
Map<String, Long> repartitionRegion = adresseRepository
.find("organisation IS NOT NULL AND region IS NOT NULL")
.list()
.stream()
.collect(Collectors.groupingBy(
a -> a.getRegion(),
Collectors.counting()));
Map<String, Object> map = new HashMap<>();
map.put("totalAssociations", total);
map.put("associationsActives", actives);
map.put("associationsInactives", inactives);
map.put("associationsSuspendues", suspendues);
map.put("associationsDissoutes", dissoutes);
map.put("nouvellesAssociations30Jours", nouvelles30Jours);
map.put("tauxActivite", tauxActivite);
map.put("repartitionParType", repartitionType);
map.put("repartitionParRegion", repartitionRegion);
return map;
}
/**
* Convertit une entité Organisation en DTO complet
*/
public OrganisationResponse convertToResponse(Organisation organisation) {
if (organisation == null) {
return null;
}
OrganisationResponse dto = new OrganisationResponse();
dto.setId(organisation.getId());
dto.setNom(organisation.getNom());
dto.setNomCourt(organisation.getNomCourt());
dto.setDescription(organisation.getDescription());
dto.setEmail(organisation.getEmail());
dto.setTelephone(organisation.getTelephone());
dto.setTelephoneSecondaire(organisation.getTelephoneSecondaire());
dto.setEmailSecondaire(organisation.getEmailSecondaire());
dto.setAdresse(organisation.getAdresse());
dto.setVille(organisation.getVille());
dto.setRegion(organisation.getRegion());
dto.setPays(organisation.getPays());
dto.setCodePostal(organisation.getCodePostal());
dto.setLatitude(organisation.getLatitude());
dto.setLongitude(organisation.getLongitude());
dto.setSiteWeb(organisation.getSiteWeb());
dto.setLogo(organisation.getLogo());
dto.setReseauxSociaux(organisation.getReseauxSociaux());
dto.setObjectifs(organisation.getObjectifs());
dto.setActivitesPrincipales(organisation.getActivitesPrincipales());
dto.setNombreMembres(organisation.getNombreMembres());
if (organisation.getId() != null) {
// Compte dynamique des administrateurs (rôle ADMIN_ORGANISATION actif)
// — le champ Organisation.nombreAdministrateurs n'est pas tenu à jour.
long countAdmins = membreRoleRepository.countAdminsByOrganisationId(organisation.getId());
dto.setNombreAdministrateurs((int) countAdmins);
long countEvenements = evenementRepository.countActifsByOrganisationId(organisation.getId());
dto.setNombreEvenements((int) countEvenements);
} else {
dto.setNombreAdministrateurs(0);
dto.setNombreEvenements(0);
}
dto.setBudgetAnnuel(organisation.getBudgetAnnuel());
dto.setDevise(organisation.getDevise());
dto.setDateFondation(organisation.getDateFondation());
dto.setNumeroEnregistrement(organisation.getNumeroEnregistrement());
dto.setNiveauHierarchique(organisation.getNiveauHierarchique());
if (organisation.getOrganisationParente() != null) {
dto.setOrganisationParenteId(organisation.getOrganisationParente().getId());
dto.setOrganisationParenteNom(organisation.getOrganisationParente().getNom());
}
dto.setTypeOrganisation(organisation.getTypeOrganisation());
dto.setTypeAssociation(organisation.getTypeOrganisation());
dto.setStatut(organisation.getStatut());
// Résolution des libellés
if (organisation.getTypeOrganisation() != null) {
typeReferenceRepository.findByDomaineAndCode("TYPE_ORGANISATION", organisation.getTypeOrganisation())
.ifPresent(ref -> {
dto.setTypeOrganisationLibelle(ref.getLibelle());
dto.setTypeLibelle(ref.getLibelle());
});
if (dto.getTypeLibelle() == null) {
dto.setTypeLibelle(organisation.getTypeOrganisation());
}
}
if (organisation.getStatut() != null) {
typeReferenceRepository.findByDomaineAndCode("STATUT_ORGANISATION", organisation.getStatut())
.ifPresent(ref -> {
dto.setStatutLibelle(ref.getLibelle());
dto.setStatutSeverity(ref.getCouleur()); // ou severity si dispo
});
}
dto.setDateCreation(organisation.getDateCreation());
dto.setDateModification(organisation.getDateModification());
dto.setCreePar(organisation.getCreePar());
dto.setModifiePar(organisation.getModifiePar());
dto.setActif(organisation.getActif());
dto.setVersion(organisation.getVersion());
dto.setOrganisationPublique(organisation.getOrganisationPublique());
dto.setAccepteNouveauxMembres(organisation.getAccepteNouveauxMembres());
dto.setCotisationObligatoire(organisation.getCotisationObligatoire());
dto.setMontantCotisationAnnuelle(organisation.getMontantCotisationAnnuelle());
return dto;
}
/**
* Convertit une entité Organisation en Summary DTO
*/
public OrganisationSummaryResponse convertToSummaryResponse(Organisation organisation) {
if (organisation == null)
return null;
String typeLibelle = organisation.getTypeOrganisation();
if (organisation.getTypeOrganisation() != null) {
typeLibelle = typeReferenceRepository
.findByDomaineAndCode("TYPE_ORGANISATION", organisation.getTypeOrganisation())
.map(dev.lions.unionflow.server.entity.TypeReference::getLibelle)
.orElse(organisation.getTypeOrganisation());
}
String statutLibelle = organisation.getStatut();
String statutSeverity = null;
if (organisation.getStatut() != null) {
var refOpt = typeReferenceRepository.findByDomaineAndCode("STATUT_ORGANISATION", organisation.getStatut());
if (refOpt.isPresent()) {
statutLibelle = refOpt.get().getLibelle();
statutSeverity = refOpt.get().getCouleur();
}
}
return new OrganisationSummaryResponse(
organisation.getId(),
organisation.getNom(),
organisation.getNomCourt(),
organisation.getTypeOrganisation(),
typeLibelle,
organisation.getStatut(),
statutLibelle,
statutSeverity,
organisation.getNombreMembres(),
organisation.getActif());
}
/**
* Crée une entité Organisation depuis CreateOrganisationRequest
*/
public Organisation convertFromCreateRequest(CreateOrganisationRequest req) {
if (req == null)
return null;
return Organisation.builder()
.nom(req.nom())
.nomCourt(req.nomCourt())
.description(req.description())
.email(req.email())
.telephone(req.telephone())
.telephoneSecondaire(req.telephoneSecondaire())
.emailSecondaire(req.emailSecondaire())
.latitude(req.latitude())
.longitude(req.longitude())
.siteWeb(req.siteWeb())
.logo(req.logo())
.reseauxSociaux(req.reseauxSociaux())
.objectifs(req.objectifs())
.activitesPrincipales(req.activitesPrincipales())
.certifications(req.certifications())
.partenaires(req.partenaires())
.notes(req.notes())
.dateFondation(req.dateFondation())
.numeroEnregistrement(req.numeroEnregistrement())
.typeOrganisation(req.typeOrganisation() != null ? req.typeOrganisation() : "ASSOCIATION")
.statut(req.statut() != null ? req.statut() : "ACTIVE")
.budgetAnnuel(req.budgetAnnuel())
.devise(req.devise() != null ? req.devise() : defaultsService.getDevise())
.cotisationObligatoire(req.cotisationObligatoire() != null ? req.cotisationObligatoire() : false)
.montantCotisationAnnuelle(req.montantCotisationAnnuelle())
.adresse(req.adresse())
.ville(req.ville())
.region(req.region())
.pays(req.pays())
.codePostal(req.codePostal())
.organisationPublique(req.organisationPublique() != null ? req.organisationPublique() : true)
.accepteNouveauxMembres(req.accepteNouveauxMembres() != null ? req.accepteNouveauxMembres() : true)
.build();
}
/**
* Crée une entité Organisation depuis UpdateOrganisationRequest
*/
public Organisation convertFromUpdateRequest(UpdateOrganisationRequest req) {
if (req == null)
return null;
return Organisation.builder()
.nom(req.nom())
.nomCourt(req.nomCourt())
.description(req.description())
.email(req.email())
.telephone(req.telephone())
.telephoneSecondaire(req.telephoneSecondaire())
.emailSecondaire(req.emailSecondaire())
.latitude(req.latitude())
.longitude(req.longitude())
.siteWeb(req.siteWeb())
.logo(req.logo())
.reseauxSociaux(req.reseauxSociaux())
.objectifs(req.objectifs())
.activitesPrincipales(req.activitesPrincipales())
.certifications(req.certifications())
.partenaires(req.partenaires())
.notes(req.notes())
.dateFondation(req.dateFondation())
.numeroEnregistrement(req.numeroEnregistrement())
.typeOrganisation(req.typeOrganisation())
.statut(req.statut())
.budgetAnnuel(req.budgetAnnuel())
.devise(req.devise() != null ? req.devise() : defaultsService.getDevise())
.cotisationObligatoire(req.cotisationObligatoire() != null ? req.cotisationObligatoire() : false)
.montantCotisationAnnuelle(req.montantCotisationAnnuelle())
.adresse(req.adresse())
.ville(req.ville())
.region(req.region())
.pays(req.pays())
.codePostal(req.codePostal())
.organisationPublique(req.organisationPublique() != null ? req.organisationPublique() : true)
.accepteNouveauxMembres(req.accepteNouveauxMembres() != null ? req.accepteNouveauxMembres() : true)
.build();
}
/**
* Retourne la liste des organisations d'un membre (pour le sélecteur multi-org).
* Inclut les infos nécessaires au sélecteur : id, nom, type, catégorie, modules, rôle du membre.
*/
public java.util.List<java.util.Map<String, Object>> listerOrganisationsParMembre(java.util.UUID membreId) {
java.util.List<MembreOrganisation> liens = membreOrganisationRepository.findOrganisationsActivesParMembre(membreId);
return liens.stream().map(lien -> {
Organisation org = lien.getOrganisation();
java.util.Map<String, Object> entry = new java.util.LinkedHashMap<>();
entry.put("organisationId", org.getId());
entry.put("nom", org.getNom());
entry.put("nomCourt", org.getNomCourt());
entry.put("typeOrganisation", org.getTypeOrganisation());
entry.put("categorieType", org.getCategorieType());
entry.put("modulesActifs", org.getModulesActifs());
entry.put("statut", org.getStatut());
entry.put("statutMembre", lien.getStatutMembre() != null ? lien.getStatutMembre().name() : null);
entry.put("roleOrg", lien.getRoleOrg());
entry.put("dateAdhesion", lien.getDateAdhesion());
return entry;
}).toList();
}
}