Apparence
Fiche salarié
La fiche d'un salarié (/utilisateurs/<id>/<volet>) : un bandeau de résumé, un rail de six volets, et trois politiques d'écriture différentes selon le volet et le rôle.
Prérequis communs : make seed-establishments, make seed-workforce, make seed-counters.
Les trois profils à faire jouer
Le point de la fiche n'est pas ce qu'elle affiche, c'est qui peut y écrire. Trois profils suffisent à couvrir les trois politiques :
| Profil | Exemple | Écrit sur |
|---|---|---|
RH / Admin (is_staff) | i.aubert | tout |
Encadrant (Manager n1, pas is_staff) | Léa Martins | Urgence et Lieux de travail & équipes seulement |
Lecteur (Service Paie) | — | rien |
L'encadrant est le cas qui compte : il n'est pas is_staff et écrit tout de même deux volets. Une régression qui rabattrait ces droits sur is_staff passerait inaperçue avec les deux autres profils.
1. Lire le bandeau de résumé
Tickets : APAJH-208 · Rôle : RH / Admin · Prérequis : make seed-counters
Ouvrez la fiche d'un salarié.
✅ Résultat attendu : le bandeau porte le nom, la fonction et l'établissement (Aide-soignant · FAM Les Cigales), le contrat et l'ETP (CDI · 100 %), puis trois chiffres : l'ancienneté en années, le solde de congés (15,5 j) et le solde d'annualisation (+12 h).
Repérez un salarié dont le solde d'annualisation dépasse 5 heures sans atteindre 30.
✅ Résultat attendu : la mention Alerte compteur apparaît. En deçà de 5 h, elle n'apparaît pas.
Couverture automatique : e2e/fiche-salarie.spec.ts → « le bandeau résume le salarié et ses trois chiffres ».
2. Naviguer entre les volets
Tickets : APAJH-208 · Rôle : n'importe quel rôle d'encadrement · Prérequis : make seed-workforce
Critères d'acceptation du ticket
- « Étant donné une fiche salarié, quand consultée, alors elle est organisée en onglets. »
Ouvrez une fiche et regardez le rail.
✅ Résultat attendu : la fiche est découpée en six onglets — Informations, Contrat, Famille & social, Urgence, Lieux de travail & équipes, Compteurs — et non en une page continue.
Depuis Informations, cliquez sur Contrat dans le rail.
✅ Résultat attendu : l'adresse devient
/utilisateurs/<id>/contratet le volet Contrat s'affiche.Passez sur Compteurs, puis utilisez le bouton Précédent du navigateur.
✅ Résultat attendu : vous revenez sur Contrat. Les volets sont des adresses, pas un état interne.
Couverture automatique : e2e/fiche-salarie.spec.ts → « le rail ouvre chaque volet par son adresse ». Voir aussi Portail § 6.
3. Vérifier ce qui est verrouillé dans Informations et Contrat
Tickets : APAJH-208 · Rôle : RH / Admin, puis Encadrant · Prérequis : make seed-workforce
En RH, ouvrez Informations.
✅ Résultat attendu : les champs qui viennent de la paie — dont le nom — sont en lecture seule. Nationalité est modifiable. Le bouton Enregistrer est présent.
Ouvrez Contrat.
✅ Résultat attendu : Type de contrat et Qualification sont renseignés ; Ancienneté, Date d'entrée et Nombre d'heures mensuelles (
151,67 h) sont en lecture seule — ce sont des valeurs calculées, jamais saisies.Décochez Non annualisé.
✅ Résultat attendu : le champ Dimanches & jours fériés prévisionnels disparaît. Un contrat annualisé porte déjà ces jours dans son calendrier ; la prévision n'a plus d'objet.
Rouvrez les deux volets avec le profil Encadrant.
✅ Résultat attendu : les mêmes valeurs sont visibles, tous les champs sont en lecture seule, les cases à cocher sont désactivées, et il n'y a pas de bouton Enregistrer.
Couverture automatique : e2e/fiche-salarie.spec.ts → « les champs de la paie sont en lecture seule, le reste est éditable par RH », « un rôle manager lit la fiche sans pouvoir l'enregistrer », « affiche les trois blocs, cadenas compris », « les dimanches ne sont demandés que sur un contrat non annualisé » et « un rôle manager voit le contrat sans pouvoir le modifier ».
4. Vérifier le masquage des données des enfants
Tickets : APAJH-208 · Rôle : Encadrant, puis RH / Admin · Prérequis : un salarié avec au moins un enfant à charge
Critères d'acceptation du ticket
- « Étant donné les droits liés aux enfants, quand affichés, alors seuls nombre et âge apparaissent par défaut. »
Avec le profil Encadrant, ouvrez Famille & social.
✅ Résultat attendu : l'enfant n'expose que son âge. Ni date de naissance, ni mention Situation de handicap.
Affichez le code source de la page et cherchez la date de naissance de l'enfant.
✅ Résultat attendu : elle est absente de la page entière, pas seulement masquée à l'écran. C'est l'API qui retire les champs avant de répondre.
Rouvrez le volet en RH / Admin.
✅ Résultat attendu : Date de naissance et Âge sont renseignés, le commutateur Handicap reflète la situation, et le volet est enregistrable.
Couverture automatique : e2e/fiche-salarie.spec.ts → « par défaut, un enfant n'expose que son âge » et « RH voit le détail et peut l'éditer ». Côté serveur, le masquage est couvert par backend/tests/test_employee.py.
5. Vérifier les deux volets qu'un encadrant peut écrire
Tickets : APAJH-208, APAJH-177 · Rôle : Encadrant, puis Lecteur · Prérequis : make seed-workforce
Critères d'acceptation du ticket (APAJH-177)
- « Un professionnel peut être rattaché à l'organisation du chef de service technique indépendamment de son établissement principal. »
Avec le profil Encadrant, ouvrez Urgence.
✅ Résultat attendu : Nom & prénom de la personne à prévenir est modifiable et Enregistrer est présent — bien que ce profil ne soit pas
is_staff.Ouvrez Lieux de travail & équipes.
✅ Résultat attendu : les équipes du salarié sont modifiables et enregistrables. Deux champs restent en lecture seule, et ils disent deux choses différentes : Établissement de paie (avec un cadenas) vient du contrat de référence, et Lieu de travail principal est porté par la fiche — il se saisit à la création ou en back-office.
Affectez le salarié à une équipe qui appartient à un autre établissement que son lieu de travail principal, puis enregistrez.
✅ Résultat attendu : l'affectation est acceptée. Lieu de travail principal n'a pas changé pour autant : les deux axes sont indépendants et ont le droit de diverger. C'est ce qui permet de rattacher un professionnel à l'organisation d'un chef de service technique sans toucher à son lieu de travail principal.
Rejouez les deux volets avec le profil Lecteur.
✅ Résultat attendu : les mêmes informations sont visibles ; les champs sont en lecture seule, les équipes s'affichent comme de simples étiquettes sans croix de retrait, et il n'y a pas de bouton Enregistrer.
Couverture automatique : e2e/fiche-salarie.spec.ts → les quatre tests du groupe « fiche salarié — Urgence et Lieux de travail ». L'étape 3 n'est couverte par aucun test end-to-end : la spec vérifie qu'un encadrant peut modifier les équipes, pas qu'une équipe d'un autre établissement est acceptée. C'est donc le critère d'APAJH-177 qui reste entièrement à la main. Côté serveur, le modèle DivisionAssignment porte la règle et backend/tests/test_employee.py la couvre.
6. Vérifier les compteurs et le verrouillage des années
Tickets : APAJH-208 · Rôle : RH / Admin, puis Encadrant · Prérequis : make seed-counters
En RH, ouvrez Compteurs.
✅ Résultat attendu : Congés annuels et Compte épargne-temps s'affichent, et le bouton Éditer est présent.
Cliquez sur Éditer, puis essayez de changer d'année.
✅ Résultat attendu : les onglets d'année sont désactivés tant que l'édition est ouverte. Changer d'année jetterait la saisie en cours sans prévenir.
Rouvrez le volet en Encadrant.
✅ Résultat attendu : les mêmes figures sont lisibles, sans bouton Éditer ni Enregistrer.
Couverture automatique : e2e/fiche-salarie.spec.ts → « les figures sont lisibles par tous, éditables par le seul staff » et « un rôle manager voit les compteurs sans bouton Éditer ».
7. Consulter et éditer la fiche sur téléphone
Tickets : APAJH-208 · Rôle : RH / Admin · Prérequis : make seed-workforce
En 390 × 844, ouvrez le volet Contrat.
✅ Résultat attendu : le rail des volets passe au-dessus du volet au lieu d'être à sa gauche, et la page ne défile pas horizontalement.
Faites défiler jusqu'au bas du volet.
✅ Résultat attendu : les champs restent éditables et la barre d'actions (Enregistrer) reste atteignable.
Couverture automatique : e2e/fiche-salarie.spec.ts → « le rail passe au-dessus du volet et la page ne déborde pas » et « le volet reste éditable et sa barre d'actions atteignable ».
8. Rattacher un salarié provisoire à son matricule paie
Tickets : APAJH-205 · Rôle : RH / Admin · Prérequis : un salarié créé sans matricule — voir Annuaire Utilisateurs § 7.
Critères d'acceptation du ticket
- Étant donné ce compte, quand le matricule paye devient disponible, alors il y est rattaché.
Ouvrez la fiche du salarié créé sans matricule.
✅ Résultat attendu : le bandeau porte le badge rouge Non synchronisée paie.
Dans le volet Informations, bloc Identité, saisissez le Matricule communiqué par la paie, puis Enregistrer.
✅ Résultat attendu : le badge Non synchronisée paie disparaît du bandeau, et la pastille Provisoire disparaît de la ligne du salarié dans l'annuaire.
Ouvrez la fiche d'un intérimaire.
✅ Résultat attendu : le champ Matricule est en lecture seule, avec l'aide « Sans objet : un intérimaire n'entre pas dans la paie. » Le bandeau porte Intérim et jamais Non synchronisée paie.
Couverture automatique : e2e/fiche-salarie.spec.ts → « sans matricule paie, le bandeau porte « Non synchronisée paie » », « avec son matricule, la fiche ne porte aucun marqueur provisoire » et « un intérimaire sans matricule porte « Intérim », pas « Non synchronisée paie » ». L'étape 2 n'est couverte par aucun test end-to-end : les specs tournent sans backend, donc la disparition des marqueurs après enregistrement reste à jouer à la main. Côté serveur, backend/tests/test_employee.py couvre la saisie du matricule par PATCH.
9. Enregistrer une attestation d'honorabilité
Tickets : APAJH-201 · Rôle : RH / Admin · Prérequis : un salarié dont la date de naissance est vide — c'est ce champ vide qui déclenchait le refus.
Critères d'acceptation du ticket
- Étant donné une attestation d'honorabilité, quand ses dates et son justificatif sont enregistrés, alors ils sont conservés sans erreur de format de date.
Volet Informations, bloc Attestation d'honorabilité : basculez le commutateur sur Oui, saisissez une Date de remise et une Date de renouvellement, joignez un PDF, puis Enregistrer.
✅ Résultat attendu : « Fiche enregistrée. » Les deux dates et le nom du fichier sont toujours là après rechargement de la page. En particulier, aucun message « La date n'a pas le bon format » — ce refus venait de la date de naissance vide, réencodée en
""parce que l'envoi partait en JSON au lieu de multipart.Cliquez sur la croix du justificatif, puis Enregistrer.
✅ Résultat attendu : « Aucun justificatif ». Les deux dates sont conservées.
Rebasculez le commutateur sur Non, puis Enregistrer.
✅ Résultat attendu : les deux dates et le justificatif sont effacés — la réponse « Non » est une suppression, pas un simple masquage.
Couverture automatique : e2e/fiche-salarie.spec.ts → « le justificatif d'honorabilité part bien en multipart » affirme le format d'envoi et le contenu du corps, qui est là où le bug se logeait. Côté serveur, backend/tests/test_employee.py couvre l'envoi du fichier, l'effacement d'une date et le détachement du justificatif par null. Les étapes 1 à 3 restent à jouer à la main de bout en bout : les specs tournent sans backend, donc la persistance après rechargement n'est pas vérifiable automatiquement.
10. Retrouver l'auteur d'une modification de fiche
Tickets : APAJH-189 · Rôle : RH / auditeur · Prérequis : un compte RH autorisé à modifier une fiche et un compte équipe portant la permission audit.view_actionlog
Critères d'acceptation du ticket
- Une écriture faite depuis l'application laisse une trace nominative unique.
- La trace désigne l'objet modifié et montre les valeurs avant et après.
Connectez-vous à l'application avec le compte RH, ouvrez une fiche salarié et modifiez son Adresse, puis cliquez sur Enregistrer.
✅ Résultat attendu : la fiche confirme son enregistrement et affiche la nouvelle adresse.
Connectez-vous au back-office avec le compte auditeur et ouvrez Audit ▸ Journal des actions.
Filtrez sur l'action Modification, le type d'objet salarié et le compte RH utilisé à l'étape 1, puis ouvrez la ligne la plus récente.
✅ Résultat attendu : une seule ligne désigne le salarié modifié, affiche l'identité figée du compte RH et montre l'ancienne et la nouvelle adresse.
Couverture automatique : backend/tests/test_audit.py vérifie la ligne unique, l'acteur, l'objet ciblé et le diff. Le passage visuel entre l'application et le back-office reste à rejouer manuellement.
11. Vérifier les données d'un contrat importé depuis CEGI
Tickets : APAJH-234 · Rôle : RH / Admin · Prérequis : un export CEGI « Personnes Contrats » déposé et traité avec succès
Critères d'acceptation du ticket
- Un fichier déposé est intégré sans action manuelle dans un délai de 15 minutes.
- Un fichier déjà traité n'est pas réimporté.
- Un fichier malformé est rejeté et ne bloque pas les fichiers suivants.
Dans le back-office, ouvrez Imports de données ▸ Lots d'import et repérez le fichier déposé.
✅ Résultat attendu : le lot est Réussi, avec une tentative et un résultat par ligne. Le total des créations, mises à jour et lignes inchangées correspond au nombre de lignes.
Ouvrez dans l'application la fiche d'un salarié de cet export, volet Contrat.
✅ Résultat attendu : le type, la qualification, les dates et le nombre d'heures mensuelles correspondent au fichier. Quand
cont_hmesvaut zéro, les heures mensuelles sont calculées à partir decont_hheb.Redéposez le même contenu sous un autre nom, puis attendez le passage suivant.
✅ Résultat attendu : aucun deuxième salarié ni contrat n'est créé. Un seul lot existe pour cette empreinte.
Déposez un fichier dont une adresse email est malformée, puis un fichier valide.
✅ Résultat attendu : le premier lot est Rejeté, avec la ligne et la colonne en erreur ; le second est Réussi.
Couverture automatique : backend/tests/test_data_imports.py couvre le parsing UTF-8/Windows-1252, les mappings, l'atomicité, l'idempotence, la poursuite après rejet, la reprise et les durées de conservation. L'étape 2 reste à jouer avec un export réel pour confronter l'affichage au fichier source.
Points d'attention
- Un matricule doit être unique. Le réutiliser sur une autre fiche est refusé avec un message lisible, à la création comme à la modification.
- Aucune règle serveur n'interdit un matricule sur la fiche d'un intérimaire, et c'est volontaire : le matricule appartient à la personne. Un intérimaire embauché ensuite en CDI garde sa fiche et reçoit alors un matricule. C'est le champ en lecture seule qui porte la règle, pas une contrainte qui bloquerait l'embauche.
- Les tests end-to-end tournent sans backend : ils prouvent que l'interface respecte les droits que l'API lui annonce, pas que l'API les applique. Les deux volets d'un même contrôle sont à vérifier — la partie serveur a ses propres tests (
backend/tests/test_employee.py,backend/tests/test_roles.py). - Le volet Diplômes & formations existe dans les maquettes mais n'est pas livré : son absence du rail est normale.
- L'ancienneté, la date d'entrée et le nombre d'heures mensuelles sont calculés. Un écart sur ces valeurs se corrige en amont — sur les contrats — jamais sur la fiche.