feat(types-ref): auto-génération du code technique depuis le libellé
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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user