# Rapport de test complet — anomalies et points illogiques

Document tenu à jour pendant la campagne de test (données : classes `TEST-DI-1A` id 44 et `TEST-DI-2A` id 43, année 2026-2027, scripts dans `backend/database/scenario/`).
Légende : ✅ corrigé · ⚠️ à décider / à vérifier · 🔎 constaté, non bloquant.

## 1. Balayages automatiques

| Contrôle | Résultat |
|---|---|
| Suite PHPUnit complète | 399 tests ; 3 échecs initiaux (fichiers de déclencheurs d'audit non régénérés pour les nouvelles tables, test de synchronisation d'audit, nom d'école « SUP MTI » écrit en dur dans `ImpressionEdt.tsx`) → ✅ corrigés, les 3 tests passent |
| Balayage des 328 routes GET de l'API avec le super admin | aucune erreur 5xx ; 404/422 uniquement quand un paramètre obligatoire manque (attendu) |
| Balayage navigateur de ~90 pages (menus + 53 écrans de paramétrage) | aucune erreur API ni exception JS, sauf : avertissement React « deux enfants avec la même clé » sur `/crm` (page supprimée) et `/preinscriptions/nouvelle` (⚠️ en cours) |

## 2. Anomalies corrigées pendant la campagne

1. ✅ **Décision « Non admis » trompeuse** : un semestre dont une matière (stage) n'a aucune note était déclaré non admis (« note éliminatoire » inexistante) avec une moyenne provisoire. Désormais : pas de moyenne, pas de décision (« En attente »), message « Semestre en cours ».
2. ✅ **Règle de calcul des notes unifiée** (client) : épreuve créée avec notes saisies = 0 pour l'étudiant sans note ; composante sans épreuve créée ou sans note saisie = pas de moyenne (matière, unité, semestre, année, relevé, PV). Trois moteurs de calcul (SQL historique, `CalculResultats`, `CalculUnites`) alignés.
3. ✅ **Relevés** : les moyennes pondérées et la décision s'affichaient alors que des unités n'avaient pas de note → plus de moyenne tant que l'année n'est pas complète.
4. ✅ **Colonne « Rattrapage »** : supprimée des pages de résultats (fiche étudiant, espace étudiant, espace parent) ; remplacée par CC / EFCF théorique / EFCF pratique / moyenne (pas de rattrapage dans le Professionnel).
5. ✅ **Erreur « Cannot use object of type stdClass as array »** sur la liste des relevés (régression introduite par le contrôle de moyenne) corrigée.
6. ✅ **PV Excel** : mise en forme du modèle du centre (en-tête et pied gris, filets noirs, colonnes et lignes spacieuses, volets figés, impression A4 ajustée avec en-têtes répétés, nombres à 2 décimales, titre/filière/année positionnés comme le modèle).
7. ✅ **Fichiers de déclencheurs d'audit** régénérés (`php artisan audit:exporter-declencheurs`) : les nouvelles tables (dépenses, recettes, jours de stage…) sont désormais couvertes.
8. ✅ **Nom d'école codé en dur** (`SUP MTI`) retiré de l'impression des emplois du temps.
9. ✅ **Cours en ligne → « Ressources et devoirs »** : l'administration peut maintenant ajouter/modifier/supprimer chapitres, ressources (fichier, lien, vidéo) et devoirs, publier, corriger (mêmes écrans que l'espace enseignant, droit `ressources.gerer`).
10. ✅ **CRM** retiré du menu, de la palette et des routes (`/crm` redirige vers Candidats).

## 3. Points illogiques ou à décider (à traiter avec le client)

