pour prod
This commit is contained in:
208
app/Services/AgentHoursContractPdfService.php
Normal file
208
app/Services/AgentHoursContractPdfService.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* Génère le document annuel de validation du quota horaire d'un agent.
|
||||
* Le PDF est autonome et ne nécessite aucune dépendance Composer.
|
||||
*/
|
||||
final class AgentHoursContractPdfService
|
||||
{
|
||||
private const PAGE_WIDTH = 595.28;
|
||||
private const PAGE_HEIGHT = 841.89;
|
||||
private const MARGIN = 42.0;
|
||||
|
||||
public function annualContract(array $agent, array $quota): string
|
||||
{
|
||||
$pdf = new SimplePdf(self::PAGE_WIDTH, self::PAGE_HEIGHT);
|
||||
$periodLabel = (string) ($quota['periode_libelle'] ?? ('année ' . ($quota['annee'] ?? date('Y'))));
|
||||
$generatedAt = new DateTimeImmutable('now', new DateTimeZone('Europe/Paris'));
|
||||
|
||||
$this->drawHeader($pdf, $agent, $periodLabel, $generatedAt);
|
||||
$this->drawAgentIdentity($pdf, $agent);
|
||||
$this->drawQuotaSummary($pdf, $quota);
|
||||
$this->drawValidationClause($pdf, $periodLabel, $generatedAt);
|
||||
$this->drawSignatures($pdf);
|
||||
|
||||
$pdf->text(
|
||||
self::MARGIN,
|
||||
813,
|
||||
sprintf('Document généré par PTA le %s - Référence agent : %s', $generatedAt->format('d/m/Y H:i'), (string) ($agent['matricule'] ?? '-')),
|
||||
7
|
||||
);
|
||||
|
||||
return $pdf->output();
|
||||
}
|
||||
|
||||
private function drawHeader(SimplePdf $pdf, array $agent, string $periodLabel, DateTimeImmutable $generatedAt): void
|
||||
{
|
||||
$pdf->text(self::MARGIN, 48, 'CONTRAT HORAIRE ANNUEL', 18, true);
|
||||
$pdf->text(self::MARGIN, 71, 'Validation du quota annuel de travail', 12, true);
|
||||
$pdf->text(self::MARGIN, 92, 'Période de référence : ' . $periodLabel, 10);
|
||||
$pdf->text(self::MARGIN + 315, 92, 'Édité le : ' . $generatedAt->format('d/m/Y'), 10);
|
||||
$pdf->line(self::MARGIN, 108, self::PAGE_WIDTH - self::MARGIN, 108, 0.35);
|
||||
|
||||
$pdf->text(
|
||||
self::MARGIN,
|
||||
130,
|
||||
sprintf('%s %s', (string) ($agent['prenom'] ?? ''), (string) ($agent['nom'] ?? '')),
|
||||
14,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private function drawAgentIdentity(SimplePdf $pdf, array $agent): void
|
||||
{
|
||||
$x = self::MARGIN;
|
||||
$y = 150.0;
|
||||
$w = self::PAGE_WIDTH - (self::MARGIN * 2);
|
||||
$h = 140.0;
|
||||
|
||||
$pdf->fillRect($x, $y, $w, 28, 0.93);
|
||||
$pdf->rect($x, $y, $w, $h, 0.65);
|
||||
$pdf->text($x + 12, $y + 19, 'Informations de l\'agent', 11, true);
|
||||
|
||||
$leftX = $x + 14;
|
||||
$rightX = $x + 278;
|
||||
$row1 = $y + 52;
|
||||
$row2 = $y + 78;
|
||||
$row3 = $y + 102;
|
||||
$row4 = $y + 128;
|
||||
|
||||
$qualification = !empty($agent['est_diplome'])
|
||||
? 'Diplômé' . (!empty($agent['diplome_libelle']) ? ' - ' . $agent['diplome_libelle'] : '')
|
||||
: 'Non diplômé';
|
||||
|
||||
$pdf->text($leftX, $row1, 'Matricule : ' . (($agent['matricule'] ?? '') ?: '-'), 9);
|
||||
$pdf->text($rightX, $row1, 'E-mail : ' . (($agent['email'] ?? '') ?: 'Non renseigné'), 9);
|
||||
$pdf->text($leftX, $row2, 'Téléphone : ' . (($agent['telephone'] ?? '') ?: 'Non renseigné'), 9);
|
||||
$pdf->text($rightX, $row2, 'Qualification : ' . $qualification, 9);
|
||||
$pdf->text($leftX, $row3, 'Lieu principal : ' . (($agent['structure_principale_nom'] ?? '') ?: 'Non renseigné'), 9);
|
||||
$pdf->text($rightX, $row3, 'Début du contrat : ' . (!empty($agent['date_debut_contrat']) ? (new DateTimeImmutable((string) $agent['date_debut_contrat']))->format('d/m/Y') : 'Non renseigné'), 9);
|
||||
$address = (string) (($agent['adresse'] ?? '') ?: 'Non renseignée');
|
||||
$addressLines = $pdf->wrap('Adresse : ' . $address, $w - 28, 8.5);
|
||||
$pdf->text($leftX, $row4, (string) ($addressLines[0] ?? 'Adresse : Non renseignée'), 8.5);
|
||||
$pdf->text($rightX, $row4, 'Type du lieu : ' . $this->typeLabel((string) ($agent['structure_principale_type_affectation'] ?? '')), 8.5);
|
||||
}
|
||||
|
||||
private function drawQuotaSummary(SimplePdf $pdf, array $quota): void
|
||||
{
|
||||
$x = self::MARGIN;
|
||||
$y = 318.0;
|
||||
$w = self::PAGE_WIDTH - (self::MARGIN * 2);
|
||||
$headerH = 30.0;
|
||||
$rowH = 31.0;
|
||||
|
||||
$rows = [
|
||||
['Quota annuel de référence à 100 %', $this->minutesLabel((int) ($quota['quota_reference_minutes'] ?? 0))],
|
||||
['Quotité de travail applicable', $this->percentLabel((float) ($quota['quotite_travail'] ?? 100))],
|
||||
['Quota annuel cible de l\'agent', (string) ($quota['quota_cible']['libelle'] ?? $this->minutesLabel((int) ($quota['quota_cible_minutes'] ?? 0)))],
|
||||
['Heures validées dans PTA à la date d\'édition', (string) ($quota['valides']['libelle'] ?? $this->minutesLabel((int) ($quota['minutes_valides'] ?? 0)))],
|
||||
['Heures encore en brouillon', (string) ($quota['brouillons']['libelle'] ?? $this->minutesLabel((int) ($quota['minutes_brouillon'] ?? 0)))],
|
||||
['Solde restant à planifier / affecter', (string) ($quota['restantes']['libelle'] ?? $this->minutesLabel((int) ($quota['minutes_restantes'] ?? 0)))],
|
||||
];
|
||||
|
||||
$pdf->fillRect($x, $y, $w, $headerH, 0.90);
|
||||
$pdf->rect($x, $y, $w, $headerH + (count($rows) * $rowH), 0.60);
|
||||
$pdf->text($x + 12, $y + 20, 'Synthèse du quota horaire', 11, true);
|
||||
|
||||
$labelWidth = 360.0;
|
||||
$valueWidth = $w - $labelWidth;
|
||||
$cursorY = $y + $headerH;
|
||||
|
||||
foreach ($rows as $index => [$label, $value]) {
|
||||
if ($index % 2 === 1) {
|
||||
$pdf->fillRect($x, $cursorY, $w, $rowH, 0.975);
|
||||
}
|
||||
$pdf->line($x, $cursorY, $x + $w, $cursorY, 0.82);
|
||||
$pdf->line($x + $labelWidth, $cursorY, $x + $labelWidth, $cursorY + $rowH, 0.82);
|
||||
$pdf->text($x + 12, $cursorY + 20, (string) $label, 8.6, $index === 2);
|
||||
$pdf->text($x + $labelWidth + 12, $cursorY + 20, (string) $value, 9.2, $index === 2);
|
||||
$cursorY += $rowH;
|
||||
}
|
||||
}
|
||||
|
||||
private function drawValidationClause(SimplePdf $pdf, string $periodLabel, DateTimeImmutable $generatedAt): void
|
||||
{
|
||||
$x = self::MARGIN;
|
||||
$y = 557.0;
|
||||
$w = self::PAGE_WIDTH - (self::MARGIN * 2);
|
||||
|
||||
$pdf->text($x, $y, 'Validation', 11, true);
|
||||
|
||||
$paragraphs = [
|
||||
sprintf(
|
||||
'Le présent document fixe et récapitule le quota annuel de travail applicable à l\'agent pour la période %s. La signature de l\'agent et la contre-signature du responsable valent validation du quota annuel indiqué ci-dessus.',
|
||||
$periodLabel
|
||||
),
|
||||
'Les heures validées et les heures en brouillon constituent un état de suivi à la date d\'édition. Toute modification ultérieure du planning doit faire l\'objet d\'une nouvelle validation dans PTA lorsque cela est nécessaire.',
|
||||
];
|
||||
|
||||
$cursorY = $y + 22;
|
||||
foreach ($paragraphs as $paragraph) {
|
||||
foreach ($pdf->wrap($paragraph, $w, 9) as $line) {
|
||||
$pdf->text($x, $cursorY, $line, 9);
|
||||
$cursorY += 13;
|
||||
}
|
||||
$cursorY += 8;
|
||||
}
|
||||
|
||||
$pdf->text($x, 638, 'Fait à : ____________________________________', 9);
|
||||
$pdf->text($x + 286, 638, 'Le : ____ / ____ / ________', 9);
|
||||
$pdf->text($x, 658, 'Document établi le ' . $generatedAt->format('d/m/Y') . '.', 8);
|
||||
}
|
||||
|
||||
private function drawSignatures(SimplePdf $pdf): void
|
||||
{
|
||||
$x = self::MARGIN;
|
||||
$y = 680.0;
|
||||
$gap = 18.0;
|
||||
$w = (self::PAGE_WIDTH - (self::MARGIN * 2) - $gap) / 2;
|
||||
$h = 120.0;
|
||||
|
||||
$pdf->rect($x, $y, $w, $h, 0.55);
|
||||
$pdf->rect($x + $w + $gap, $y, $w, $h, 0.55);
|
||||
|
||||
$pdf->fillRect($x, $y, $w, 28, 0.94);
|
||||
$pdf->fillRect($x + $w + $gap, $y, $w, 28, 0.94);
|
||||
|
||||
$pdf->text($x + 10, $y + 19, 'Signature de l\'agent', 10, true);
|
||||
$pdf->text($x + $w + $gap + 10, $y + 19, 'Contre-signature du responsable', 10, true);
|
||||
|
||||
$pdf->text($x + 10, $y + 48, 'Nom : ______________________________', 8.5);
|
||||
$pdf->text($x + 10, $y + 68, 'Mention « Lu et approuvé » :', 8.5);
|
||||
$pdf->text($x + 10, $y + 101, 'Signature :', 8.5);
|
||||
|
||||
$rightX = $x + $w + $gap + 10;
|
||||
$pdf->text($rightX, $y + 48, 'Nom / qualité : _____________________', 8.5);
|
||||
$pdf->text($rightX, $y + 68, 'Mention « Bon pour validation » :', 8.5);
|
||||
$pdf->text($rightX, $y + 101, 'Signature et cachet :', 8.5);
|
||||
}
|
||||
|
||||
private function typeLabel(string $type): string
|
||||
{
|
||||
return match (strtoupper($type)) {
|
||||
'EXTRASCOLAIRE' => 'Extrascolaire',
|
||||
'PERISCOLAIRE' => 'Périscolaire',
|
||||
default => 'Non renseigné',
|
||||
};
|
||||
}
|
||||
|
||||
private function percentLabel(float $rate): string
|
||||
{
|
||||
$formatted = rtrim(rtrim(number_format($rate, 2, ',', ' '), '0'), ',');
|
||||
return $formatted . ' %';
|
||||
}
|
||||
|
||||
private function minutesLabel(int $minutes): string
|
||||
{
|
||||
$sign = $minutes < 0 ? '-' : '';
|
||||
$absolute = abs($minutes);
|
||||
return sprintf('%s%d h %02d', $sign, intdiv($absolute, 60), $absolute % 60);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user