Files
unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/service/OrganisationModuleService.java
dahoud 4b2b326afe refactor: nettoyer terminologie entité→organisation et corriger mapping TONTINE
- ADMIN_ENTITE→ADMIN_ORGANISATION dans Javadoc et README
- OrganisationModuleService: retirer TONTINE de MUTUELLE (BCEAO-réglementé, incompatible)
- Ajouter TONTINE aux ASSOCIATION et CLUB_SERVICE (pratique courante Afrique de l'Ouest)
- V18 migration: aligner modules_requis avec le code Java
2026-04-17 19:19:48 +00:00

157 lines
5.7 KiB
Java

package dev.lions.unionflow.server.service;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.jboss.logging.Logger;
/**
* Service de gestion des modules actifs par organisation.
*
* <p>Architecture Option C — les modules actifs sont déterminés par le TYPE
* d'organisation, pas par le plan tarifaire. Le plan impacte uniquement la
* profondeur fonctionnelle (reporting, API, fédération).
*
* <p>Les modules sont regroupés en deux catégories :
* <ul>
* <li>MODULES_COMMUNS — accessibles à tous les types d'org</li>
* <li>Modules métier — spécifiques au type d'org (TONTINE, CREDIT, etc.)</li>
* </ul>
*/
@ApplicationScoped
public class OrganisationModuleService {
private static final Logger LOG = Logger.getLogger(OrganisationModuleService.class);
/** Modules présents sur toutes les organisations quelle que soit leur nature. */
public static final Set<String> MODULES_COMMUNS = Set.of(
"MEMBRES",
"COTISATIONS",
"EVENEMENTS",
"COMMUNICATION",
"DOCUMENTS",
"NOTIFICATION",
"AIDE"
);
@Inject
OrganisationRepository organisationRepository;
/**
* Retourne l'ensemble des modules actifs pour une organisation donnée.
* Combine les modules communs avec les modules métier du type d'org.
*/
public Set<String> getModulesActifs(UUID organisationId) {
Optional<Organisation> opt = organisationRepository.findByIdOptional(organisationId);
if (opt.isEmpty()) {
LOG.warnf("Organisation introuvable : %s", organisationId);
return MODULES_COMMUNS;
}
return getModulesActifs(opt.get());
}
/**
* Retourne l'ensemble des modules actifs pour une organisation.
*/
public Set<String> getModulesActifs(Organisation organisation) {
Set<String> modules = new LinkedHashSet<>(MODULES_COMMUNS);
// 1. Modules issus du champ modulesActifs persisté (calculé depuis types_reference en V18)
String modulesActifsCsv = organisation.getModulesActifs();
if (modulesActifsCsv != null && !modulesActifsCsv.isBlank()) {
Arrays.stream(modulesActifsCsv.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.forEach(modules::add);
return modules;
}
// 2. Fallback : déduction depuis le typeOrganisation si modulesActifs non renseigné
modules.addAll(getModulesParType(organisation.getTypeOrganisation()));
return modules;
}
/**
* Vérifie si un module spécifique est actif pour une organisation.
*/
public boolean isModuleActif(UUID organisationId, String module) {
return getModulesActifs(organisationId).contains(module.toUpperCase());
}
/**
* Retourne les modules métier associés à un type d'organisation.
* Utilisé en fallback si la colonne modules_actifs n'est pas peuplée.
*/
public Set<String> getModulesParType(String typeOrganisation) {
if (typeOrganisation == null) {
return Collections.emptySet();
}
Set<String> modules = new LinkedHashSet<>();
switch (typeOrganisation.toUpperCase()) {
case "TONTINE" -> {
modules.add("TONTINE");
modules.add("FINANCE");
}
case "MUTUELLE", "MUTUELLE_EPARGNE", "MUTUELLE_CREDIT" -> {
modules.add("EPARGNE");
modules.add("CREDIT");
modules.add("FINANCE");
modules.add("LCB_FT");
}
case "COOPERATIVE" -> {
modules.add("AGRICULTURE");
modules.add("FINANCE");
}
case "ONG", "FONDATION" -> {
modules.add("PROJETS_ONG");
modules.add("COLLECTE_FONDS");
modules.add("FINANCE");
}
case "EGLISE", "GROUPE_PRIERE" -> {
modules.add("CULTE_DONS");
}
case "SYNDICAT", "ORDRE_PROFESSIONNEL", "FEDERATION" -> {
modules.add("VOTES");
modules.add("REGISTRE_AGREMENT");
}
case "GIE" -> {
modules.add("FINANCE");
}
case "ASSOCIATION", "CLUB_SERVICE" -> {
modules.add("TONTINE");
modules.add("VOTES");
}
case "CLUB_SPORTIF", "CLUB_CULTUREL" -> {
modules.add("VOTES");
}
default -> LOG.debugf("Type d''organisation non reconnu pour module mapping : %s", typeOrganisation);
}
return modules;
}
/**
* Retourne la liste des modules actifs sous forme de tableau JSON-friendly.
* Utilisé par l'endpoint /api/organisations/{id}/modules-actifs
*/
public ModulesActifsResponse getModulesActifsResponse(UUID organisationId) {
Optional<Organisation> opt = organisationRepository.findByIdOptional(organisationId);
if (opt.isEmpty()) {
return new ModulesActifsResponse(organisationId, Collections.emptySet(), "UNKNOWN");
}
Organisation org = opt.get();
Set<String> modules = getModulesActifs(org);
return new ModulesActifsResponse(organisationId, modules, org.getTypeOrganisation());
}
/** DTO de réponse pour l'endpoint modules-actifs. */
public record ModulesActifsResponse(UUID organisationId, Set<String> modules, String typeOrganisation) {}
}