- ⚠️ **Classes importées de l'ancien système** : relancer le recalcul des résultats change les valeurs importées (les épreuves non encore saisies et les doublons d'épreuves sans note diluaient les moyennes ; la nouvelle règle les ignore). Exemple : « Logiciels d'application : Word » passe de 13,56 à 19,63 pour DRIOUCH Hiba parce qu'une épreuve en double sans aucune note divisait par deux. → décider si l'on supprime les épreuves en double sans note.
- ⚠️ **Résultats « 0 » persistants** dans les PV Excel de classes importées (ex. unité annuelle « Installation d'un poste informatique ») : lignes `n_resultat_uf` / `n_resultat_emo` anciennes à 0 ; un recalcul de la classe les remet à vide.
- ⚠️ **Rattrapage encore présent dans le code** (non affiché dans les nouvelles pages) : saisie des notes enseignant (`MesNotes.tsx`, épreuves de type RAT), calcul `CalculResultats` (rattrapage plafonné), séances de rattrapage d'absences d'enseignants (autre notion : cours rattrapé, à conserver). À retirer complètement si le client confirme « pas de rattrapage ».
- ⚠️ **Compte `finance@supmti.test` et autres comptes de démonstration** absents de la base remplacée par le collègue : seuls `pedagogie@supmti.test` et les comptes créés pour le test (`superadmin@`, `multi@polysco.test`) existent.
- 🔎 Les coordonnées de l'établissement (n° d'autorisation, téléphone) affichent des valeurs de démonstration (« À COMPLÉTER ») : à renseigner dans la fiche établissement avant impression officielle.
- 🔎 Président du jury des relevés récapitulatifs : à saisir dans le paramètre `releve_president_jury`.


## 4. Pédagogie et planning (agent « pédagogie », classes TEST-DI-1A / TEST-DI-2A)

Données créées : 8 enseignants (comptes, contrats, taux horaires) affectés aux 31 matières des deux classes ; calendriers validés (session 1 complétée, session 2 créée) avec rentrée, vacances, examens, Ramadan, soutenances, délibérations, stage en alternance 2 j école / 3 j stage (2A), stage en bloc du 01/02 au 12/03/2027 (1A) ; 14 jours fériés ; 6 emplois du temps publiés (jour et soir) ≈ 700 séances ; 27 séances passées avec appel ; 5 absences d'enseignants ; 12 examens d'unité (EFCFT / EFCFP) avec salles, responsables et surveillants ; compte `enseignant@polysco.test` affecté à 11 matières, 11 séances passées, 247 à venir, 5 surveillances.
≈ 400 contrôles par endpoint (enseignants, calendriers, emplois du temps, séances, absences, examens, cahier de texte, ressources, devoirs, annonces).

Anomalies corrigées :
1. ✅ `UniteFormationController::updateElement` : erreur 500 sur les éléments sans module technique (`emo_mod_id` NULL, éléments copiés / importés).
2. ✅ `EmploisDuTemps::colonnes()` : un créneau ajouté à un emploi du temps déjà publié ne générait aucune séance (`uet_est_actif` NULL) ; séances régénérées pour 3 créneaux, test de non-régression ajouté (`PlanningTest`).
3. ✅ `Seances::exceptionnelle` : erreur 500 pour tout examen sur une unité annuelle (pas de semestre) → semestre déduit de la date par le calendrier validé.
4. ✅ `Seances` / `Examens` : responsable d'un examen d'unité exigé sur l'élément principal → il suffit qu'il enseigne un élément de l'unité.
5. ✅ `ExamenController` : `emo_id` n'est plus exigé à la modification d'un examen d'unité (422 injustifié).
6. ✅ `CalendrierService::dupliquer` : la duplication perdait les jours de stage en alternance et les classes des périodes de stage.
7. ✅ `Audience::classesEnseignant` : un enseignant dont la matière était reprise par affectation ne pouvait pas publier d'annonce à sa classe.
8. ✅ Migration `2026_10_27_100000_desactiver_periode_rattrapages` : type de période « Rattrapages » retiré du calendrier (règle « pas de rattrapage »).

