From 48604bbbc6dd8e9074a4f4c54da0efc69582fd0b Mon Sep 17 00:00:00 2001 From: dahoud <41957584+DahoudG@users.noreply.github.com> Date: Thu, 16 Apr 2026 10:20:19 +0000 Subject: [PATCH] =?UTF-8?q?feat(types-ref):=20auto-g=C3=A9n=C3=A9ration=20?= =?UTF-8?q?du=20code=20technique=20depuis=20le=20libell=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TypeReferenceService.creer() : - Si code non fourni ou vide : auto-généré depuis le libellé via genererCodeDepuisLibelle() - Si code fourni : nettoyé via normaliserCode() (strip accents, UPPER_SNAKE_CASE) - Dédoublonnage automatique : si le code existe, suffixe _2, _3, etc. Méthodes ajoutées : - genererCodeDepuisLibelle(String) : libellé → UPPER_SNAKE_CASE sans accents Ex: 'Mutuelle d''Épargne' → 'MUTUELLE_D_EPARGNE' - normaliserCode(String) : Normalizer.NFD + strip diacritics + [^A-Za-z0-9] → _ - assurerUniciteCode(String, String, UUID) : suffixe incrémental si doublon Les types système (est_systeme=true, seeded en V18) gardent leurs codes figés. Seuls les types créés par l'utilisateur bénéficient de l'auto-génération. --- .../server/service/TypeReferenceService.java | 69 ++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/lions/unionflow/server/service/TypeReferenceService.java b/src/main/java/dev/lions/unionflow/server/service/TypeReferenceService.java index f968679..b851829 100644 --- a/src/main/java/dev/lions/unionflow/server/service/TypeReferenceService.java +++ b/src/main/java/dev/lions/unionflow/server/service/TypeReferenceService.java @@ -10,6 +10,7 @@ import dev.lions.unionflow.server.repository.TypeReferenceRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; +import java.text.Normalizer; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -118,14 +119,23 @@ public class TypeReferenceService { @Transactional public TypeReferenceResponse creer( CreateTypeReferenceRequest request) { + // Auto-génération du code depuis le libellé si non fourni + // ou nettoyage si fourni (UPPER_SNAKE_CASE, sans accents ni caractères spéciaux) + String code = (request.code() != null && !request.code().isBlank()) + ? normaliserCode(request.code()) + : genererCodeDepuisLibelle(request.libelle()); + + // Dédoublonnage : si le code existe déjà, suffixer _2, _3, etc. + code = assurerUniciteCode(code, request.domaine(), request.organisationId()); + validerUnicite( request.domaine(), - request.code(), + code, request.organisationId()); TypeReference entity = TypeReference.builder() .domaine(request.domaine()) - .code(request.code()) + .code(code) .libelle(request.libelle()) .description(request.description()) .icone(request.icone()) @@ -364,4 +374,59 @@ public class TypeReferenceService { + domaine + "'"); } } + + // ── Auto-génération de codes techniques ───────────────────────── + + /** + * Génère un code UPPER_SNAKE_CASE depuis un libellé. + * Ex: "Mon Association Locale" → "MON_ASSOCIATION_LOCALE" + * "Église de Dakar" → "EGLISE_DE_DAKAR" + * "Mutuelle d'Épargne" → "MUTUELLE_D_EPARGNE" + */ + static String genererCodeDepuisLibelle(String libelle) { + if (libelle == null || libelle.isBlank()) { + return "TYPE_" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); + } + return normaliserCode(libelle); + } + + /** + * Normalise une chaîne en code technique UPPER_SNAKE_CASE : + * strip accents, remplace tout non-alphanumérique par _, collapse _, trim _. + */ + static String normaliserCode(String input) { + // 1. Décomposer les accents puis les retirer + String s = Normalizer.normalize(input, Normalizer.Form.NFD) + .replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); + // 2. Remplacer tout non-alphanumérique par underscore + s = s.replaceAll("[^A-Za-z0-9]+", "_"); + // 3. Majuscules + s = s.toUpperCase(); + // 4. Collapse underscores multiples et trim + s = s.replaceAll("_+", "_").replaceAll("^_|_$", ""); + // 5. Safety : si vide après nettoyage + if (s.isEmpty()) { + s = "TYPE_" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); + } + return s; + } + + /** + * S'assure que le code est unique dans le domaine. Si le code existe déjà, + * suffixe avec _2, _3, etc. jusqu'à trouver un code libre. + */ + private String assurerUniciteCode(String baseCode, String domaine, UUID organisationId) { + String candidate = baseCode; + int suffix = 2; + while (repository.existsByDomaineAndCode(domaine, candidate, organisationId)) { + candidate = baseCode + "_" + suffix; + suffix++; + if (suffix > 100) { + // Protection anti-boucle infinie + candidate = baseCode + "_" + UUID.randomUUID().toString().substring(0, 4).toUpperCase(); + break; + } + } + return candidate; + } }