Nouvelle colonne `agent.droit_enveloppe_formation`, cochée par défaut, saisie à la création de l'agent et modifiable depuis sa fiche. Un agent sans ce droit : - ne voit plus le motif « Formation » dans le sélecteur de motif de l'éditeur de planning ni dans le modal de la vue individuelle ; - se voit refuser toute affectation de ce motif par le serveur, avec un message qui nomme le motif et l'agent (save_planning.php et update_agent_entry.php) ; - a une enveloppe de formation de 0 min au PTA annuel, et une ALERTE FORMATION_SANS_DROIT si des heures de formation subsistent dans son planning. À ne pas confondre avec `formation_repartition_annuelle`, qui existait déjà : celle-ci dit que la formation est déjà comptée dans la répartition annuelle — l'agent y a droit, l'enveloppe complémentaire n'est simplement pas ajoutée. Les deux règles sont désormais rassemblées dans AgentModel::trainingEnvelopeMinutes(), qui remplace les deux calculs « 840 ou 0 » jusque-là dupliqués. Le motif interdit reste affiché lorsqu'il est déjà celui de la plage en cours d'édition : le retirer de la liste changerait silencieusement le motif d'une saisie existante. C'est le contrôle de saisie, puis le serveur, qui demandent alors de corriger la plage. La migration est nommée v7_9b et non v7_10 : les fichiers sont joués dans l'ordre alphabétique, où « v7_10 » passerait avant « v7_8 ». Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
122 lines
5.3 KiB
PHP
122 lines
5.3 KiB
PHP
<?php
|
||
/** @var string $csrfToken */
|
||
/** @var array $agents */
|
||
/** @var array $structures */
|
||
/** @var string $error */
|
||
/** @var array|null $currentProfile */
|
||
/** @var string $cspNonce */
|
||
?>
|
||
<!doctype html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Choisir votre accès — PTA</title>
|
||
<link rel="stylesheet" href="assets/style.css?v=7.12">
|
||
</head>
|
||
<body class="role-page-body">
|
||
<main class="role-page-shell">
|
||
<section class="role-intro">
|
||
<p class="eyebrow">PTA</p>
|
||
<h1>Quel est votre rôle ?</h1>
|
||
<p>Votre choix détermine les pages visibles et les actions autorisées pendant cette session.</p>
|
||
<?php if ($currentProfile): ?>
|
||
<div class="role-current-profile">
|
||
Profil actuel : <strong><?= htmlspecialchars((string) $currentProfile['role_label']) ?></strong>
|
||
— <?= htmlspecialchars((string) $currentProfile['label']) ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if ($error !== ''): ?>
|
||
<div class="message message-error"><?= htmlspecialchars($error) ?></div>
|
||
<?php endif; ?>
|
||
</section>
|
||
|
||
<form method="post" class="role-selection-form" id="role-selection-form">
|
||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
|
||
|
||
<div class="role-choice-grid">
|
||
<label class="role-choice-card">
|
||
<input type="radio" name="role" value="AGENT" required>
|
||
<span class="role-choice-content">
|
||
<strong>Agent</strong>
|
||
<small>Lecture de mon planning et du planning de mon lieu de rattachement.</small>
|
||
</span>
|
||
</label>
|
||
|
||
<label class="role-choice-card">
|
||
<input type="radio" name="role" value="RESPONSABLE_STRUCTURE" required>
|
||
<span class="role-choice-content">
|
||
<strong>Responsable de structure</strong>
|
||
<small>Saisie et modification des horaires et motifs de mon lieu, uniquement en brouillon.</small>
|
||
</span>
|
||
</label>
|
||
|
||
<label class="role-choice-card">
|
||
<input type="radio" name="role" value="SERVICE_ENFANCE" required>
|
||
<span class="role-choice-content">
|
||
<strong>Service Enfance</strong>
|
||
<small>Contrôle complet, prévisionnel N+1, administration et validation des plannings.</small>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div id="agent-context" class="role-context-card" hidden>
|
||
<label class="field">
|
||
<span>Je suis l’agent</span>
|
||
<select name="agent_id" id="role-agent-select">
|
||
<option value="">Choisir mon identité</option>
|
||
<?php foreach ($agents as $agent): ?>
|
||
<option value="<?= (int) $agent['id_agent'] ?>">
|
||
<?= htmlspecialchars($agent['prenom'] . ' ' . $agent['nom'] . ' (' . $agent['matricule'] . ')') ?>
|
||
<?= !empty($agent['structure_nom']) ? ' — ' . htmlspecialchars((string) $agent['structure_nom']) : '' ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<div id="responsable-context" class="role-context-card" hidden>
|
||
<label class="field">
|
||
<span>Je suis responsable du lieu</span>
|
||
<select name="structure_id" id="role-structure-select">
|
||
<option value="">Choisir le lieu d’affectation</option>
|
||
<?php foreach ($structures as $structure): ?>
|
||
<option value="<?= (int) $structure['id_structure'] ?>">
|
||
<?= htmlspecialchars((string) $structure['nom']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="role-form-actions">
|
||
<button type="submit" class="button button-primary">Accéder à PTA</button>
|
||
</div>
|
||
</form>
|
||
|
||
<aside class="role-security-note">
|
||
<strong>Version de démonstration :</strong> ce sélecteur organise les droits dans l’application, mais ne remplace pas une authentification nominative. En production, le rôle devra être associé au compte connecté.
|
||
</aside>
|
||
</main>
|
||
<script nonce="<?= htmlspecialchars($cspNonce, ENT_QUOTES) ?>">
|
||
(() => {
|
||
const agentContext = document.querySelector('#agent-context');
|
||
const responsableContext = document.querySelector('#responsable-context');
|
||
const agentSelect = document.querySelector('#role-agent-select');
|
||
const structureSelect = document.querySelector('#role-structure-select');
|
||
|
||
function refresh() {
|
||
const role = document.querySelector('input[name="role"]:checked')?.value || '';
|
||
agentContext.hidden = role !== 'AGENT';
|
||
responsableContext.hidden = role !== 'RESPONSABLE_STRUCTURE';
|
||
agentSelect.required = role === 'AGENT';
|
||
structureSelect.required = role === 'RESPONSABLE_STRUCTURE';
|
||
}
|
||
|
||
document.querySelectorAll('input[name="role"]').forEach((input) => input.addEventListener('change', refresh));
|
||
refresh();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|