Restant :
- ⚠️ `/planning/salles/occupation` ne vérifie pas le périmètre du centre (mineur).
- ⚠️ Aucune unité à exactement 2 éléments dans le programme des classes de test : le cas « unité à deux éléments » (emploi du temps + examen d'unité + notes) n'est pas couvert par ces données.
- 🔎 Un examen dont l'épreuve a des notes ne peut pas être supprimé (règle PX8, voulu) : seule l'annulation est possible.
- 🔎 Le test PHPUnit ajouté (`PlanningTest`) n'a pas pu être exécuté pendant la campagne (base de test partagée, deadlock de `migrate:fresh`) → à relancer une fois les agents terminés.


## 5. Candidats, scolarité, stages, vie étudiante, communication, parents, RH, administration

Données créées (via les vrais contrôleurs) : 10 candidats à tous les stades (2 admis jusqu'à l'inscription), 12 demandes + 3 depuis le portail, 6 mises à niveau, 6 PV d'acceptation, 14 photos ; 4 entreprises, 5 offres, 6 candidatures, **9 stages** (alternance avec jours pointés, convention, stage évalué avec attestation, PFA, annulé, refusé) et 2 soutenances ; 8 incidents disciplinaires, 4 sanctions, 1 conseil, 1 campagne d'évaluation ; 7 annonces, 6 conversations (4 onglets de destinataires) ; 7 comptes parents ; RH : services, postes, employés, contrats, congés, documents, attestations. ≈ 250 appels testés, permissions par rôle et cloisonnement par centre vérifiés.

Anomalies corrigées :
1. ✅ **Bloquant** : la nationalité « Marocaine » n'avait aucun pays rattaché (`nat_pays_id` vide sur les 194 nationalités) → tout candidat marocain était traité comme étranger (passeport au lieu du CIN, mauvaises pièces, mauvais frais). Migration `2026_10_09_000100_lier_nationalites_aux_pays` + repli sur le libellé dans `PreinscriptionRules.php`.
2. ✅ Erreur 500 « Undefined array key lignes » sur la simulation de frais d'un candidat (`DossierCandidatController::simulerFrais`).
3. ✅ Fuite entre centres : `/rh/organisation` montrait les postes d'autres centres (`OrganisationController`).
4. ✅ Clé React dupliquée dans le fil d'Ariane (`Coquille.tsx`) à l'origine de l'avertissement sur `/crm` et `/preinscriptions/nouvelle`.
5. ✅ `config/audit.php` : libellés de `n_stage_jours` et `n_types_demandes`.

Restant / à décider :
- ⚠️ **Couverture d'audit** : les tables `n_seance_surveillants`, `n_examens_publications`, `n_depenses`, `n_depense_familles`, `n_autres_recettes`, `n_num_diplomes`, `n_avancement_commentaires`, `n_calendrier_periode_classes`, `n_domaines_uf`, `n_sequences_pedagogiques` sont « non classées » ; `n_sequences` signale des écritures SQL brutes (à traiter avec le collègue qui gère l'audit).
- ⚠️ **Grille tarifaire vide** pour les classes de test (formation TS-DI, année 2026-2027) : la proposition de frais du CRM est vide (frais saisis à la main).
- ⚠️ Le directeur `multi@polysco.test` n'a pas accès aux réinscriptions ni aux mises à niveau : à confirmer côté client (permissions du rôle DIRECTEUR).
- ⚠️ Les stages créés par l'administration démarrent directement au statut « Validé » : le bouton « Valider » n'a d'effet que pour les demandes d'étudiants (peu lisible).
- ⚠️ La diffusion à une classe (annonce / message) est réservée aux enseignants de la classe : le personnel d'administration ne peut pas la déclencher (le super admin reçoit un 403).
- 🔎 Le PV de soutenance ne peut être saisi qu'à partir du jour de la soutenance (règle) ; les soutenances de test sont en 2027.
- 🔎 Pas de route « clubs et événements étudiants » : seules la discipline et l'évaluation des enseignements existent dans la vie étudiante.
- 🔎 Le test ajouté `CrmInscriptionsTest::test_nationalite_marocaine_sans_pays_rattache` n'a pas pu être exécuté pendant la campagne (base de test partagée) → à relancer.


## 6. Finance

