- 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
157 lines
5.7 KiB
Java
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) {}
|
|
}
|