Rapprochement des dates de session OGDPC
Version métier : voir Rapprochement des dates de session OGDPC.
Description
Section intitulée « Description »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.
Déclenchement
Section intitulée « Déclenchement »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 :
docker exec $APP_NAME php bin/console scheduled:ogdpc-reconcile-session-datesOptions (utilisables en manuel) :
--bucket=<name>(défauterevo-lms)--csv-key=<key>(défautdpc-extract/ogdpc_sessions_latest.csv)--local-csv=/path.csv— court-circuite MinIO--no-report-upload— n’upload pas le rapport CSV
Fonctionnement
Section intitulée « Fonctionnement »- Charger le CSV :
--local-csvsinonGetObjectMinIO (erevo-lms/dpc-extract/ogdpc_sessions_latest.csv). Échec ⇒ScheduledCommandException. - 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. - Regrouper les lignes par
reference(=Version.reference). - Pour chaque
reference:VersionRepository::findOneBy(['reference' => …]). Absent ⇒ log erreur + skip.- Index
internalId → SessionDatepour lesSessionDaterattachées à laVersion. determineProgramCategory($version)→FC/VC/EPP/IP(basé surFormatInterface::*_FORMATet l’internalIddu format).- Pour chaque session CSV :
extractSessionNumber("26.013" → 13); invalide ⇒ log erreur.- Lookup par
internalId. Absent ⇒missing(pas une erreur bloquante). reconcileDates()compare et corrigestartingAt,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:00Paris / End23:59:59Paris.
lmsStartDate: sinullou antérieure àstartingAt, réalignée surstartingAt.- Pour les VC,
reconcileVcModules(): lesVirtualClassModulesont réécrits selon la grille standard :- module
N(1-based) → jourstartDate + floor((N-1)/2)jours, horaires09:00–12:30(N impair) ou13:30–17:00(N pair) ; - si
moduleCount != daysInSpan * 2, layout non-standard →skipped(pas modifié).
- module
- Validation IA Gemini (si
GeminiClient::isEnabled()) : pour chaquereference, prompt décrivant les règles FC/VC/EPP/IP ; Gemini renvoieOKou une listeSession N: issue. Warnings consignés sans impact sur l’exit. - Si au moins un fix a été appliqué,
EntityManager::flush()(atomique pour l’ensemble du run). - Rapport CSV :
reference;session_number;type;descriptionavectype ∈ {fixed, error, missing, skipped}, uploadé sur MinIO (dpc-extract/reports/…) sauf--no-report-upload. - Exit :
FAILUREsi$errorsnon vide, sinonSUCCESS. Les warnings Gemini et lesmissingne déclenchent pas d’échec.
Entités impactées
Section intitulée « Entités impactées »- 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,finishingAtlors 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,productabsentes — à créer parentity-documenter.
Gestion des erreurs
Section intitulée « Gestion des erreurs »ScheduledCommandException(fait échouer le job) :- CSV local introuvable (
--local-csv) ; - Échec
GetObjectMinIO.
- CSV local introuvable (
- Erreurs par ligne (session invalide,
Versionmanquante, date CSV illisible) : loggées, agrégées dans$errors, ne font pasthrow— mais l’exit code final devientFAILUREsi$errorsest non vide. - Warnings Gemini et
missing: loggés, pas d’échec. - Le
flush()Doctrine est atomique pour l’ensemble du run (pas de flush parreference).
Dépendances externes
Section intitulée « Dépendances externes »- 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 (commit12d65af2). Modèlegemini-2.5-flash. - MariaDB : Versions, SessionDates, VirtualClasses, VirtualClassModules.
Observabilité
Section intitulée « Observabilité »- Logs :
GitLab > Build > Pipelines > ogdpc_reconcile_session_dates. Sortie très détaillée (compteursMatched / Fixed / LMS fixed / VC modules fixed / VC modules skipped / Missing / Errors / AI warnings). - Rapport CSV :
dpc-extract/reports/session-date-reconcile_latest.csvsur MinIO — à récupérer pour audit après chaque run. - Alerting : Sentry capture les
ScheduledCommandExceptionet toute exception PHP.
Références code
Section intitulée « Références code »- Commande :
src/Command/Scheduled/ReconcileSessionDateCommand.php - Job CI :
ci-jobs/.scheduled-ci.yml(jobogdpc_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