- nouvelle page /retenue : sélection apprenti, date retenue, date du
problème, motif (3 cases mutex), branche (autocomplete + saisie libre
depuis NotesExamen), remarque. Génération PDF basée sur le template
AcroForm officiel, séparation des 3 widgets Date partagés en 3 champs
distincts pour ne remplir que celui de la case cochée. Téléchargement
ou envoi par email (3 destinataires).
- profession : nouveau champ ApprentiFiche.profession, dérivé du préfixe
de classe via mapping configurable dans Paramètres
("AUTOMAT" → "Automaticien CFC" par défaut). Section dédiée avec
classes orphelines détectées automatiquement.
- notices Escada : nouvelle table Notice (apprenti, titre, remarque,
date, status). Checkbox "Ajouter automatiquement une notice sur
Escada" sur /retenue qui crée une entrée pending. Bloc dédié sur
/escada listant les pending, bouton "Pousser les notices" qui lance
scripts/push_notices.py (Playwright : navigation Classes → Élèves →
Notices → Ajouter, fill date / titre / remarque, vérification post-save,
suppression DB si OK, marquage failed sinon). Nouveau task_kind "push_notices"
dans le cron pour exécution planifiée.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- création de compte par admin envoie un email avec lien de définition (7j),
bouton "Reset mdp" pour renvoyer un lien (24h). Plus aucun admin ne peut
modifier directement le mdp d'un user (tout passe par les liens email).
- nouvelle page /password-set publique (validation token, formulaire, hash
bcrypt) au style aligné sur /login, avec emails multipart texte+HTML.
- nouvelle page /profile (changement mdp avec ancien, reset 2FA, avatar,
infos), accessible via dropdown sur le widget user en bas de sidebar.
- restriction d'accès par utilisateur : champ allowed_classes dans auth.yaml,
multi-select dans la page Users, filtrage cross-page (KPIs, sanctions,
classes, apprentis, navigations cross-page, génération PDF avis).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- importer.py : nouvelle logique pour les 4 cas d'absence × pending :
* abs en PDF + pending modify : pending wins (sans force) / override (force)
* abs en PDF + pas en DB + pending action=clear : respecte la suppression
locale (sans force) / recrée l'abs (force)
* orpheline (DB sans PDF) sans pending : supprimée + comptée + détaillée
* orpheline avec pending : conservée (sans force) / supprimée (force)
- importer.py : query orpheline par classe + fenêtre de dates du PDF
(couvre les abs locales avec import_id=None)
- run_imports.py : remonte orphelines + pending_skipped dans res_abs
- notifier.py : niveau detailed inclut absences supprimées par classe
+ détail des orphelines (max 5 par classe)
- escada.py : sépare cache disque (toutes classes pour matching Matu)
vs liste UI (filtrée MP/MI/Formation)
- escada.py : timeout polling import passe de 60s à 15min
- escada.py : retire mode test push, fix bouton Actualiser bloqué sans
classe sélectionnée
- cron.py : reset last_run_at à l'activation d'un job pour relance
immédiate au prochain tick
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>