Champs personnalisés (ChampsUtilisateur)
Les champs personnalisés étendent le profil de l'employé avec des données métier spécifiques au client : département, poste, statut RH, options internes, etc. Ce guide couvre la définition, le scoping par employeur, les options de choix, et l'assignation des valeurs.
Module requis : MaCarteDeMembre.
Client SDK : IChampUtilisateurClient.
1. Modèle
Un champ personnalisé est défini une fois au niveau du client MCM. Il est ensuite :
- Scopé à un sous-ensemble d'employeurs (ou à tous).
- Typé : texte libre, date, booléen, ou liste de choix.
- Affecté à chaque employé en lui passant une valeur au sein de
B2BUpsertEmployeDtoV2.ValeursChampUtilisateur(ouB2BUpdateEmployeDto).
Client MCM
└ ChampUtilisateur (Nom unique)
├ Type (Texte / Date / Booleen / Choix)
├ Scope Employeurs : [EMP001, EMP002, …]
├ Choix : [Oui, Non, Partiel] (si Type=Choix)
└ Valeurs assignées aux Employés
2. Types de champs
Les types sont identifiés par des GUIDs constants (B2BTypeChampUtilisateur) :
| Constante | GUID | Description |
|---|---|---|
B2BTypeChampUtilisateur.Texte | ...004 | Texte libre (MaxLength configurable) |
B2BTypeChampUtilisateur.Date | ...002 | Saisie de date |
B2BTypeChampUtilisateur.Booleen | ...003 | Case à cocher (oui/non) |
B2BTypeChampUtilisateur.Choix | ...001 | Liste déroulante (options définies séparément) |
using MCM.B2B.Contracts;
var typeId = Guid.Parse(B2BTypeChampUtilisateur.Texte);
3. Créer un champ
Texte libre
await champUtilisateurClient.AddChampUtilisateur(new B2BAddChampUtilisateurDto
{
Nom = "departement", // clé, unique
TypeChampUtilisateurId = Guid.Parse(B2BTypeChampUtilisateur.Texte),
Label = "Département",
MaxLength = 100,
Ordre = 1,
EstRequis = false,
TexteAide = "Département opérationnel du membre."
});
Nom est l'identifiant stable (slug). Label est l'affichage UI.
Choix (liste déroulante)
// 1. Créer le champ
await champUtilisateurClient.AddChampUtilisateur(new B2BAddChampUtilisateurDto
{
Nom = "statut_rh",
TypeChampUtilisateurId = Guid.Parse(B2BTypeChampUtilisateur.Choix),
Label = "Statut RH",
MaxLength = 0,
Ordre = 2,
EstRequis = true
});
// 2. Définir les options
await champUtilisateurClient.SetChoix("statut_rh", new B2BSetChoixChampUtilisateurRequest
{
Choix =
[
new() { IdExterne = "ACT", Label = "Actif", Ordre = 1 },
new() { IdExterne = "INA", Label = "Inactif", Ordre = 2 },
new() { IdExterne = "RET", Label = "Retraité", Ordre = 3 }
]
});
SetChoix est un remplacement complet — la liste fournie remplace les options existantes. Préservez les IdExterne des options existantes si vous voulez conserver leurs assignations sur les employés.
Date ou booléen
Même pattern qu'un texte, mais sans MaxLength significatif :
await champUtilisateurClient.AddChampUtilisateur(new B2BAddChampUtilisateurDto
{
Nom = "date_conge_sabbatique",
TypeChampUtilisateurId = Guid.Parse(B2BTypeChampUtilisateur.Date),
Label = "Début du congé sabbatique",
MaxLength = 0,
Ordre = 3
});
4. Scoper à des employeurs
Par défaut, un champ créé est disponible pour tous les employeurs. Pour le restreindre :
await champUtilisateurClient.SetEmployeurs("departement",
new B2BSetEmployeursChampUtilisateurRequest
{
IdExternes = ["EMP001", "EMP002"]
});
- Liste vide
[]= aucune restriction retirée (vérifier : appelezGetChampUtilisateurByNom; la listeEmployeursreflète le scoping). - Remplacement complet à chaque appel (pas d'ajout/retrait granulaire).
Utile quand un même client MCM intègre plusieurs organisations (fédération) et que chaque employeur a ses propres champs.
5. Assigner une valeur à un employé
Les valeurs voyagent dans le DTO employé, pas via un endpoint séparé. Elles sont mises à jour lors d'un UpdateEmploye ou d'un Sync.
Via Sync V2
var employe = new B2BUpsertEmployeDtoV2
{
IdExterne = "PERSON001",
Prenom = "Alice",
Nom = "Tremblay",
Courriel = "alice@example.com",
ValeursChampUtilisateur =
[
new() { NomChamp = "departement", Valeur = "Finances" },
new() { NomChamp = "statut_rh", Valeur = "ACT" }, // IdExterne du choix
new() { NomChamp = "date_conge_sabbatique", Valeur = "2026-09-01" }
]
};
await syncClient.Sync([], [employe], []);
Via CRUD V1
B2BUpdateEmployeDto.ValeursChampUtilisateur utilise B2BValeurChampUtilisateurItem (structure typée) au lieu du DTO plat :
await employesClient.UpdateEmploye(new B2BUpdateEmployeDto
{
IdExterne = "PERSON001",
// ...autres champs requis
ValeursChampUtilisateur =
[
new() { Nom = "departement", ValeurString = "Finances" },
new() { Nom = "statut_rh", ValeurChoix = "ACT" },
new() { Nom = "date_conge_sabbatique", ValeurDate = new DateTime(2026, 9, 1) },
]
});
Sérialisation des valeurs
| Type de champ | Format de Valeur (V2, string) | Propriété typée (V1 item) |
|---|---|---|
| Texte | "Finances" | ValeurString |
| Date | "2026-09-01" (ISO 8601) | ValeurDate |
| Booléen | "true" / "false" | ValeurBool |
| Choix | "ACT" (IdExterne de l'option) | ValeurChoix |
Valeur null ou absente = valeur non modifiée. Pour retirer une valeur, passez Valeur = "" (chaîne vide).
6. Lire les champs définis
var all = await champUtilisateurClient.GetAllChampUtilisateur();
foreach (var c in all.Value)
{
Console.WriteLine($"{c.Nom} ({c.TypeChampUtilisateurNom}) — requis={c.EstRequis}");
foreach (var choix in c.Choix)
Console.WriteLine($" • {choix.IdExterne}: {choix.Label}");
foreach (var e in c.Employeurs)
Console.WriteLine($" @ {e.IdentifiantExterne} ({e.Nom})");
}
Pour un champ unique :
var field = await champUtilisateurClient.GetChampUtilisateurByNom("departement");
7. Mettre à jour / supprimer
await champUtilisateurClient.UpdateChampUtilisateur("departement",
new B2BEditChampUtilisateurDto
{
Label = "Département d'affectation",
MaxLength = 150,
Ordre = 1,
EstRequis = true,
TexteAide = "Département RH actuel."
});
await champUtilisateurClient.DeleteChampUtilisateur("departement");
Attention : UpdateChampUtilisateur ne change pas le type. Si vous devez migrer (Texte → Choix), créez un nouveau champ, migrez les valeurs par sync, supprimez l'ancien.
Suppression : retire le champ et toutes les valeurs assignées. Irréversible.
8. Cas d'usage typiques
Afficher un onglet RH conditionnel
- Créer les champs :
poste,date_embauche,statut_rh. - Les scoper aux employeurs RH (
SetEmployeurs). - Les assigner par sync quotidien depuis votre SIRH.
- Les lire via
ISignatureClient.SearchSignaturesV2(les instantanés d'adhésion V2 incluentValeursChampUtilisateur).
Formulaire d'adhésion avec options métier
- Champ
formule_cotisationde typeChoixavec{STD, PREMIUM, ETUDIANT}. - Scope aux employeurs éligibles.
- La valeur est capturée lors du formulaire d'adhésion public (côté MCM).
- Lue côté conciliation dans
B2BDemandeAdhesionConciliationItem(pas encore exposé — à confirmer).
Nettoyage périodique
// Supprimer un champ obsolète
await champUtilisateurClient.DeleteChampUtilisateur("ancien_code_poste");
// Migrer ses valeurs vers un nouveau champ via sync
9. Bonnes pratiques
- Nommage :
snake_casecourt et stable. Ne renommez pas (leNomest la clé — pas de rename endpoint). - Requis (
EstRequis) : n'activez qu'après avoir rempli les valeurs existantes, sinon vos syncs rejetteront les employés sans valeur. MaxLength: définissez une borne haute. MCM valide à l'écriture.- Choix : préférez des
IdExternestables (ACT,INA) plutôt que des labels (Actif,Inactif) — vous pourrez renommer le libellé sans casser les données. - Portée : minimiser les champs visibles par employeur. Un employé multi-emplois voit l'union des champs de ses employeurs.
- Pas de hiérarchie : les champs sont plats. Pour des groupes, utilisez une convention de nommage (
rh_departement,rh_poste).
10. Dépannage
| Symptôme | Cause |
|---|---|
ChampUtilisateur.NomDuplique au create | Le Nom existe déjà (rappel : unique par client) |
| Valeur ignorée dans un sync | Le NomChamp ne correspond à aucun champ actif, ou l'employeur de l'employé est hors portée |
| Valeur de type choix rejetée | Valeur contient le label au lieu du IdExterne du choix |
| Impossible de supprimer un champ | Vérifiez qu'il n'est pas référencé par un formulaire actif côté MCM |
Voir aussi
IChampUtilisateurClient- Guide — synchronisation des employés (affectation de valeurs)
- Endpoints HTTP —
ChampsUtilisateurController