# Push vers Escada Le push envoie les modifications locales (absences en `EscadaPending` + notices en attente dans `Notice`) vers Escadaweb via Playwright. ## Page : `/escada` → « Pousser vers Escada » ### Quand un pending d'absence est créé ? Chaque modification d'absence dans l'application crée ou met à jour une entrée dans `EscadaPending` : | Action utilisateur | Pending créé | |---------------------------------------------------|---------------------| | Marquer P3 comme excusée | `action=E` | | Marquer P5 comme non excusée | `action=N` | | Retirer une absence (présent) | `action=clear` | | Excuse rapide d'une journée (page Apprentis) | `action=E` × n | | « Absent toute la journée » (selon horaire classe)| `action=N` × n (sur enregistrement) | La contrainte d'unicité `(apprenti_id, date, periode)` garantit qu'une période a au plus un pending. Si on modifie deux fois la même période, le dernier pending écrase le précédent. ## Phases du push d'absences ### Phase 1 : Préparation `scripts/push_to_escada.py` : 1. Lit toutes les entrées de `EscadaPending` 2. Groupe par classe pour minimiser les navigations Escada 3. Lance Playwright ### Phase 2 : Exécution Playwright Pour chaque pending : 1. Navigue jusqu'à la page d'absences de l'apprenti dans Escadaweb 2. Trouve la cellule (date × période) 3. Selon l'action : - `E` : sélectionne « Excusée » dans le dropdown - `N` : sélectionne « Non excusée » - `clear` : remet à blanc (= apprenti présent) 4. Clique sur **Speichern** (Enregistrer) 5. Si OK → supprime l'entrée du `EscadaPending` 6. Si erreur → conserve l'entrée et la liste dans `PUSH_DONE` ### Phase 3 : Rapport Le script imprime une ligne `PUSH_DONE {"ok": N, "err": [...]}` à la fin. L'app la parse et affiche : - Nombre d'envois OK - Liste des erreurs (chaque erreur mentionne l'apprenti, la date et la période) ## Push de notices Les notices créées localement (création d'avis de retenue ou de sanction depuis l'app) sont enregistrées dans la table `Notice` (statut `pending`), puis poussées par `scripts/push_notices.py`. ### Workflow 1. L'utilisateur clique sur « Générer l'avis » dans une modale d'avis sanction/retenue. Cela : - Génère le PDF (téléchargement) - Crée une `Notice` avec `source="sanction"` ou `"retenue"`, `status="pending"`, et le préfixe `()` est ajouté en début de la remarque pour traçabilité 2. La file `Notice (status=pending)` est visible côté admin sur `/escada` ou via les tâches cron. 3. `push_notices.py` : - Lit les notices `pending` - Pour chaque, navigue dans Escada (page de l'apprenti → onglet Notices) et crée la notice avec son titre + remarque + date - Marque comme `synced` si OK, `error` (+ `error_msg`) sinon ### task_kind cron - `task_kind=push` + `sync_abs=1` → pousse les absences - `task_kind=push` + `sync_notices=1` → pousse les notices - `task_kind=push` + les deux → push absences puis notices (séquentiel) ## Que faire si un push échoue ? 1. **Vérifier les logs** (`/logs`) — l'erreur exacte est tracée. 2. **Causes fréquentes** : - Session Escada expirée → relancer un Actualiser sur la page Escada (re-login automatique) - Apprenti avec un nom différent dans Escada → renommage à faire dans la DB ou côté Escada - Page de notation verrouillée par un collègue (Escada utilise des locks pessimistes) 3. **Re-tenter** : les pendings (et notices `pending`/`error`) restent en file d'attente, un nouveau push les retraitera. ## Audit Chaque push manuel logue qui l'a déclenché : ``` [abs] {user} : Push Escada démarré par {username} [notice] {user} : création (sanction) pour {apprenti} [notice] {user} : création (retenue) pour {apprenti} — case=devoir ``` Côté résultat : - `Push terminé — ok:N erreurs:M` dans `operations.log` ## Push automatique via cron Les tâches planifiées de type `push` ou `push_then_sync` exécutent les mêmes scripts. Voir la section [Tâches planifiées](#).