V7.10 — Tableau de bord, guide, semaine type et enveloppe de formation

Reprise dans le répertoire de production du travail mené dans le worktree
ux-service-enfance :

- tableau de bord Service Enfance (dashboard.php) et navigation regroupée ;
- guide d'utilisation (faq.php) accessible depuis toute la navigation ;
- éditeur de semaine type mis en avant sur l'écran de saisie ;
- droit à l'enveloppe de formation par agent, en remplacement de la case
  « formation déjà prévue dans la répartition annuelle » ;
- correctif de « [object Object] » sur les cartes de quota du PTA ;
- motif de travail par défaut à la saisie, heures travaillées complètes
  dans les PDF.

Le docker-compose.yml de production est conservé : celui du worktree décrit
une pile de test (conteneurs et volume suffixés « test », ports 9080/9081),
qui aurait fait redémarrer l'application sur un volume MariaDB vide.

Les migrations database/migration_v7_9*.sql sont obligatoires ; le service
db-migrate les applique au déploiement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
PTA
2026-08-17 16:53:04 +02:00
parent 57bd8da5c8
commit 4201894e28
69 changed files with 5228 additions and 246 deletions

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Services;
use App\Core\MotifCategories;
use DateTimeImmutable;
final class PlanningPdfService
@@ -170,7 +171,7 @@ final class PlanningPdfService
$blockY = $y + 5;
foreach ($blocks as $block) {
$entry = $block['entry'];
$palette = $this->motifPalette((string) ($entry['motif_code'] ?? 'AUTRE'));
$palette = $this->entryPalette($entry);
$blockHeight = (float) $block['height'];
$pdf->fillRectColor($cellX + 4, $blockY, $dayWidth - 8, $blockHeight, $palette['background']);
$pdf->fillRectColor($cellX + 4, $blockY, 3.0, $blockHeight, $palette['accent']);
@@ -269,7 +270,7 @@ final class PlanningPdfService
break;
}
$palette = $this->motifPalette((string) ($entry['motif_code'] ?? 'AUTRE'));
$palette = $this->entryPalette($entry);
$pdf->fillRectColor($colX + 4, $cursorY, $colWidth - 8, $cardHeight, $palette['background']);
$pdf->fillRectColor($colX + 4, $cursorY, 3.0, $cardHeight, $palette['accent']);
@@ -320,21 +321,35 @@ final class PlanningPdfService
return $pdf->wrap($first, $width, 7.0);
}
/**
* Le motif générique TRAVAIL n'apporte aucune information sur une plage déjà colorée
* en « temps de travail » ; les motifs de travail spécialisés (ALP matin, ALP soir,
* restauration…) restent affichés, ils précisent la nature du temps travaillé.
*/
private function motifDisplayLabel(array $entry): string
{
return strtoupper((string) ($entry['motif_code'] ?? '')) === 'TRAVAIL'
return MotifCategories::normalizeCode($entry['motif_code'] ?? null) === 'TRAVAIL'
? ''
: (string) ($entry['motif_libelle'] ?? 'Affectation');
}
/** @return array{accent:string,background:string,label:string} */
private function motifPalette(string $code): array
private function entryPalette(array $entry): array
{
return match (strtoupper($code)) {
'TRAVAIL' => ['accent' => '#2563EB', 'background' => '#EFF6FF', 'label' => 'Travail'],
'FORMATION' => ['accent' => '#7C3AED', 'background' => '#F5F3FF', 'label' => 'Formation'],
'CONGE' => ['accent' => '#059669', 'background' => '#ECFDF5', 'label' => 'Conge'],
'MALADIE' => ['accent' => '#DC2626', 'background' => '#FEF2F2', 'label' => 'Absence'],
return $this->motifPalette(
(string) ($entry['motif_code'] ?? 'AUTRE'),
(int) ($entry['compte_dans_quota'] ?? 0) === 1
);
}
/** @return array{accent:string,background:string,label:string} */
private function motifPalette(string $code, bool $countsInQuota = false): array
{
return match (MotifCategories::category($code, $countsInQuota)) {
MotifCategories::TRAVAIL => ['accent' => '#2563EB', 'background' => '#EFF6FF', 'label' => 'Travail'],
MotifCategories::FORMATION => ['accent' => '#7C3AED', 'background' => '#F5F3FF', 'label' => 'Formation'],
MotifCategories::CONGE => ['accent' => '#059669', 'background' => '#ECFDF5', 'label' => 'Conge'],
MotifCategories::ABSENCE => ['accent' => '#DC2626', 'background' => '#FEF2F2', 'label' => 'Absence'],
default => ['accent' => '#64748B', 'background' => '#F8FAFC', 'label' => 'Autre absence'],
};
}
@@ -342,18 +357,20 @@ final class PlanningPdfService
private function drawLegend(SimplePdf $pdf, float $x, float $y): void
{
$items = [
['TRAVAIL', 'Travail'],
['TRAVAIL', 'Travail (dont ALP, restauration, preparation)'],
['FORMATION', 'Formation'],
['CONGE', 'Conge'],
['MALADIE', 'Absence'],
['AUTRE', 'Autre absence'],
['ABSENCE', 'Absence'],
['JNT', 'Autre absence'],
];
foreach ($items as [$code, $label]) {
$palette = $this->motifPalette($code);
$pdf->fillRectColor($x, $y - 7, 8, 8, $palette['accent']);
$pdf->text($x + 12, $y, $label, 6.5);
$x += 76;
// Largeur estimée du libellé (Helvetica ~0,52 em) plutôt qu'un pas fixe :
// la première entrée est trop longue pour une colonne de 76 points.
$x += 12 + (mb_strlen($label) * 6.5 * 0.52) + 18;
}
}