Données créées : 2 caisses (SITE1, SOIR) avec caissiers et 2 comptes bancaires ; **28 encaissements** numérotés (espèces, chèque, chèque différé, virement, TPE, mixte ; complets, partiels avec centimes ; 18 valides, 7 provisoires, 1 chèque impayé, 2 annulés) ; bordereau de remise, chèques impayés, remboursements (payé, refusé, en attente) ; 2 dossiers de recouvrement avec relances ; 13 dépenses (plusieurs familles) et 4 autres recettes ; mois offert, réductions, bourse, changement de périodicité ; plan de paiement créé / modifié / dupliqué ; versement en banque et 4 clôtures de caisse (dont une avec écart justifié) ; **4 vacations d'octobre 2026** générées depuis 25 séances (2 payées, 1 partielle, 1 à valider) → 3 dépenses automatiques (400, 900 et 510 MAD). Montants en centimes, numéros de reçus, totaux de la synthèse « Recettes et dépenses », données d'impression des reçus et bordereaux, permissions et cloisonnement par centre : cohérents.

Anomalies corrigées :
1. ✅ **Échéanciers à 13 × 999,99 + 1 000,13 au lieu de 14 × 1 000,00** : cause du « échu 999,99 » vu dans le Suivi des diplômes (parts de plan stockées à 4 décimales, 7,1428 %, appliquées à la lettre). `CalculFrais::calculer` traite désormais des parts quasi égales comme égales ; échéanciers existants sans paiement remis d'équerre (14 frais). Effet voulu : 35 000 MAD sur 17 mois → 2 058,82 (arrondi correct) ; test `PlansPaiementTest` adapté + nouveau test 14 000 / 14.
2. ✅ Message trompeur : payer une part d'une vacation déjà soldée répondait « doit être validée » → « déjà entièrement payée » (`Vacations::payer`).

