Aller au contenu

Rapprochement des dates de session OGDPC

Version métier : voir Rapprochement des dates de session OGDPC.

Commande qui compare les dates extraites du portail OGDPC (CSV déposé par Extraction des sessions OGDPC) aux SessionDate en base Doctrine, applique les correctifs nécessaires (dates de début/fin, pivot lmsStartDate, horaires des VirtualClassModule), puis délègue à Gemini un contrôle sémantique de l’ordre des 4 dates selon le type de programme (FC, VC, EPP, IP).

Un rapport CSV détaillé (dpc-extract/reports/session-date-reconcile_<timestamp>.csv + alias …_latest.csv) est uploadé sur MinIO après chaque exécution.

Planification GitLab (via pipeline_schedules API, 2026-04-23) :

  • Description : Reconcile session dates against ANDPC
  • ID du schedule : 4217183
  • Cron : 30 2 * * * (fuseau : Europe/Paris) — 02:30 Paris, 1h30 après l’extraction pour laisser le CSV arriver sur MinIO.
  • Branche : refs/heads/master
  • État : actif (dernier run 2026-04-23 → failed)
  • Variable injectée : SCHEDULE_TYPE=ogdpc_reconcile_session_dates

TODO(review) : le dernier run (pipeline 2473166202) est en échec. Remonter dans Sentry les erreurs applicatives correspondantes et corriger.

Job CI : ogdpc_reconcile_session_dates dans ci-jobs/.scheduled-ci.yml (stage ogdpc_extract).

Commande exécutée :

Fenêtre de terminal
docker exec $APP_NAME php bin/console scheduled:ogdpc-reconcile-session-dates

Options (utilisables en manuel) :

  • --bucket=<name> (défaut erevo-lms)
  • --csv-key=<key> (défaut dpc-extract/ogdpc_sessions_latest.csv)
  • --local-csv=/path.csv — court-circuite MinIO
  • --no-report-upload — n’upload pas le rapport CSV
  1. Charger le CSV : --local-csv sinon GetObject MinIO (erevo-lms/dpc-extract/ogdpc_sessions_latest.csv). Échec ⇒ ScheduledCommandException.
  2. Parser le CSV (BOM-aware, séparateur ;). Colonnes : reference, session_number, start_date, end_date, continuing_education_end_date, second_evaluation_start_date, format, intervenant, hours, participant_list_url.
  3. Regrouper les lignes par reference (= Version.reference).
  4. Pour chaque reference :
    • VersionRepository::findOneBy(['reference' => …]). Absent ⇒ log erreur + skip.
    • Index internalId → SessionDate pour les SessionDate rattachées à la Version.
    • determineProgramCategory($version)FC / VC / EPP / IP (basé sur FormatInterface::*_FORMAT et l’internalId du format).
    • Pour chaque session CSV :
      • extractSessionNumber("26.013" → 13) ; invalide ⇒ log erreur.
      • Lookup par internalId. Absent ⇒ missing (pas une erreur bloquante).
      • reconcileDates() compare et corrige startingAt, finishingAt, continuingEducationEndDate, secondEvaluationStartDate :
        • VC : comparaison full datetime, écrasement forcé à 09:00–17:00 Paris (DB en UTC).
        • Non-VC : comparaison date-only (Paris), préserve l’heure existante. Start 00:00:00 Paris / End 23:59:59 Paris.
      • lmsStartDate : si null ou antérieure à startingAt, réalignée sur startingAt.
      • Pour les VC, reconcileVcModules() : les VirtualClassModule sont réécrits selon la grille standard :
        • module N (1-based) → jour startDate + floor((N-1)/2) jours, horaires 09:00–12:30 (N impair) ou 13:30–17:00 (N pair) ;
        • si moduleCount != daysInSpan * 2, layout non-standard → skipped (pas modifié).
  5. Validation IA Gemini (si GeminiClient::isEnabled()) : pour chaque reference, prompt décrivant les règles FC/VC/EPP/IP ; Gemini renvoie OK ou une liste Session N: issue. Warnings consignés sans impact sur l’exit.
  6. Si au moins un fix a été appliqué, EntityManager::flush() (atomique pour l’ensemble du run).
  7. Rapport CSV : reference;session_number;type;description avec type ∈ {fixed, error, missing, skipped}, uploadé sur MinIO (dpc-extract/reports/…) sauf --no-report-upload.
  8. Exit : FAILURE si $errors non vide, sinon SUCCESS. Les warnings Gemini et les missing ne déclenchent pas d’échec.
  • Version — lecture par reference.
  • SessionDate — écriture startingAt, finishingAt, continuingEducationEndDate, secondEvaluationStartDate, lmsStartDate.
  • VirtualClass — lecture via VirtualClassRepository::findOneBy(['sessionDate' => $sd]) pour accéder aux modules.
  • VirtualClassModule — écriture startingAt, finishingAt lors de la normalisation des demi-journées.
  • Product / Format — lecture pour déterminer la catégorie de programme.

TODO(review) : pages modele-de-donnees/version, session-date, virtual-class, virtual-class-module, product absentes — à créer par entity-documenter.

  • ScheduledCommandException (fait échouer le job) :
    • CSV local introuvable (--local-csv) ;
    • Échec GetObject MinIO.
  • Erreurs par ligne (session invalide, Version manquante, date CSV illisible) : loggées, agrégées dans $errors, ne font pas throw — mais l’exit code final devient FAILURE si $errors est non vide.
  • Warnings Gemini et missing : loggés, pas d’échec.
  • Le flush() Doctrine est atomique pour l’ensemble du run (pas de flush par reference).
  • MinIO / S3 : erevo-lms/dpc-extract/ogdpc_sessions_latest.csv (input), erevo-lms/dpc-extract/reports/session-date-reconcile_*.csv (output).
  • Gemini API (App\Service\GeminiClient) — credential $GEMINI_API_KEY. Activée si la clé est présente ; retry 5xx/429 (commit 12d65af2). Modèle gemini-2.5-flash.
  • MariaDB : Versions, SessionDates, VirtualClasses, VirtualClassModules.
  • Logs : GitLab > Build > Pipelines > ogdpc_reconcile_session_dates. Sortie très détaillée (compteurs Matched / Fixed / LMS fixed / VC modules fixed / VC modules skipped / Missing / Errors / AI warnings).
  • Rapport CSV : dpc-extract/reports/session-date-reconcile_latest.csv sur MinIO — à récupérer pour audit après chaque run.
  • Alerting : Sentry capture les ScheduledCommandException et toute exception PHP.
  • Commande : src/Command/Scheduled/ReconcileSessionDateCommand.php
  • Job CI : ci-jobs/.scheduled-ci.yml (job ogdpc_reconcile_session_dates)
  • Services : App\Service\GeminiClient, Aws\S3\S3Client
  • Repositories : App\Repository\VirtualClassRepository, EntityManager::getRepository(Version::class)
  • Interface de formats : App\Interface\FormatInterface
  • Exception : App\Exceptions\ScheduledCommandException