Aller au contenu principal

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 (ou B2BUpdateEmployeDto).
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) :

ConstanteGUIDDescription
B2BTypeChampUtilisateur.Texte...004Texte libre (MaxLength configurable)
B2BTypeChampUtilisateur.Date...002Saisie de date
B2BTypeChampUtilisateur.Booleen...003Case à cocher (oui/non)
B2BTypeChampUtilisateur.Choix...001Liste 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 : appelez GetChampUtilisateurByNom ; la liste Employeurs reflè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 champFormat 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 (TexteChoix), 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

  1. Créer les champs : poste, date_embauche, statut_rh.
  2. Les scoper aux employeurs RH (SetEmployeurs).
  3. Les assigner par sync quotidien depuis votre SIRH.
  4. Les lire via ISignatureClient.SearchSignaturesV2 (les instantanés d'adhésion V2 incluent ValeursChampUtilisateur).

Formulaire d'adhésion avec options métier

  1. Champ formule_cotisation de type Choix avec {STD, PREMIUM, ETUDIANT}.
  2. Scope aux employeurs éligibles.
  3. La valeur est capturée lors du formulaire d'adhésion public (côté MCM).
  4. 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_case court et stable. Ne renommez pas (le Nom est 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 IdExterne stables (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ômeCause
ChampUtilisateur.NomDuplique au createLe Nom existe déjà (rappel : unique par client)
Valeur ignorée dans un syncLe NomChamp ne correspond à aucun champ actif, ou l'employeur de l'employé est hors portée
Valeur de type choix rejetéeValeur contient le label au lieu du IdExterne du choix
Impossible de supprimer un champVérifiez qu'il n'est pas référencé par un formulaire actif côté MCM

Voir aussi