Restant / à décider :
- ⚠️ **4 frais de TS-GE-2A-TEST (classe 42) gardent des échéances à 999,99** : paiements déjà imputés, non modifiés (3 soldés, 1 partiellement payé sans échu aujourd'hui).
- ⚠️ **Doublons de numéros de reçu (`rec_seq`) parmi les reçus importés** de l'ancien système (hors scénario).
- ⚠️ Il n'existe pas de fonction « ouverture de caisse » : elle revient à rattacher un caissier à une caisse.
- 🔎 Le jeton anti-double-soumission des encaissements n'est pas testable via `api()` (le cache est vidé à chaque appel) ; une double soumission a créé 2 reçus (doublon annulé).
- 🔎 Données d'établissement de test : ICE `000000000000001`, adresse « À compléter ».
- 🔎 Incident du test : le plan de test n°3 a été supprimé par erreur puis recréé à l'identique (même id, 10 échéances de 10 %).
- 🔎 Tests PHPUnit finance non relancés après modifications (base de test partagée) : `php vendor/bin/phpunit --filter PlansPaiementTest` à relancer.


## 7. Notes, délibérations, PV, relevés, diplômes, lauréats

Données créées : épreuves et notes (3 CC = 10+10+10, EFCFT 20, EFCFP 30 par matière) pour TEST-DI-1A (unité annuelle, S1, S2) et TEST-DI-2A (unités annuelles, S3, S4), étudiants du soir compris ; 1re année des 12 étudiants de la 2A dans TS-DI-1A 2025-2026 (moyenne des deux années) ; NSTI de la 2A (9 critères) ; cas couverts : CC non noté (0), absents, EFCFP non créé (S2 de la 1A sans moyenne), EFCFT créé sans note, unité sans note (stage), examen d'unité EFCFP, **unité à exactement 2 éléments (unité 223 : éléments 354 et 355, examen d'unité EFCFT/EFCFP)**, ajournés, mentions Passable → Très Bien ; délibérations (2A S3 : faite, confirmée, rouverte avec motif, reconfirmée, publiée ; 2A S4 confirmée et publiée ; 1A S1 confirmée puis rouverte ; 1A S2 planifiée), points de jury posés / retirés / refusés sur délibération confirmée ; **88 PV** (17 types, Excel et PDF) valides ; **360 impressions de relevés** (3 types, année et semestres, relevés de classe) sans échec ; diplômes : 9 lauréats numérotés, 7 relevés livrés, 5 diplômes remis (dont un refus 409 pour solde dû puis remise avec confirmation d'impayé), 5 situations d'insertion.
Recalcul indépendant depuis les notes brutes : **0 écart** sur élément, unité, semestre et année ; moyennes des deux années, NSTI, moyenne finale, mention et décision conformes aux formules pour les 12 étudiants de la 2A.

Anomalies corrigées :
1. ✅ `CalculUnites` : erreur 500 de clé étrangère (`ri_sem_id = 0`) pour une classe avec unités annuelles ; un EFCF manquant sur un seul élément d'une unité donnait quand même une note d'unité (désormais absente) ; la moyenne annuelle était calculée avec une unité incomplète (désormais vide) ; **les points de jury ne comptaient pas dans les moyennes** (ils comptent maintenant).
2. ✅ `CalculResultatsProfessionnel` : résultat de diplôme (moyenne finale, décision) non calculé si une année est incomplète ; points de jury pris en compte dans `rn_moyenne_finale`, y compris sur un élément sans note propre.
3. ✅ `CalculResultats::classe()` et `apresChangement()` délèguent au calcul Professionnel : **ouvrir la fiche d'une délibération ou poser des points de jury écrasait les résultats avec l'ancien calcul** (le S3 repassait à vide).
4. ✅ `Deliberations` : préalables réécrits (composantes CC / EFCFT / EFCFP non créées ou sans note, notes manquantes = 0 : plus de faux « poids ≠ 100 % » ni « notes non remises ») ; grille de délibération par unité (`n_resultat_uf`), liste « en attente » corrigée, plus de « modules ».
5. ✅ Front : `notes/donnees.ts` et `ResultatsDeliberation.tsx` affichent la note d'unité renvoyée par le serveur.

Restant / à décider :
- ⚠️ PV « Liste des lauréats » : la colonne « Numéro Lauréat » reprend le numéro d'inscription, pas le numéro de diplôme.
- ⚠️ La liste des diplômes ne demande pas de délibération finale confirmée, alors que l'insertion professionnelle l'exige (règles différentes entre les deux modules).
- ⚠️ `n_resultats_admissions.ra_decision` vaut « Ajourné » par défaut (colonne NOT NULL), y compris quand le résultat est seulement incomplet.
- ⚠️ Les notes de 1re année ajoutées pour les 12 étudiants de la 2A rendent calculables les S2 des autres étudiants de TS-DI-1A 2025-2026, avec des zéros là où rien n'était saisi.
- 🔎 Des examens d'unité vides (coefficient nul) sont créés par le planning des examens ; ignorés sans note, mais ils forcent le calcul par unités.
- 🔎 L'unité 222 contient l'élément TI (coefficient d'unité 12 contre 11 pour la somme des éléments hors TI).
- 🔎 Non testé : espace étudiant « mes notes / évaluations » (balayage navigateur ci-dessous) ; aucun test PHPUnit ajouté pour ce domaine.

*(Ce document est complété au fil des tests ; voir les sections suivantes.)*

## 8. Unités de formation fusionnées dans les classes de test (corrigé)

- **Symptôme** : page « Mes résultats » de l'étudiant, « Métier et formation » affiché deux fois (en-tête d'unité + première matière).
- **Cause** : `UnitesFormation::copierClasse` regroupait toutes les matières d'un même semestre dans une seule unité (19 unités réduites à 3-4 dans TEST-DI-1A / 2A). L'en-tête d'unité reprend le nom de sa matière principale, d'où le doublon.
- **Correction** : code corrigé ; données réparées par `database/scenario/09_corriger_unites.php` (une unité par matière, examens d'unité convertis en examens par matière, résultats recalculés, délibérations confirmées rétablies). L'unité 223 (2 éléments) reste volontairement.
- **Point restant** : le doublon visuel existe pour toute unité dont le nom est identique à celui de sa matière unique ; l'affichage pourrait masquer l'en-tête dans ce cas.
