530 lines
24 KiB
PHP
530 lines
24 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Controllers;
|
||
|
||
use App\Core\Access;
|
||
use App\Core\Csrf;
|
||
use App\Core\JsonResponse;
|
||
use App\Core\PdfResponse;
|
||
use App\Core\Request;
|
||
use App\Models\AgentModel;
|
||
use App\Models\QuotaModel;
|
||
use App\Models\StructureModel;
|
||
use App\Services\AgentHoursContractPdfService;
|
||
use App\Services\AgentTimeSummaryPdfService;
|
||
use App\Services\PlanningPdfService;
|
||
use DateTimeImmutable;
|
||
use PDO;
|
||
use Throwable;
|
||
|
||
final class AgentController
|
||
{
|
||
private AgentModel $agentModel;
|
||
private StructureModel $structureModel;
|
||
private QuotaModel $quotaModel;
|
||
private Access $access;
|
||
|
||
public function __construct(private PDO $pdo)
|
||
{
|
||
$this->agentModel = new AgentModel($pdo);
|
||
$this->structureModel = new StructureModel($pdo);
|
||
$this->quotaModel = new QuotaModel($pdo);
|
||
$this->access = new Access($pdo);
|
||
}
|
||
|
||
public function listForPlanning(): void
|
||
{
|
||
$this->access->requireDraftEditor();
|
||
$selectedLocation = filter_input(INPUT_GET, 'structure_id', FILTER_VALIDATE_INT) ?: 0;
|
||
if ($selectedLocation) {
|
||
$this->access->requireStructureEdit((int) $selectedLocation);
|
||
}
|
||
JsonResponse::send(200, ['agents' => $this->agentModel->listForLocation((int) $selectedLocation)]);
|
||
}
|
||
|
||
public function overview(): void
|
||
{
|
||
$agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT);
|
||
$weekValue = trim((string) ($_GET['week'] ?? ''));
|
||
$week = $this->parseWeek($weekValue);
|
||
|
||
if (!$agentId || $week === null) {
|
||
JsonResponse::send(400, ['error' => 'Agent ou semaine invalide.']);
|
||
}
|
||
$this->access->requireAgentView((int) $agentId);
|
||
|
||
$agent = $this->agentModel->findActive((int) $agentId);
|
||
if ($agent === null) {
|
||
JsonResponse::send(404, ['error' => 'Agent introuvable.']);
|
||
}
|
||
|
||
[$year, $weekNumber] = $week;
|
||
$weekStart = (new DateTimeImmutable())->setISODate($year, $weekNumber, 1)->format('Y-m-d');
|
||
$weekEnd = (new DateTimeImmutable())->setISODate($year, $weekNumber, 7)->format('Y-m-d');
|
||
|
||
JsonResponse::send(200, [
|
||
'agent' => $agent,
|
||
'week' => ['value' => $weekValue, 'date_debut' => $weekStart, 'date_fin' => $weekEnd],
|
||
'quota' => $this->quotaModel->forDateForApi((int) $agentId, $weekStart),
|
||
'entries' => $this->agentModel->entriesForWeek((int) $agentId, $year, $weekNumber),
|
||
]);
|
||
}
|
||
|
||
public function monthOverview(): void
|
||
{
|
||
$agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT);
|
||
$monthValue = trim((string) ($_GET['month'] ?? ''));
|
||
|
||
if (!$agentId || !preg_match('/^(\d{4})-(\d{2})$/', $monthValue, $matches)) {
|
||
JsonResponse::send(400, ['error' => 'Agent ou mois invalide.']);
|
||
}
|
||
$this->access->requireAgentView((int) $agentId);
|
||
|
||
$year = (int) $matches[1];
|
||
$monthNumber = (int) $matches[2];
|
||
if ($monthNumber < 1 || $monthNumber > 12) {
|
||
JsonResponse::send(400, ['error' => 'Mois invalide.']);
|
||
}
|
||
|
||
$agent = $this->agentModel->findActive((int) $agentId);
|
||
if ($agent === null) {
|
||
JsonResponse::send(404, ['error' => 'Agent introuvable.']);
|
||
}
|
||
|
||
$firstDay = new DateTimeImmutable(sprintf('%04d-%02d-01', $year, $monthNumber));
|
||
$lastDay = $firstDay->modify('last day of this month');
|
||
$gridStart = $firstDay->modify('-' . ((int) $firstDay->format('N') - 1) . ' days');
|
||
$lastWeekMonday = $lastDay->modify('-' . ((int) $lastDay->format('N') - 1) . ' days');
|
||
$gridEnd = $lastWeekMonday->modify('+4 days');
|
||
|
||
$dayLabels = [1 => 'Lundi', 2 => 'Mardi', 3 => 'Mercredi', 4 => 'Jeudi', 5 => 'Vendredi'];
|
||
$monthLabels = [
|
||
1 => 'Janvier', 2 => 'Février', 3 => 'Mars', 4 => 'Avril', 5 => 'Mai', 6 => 'Juin',
|
||
7 => 'Juillet', 8 => 'Août', 9 => 'Septembre', 10 => 'Octobre', 11 => 'Novembre', 12 => 'Décembre',
|
||
];
|
||
$weeks = [];
|
||
|
||
for ($monday = $gridStart; $monday <= $lastWeekMonday; $monday = $monday->modify('+7 days')) {
|
||
$days = [];
|
||
for ($weekday = 1; $weekday <= 5; $weekday++) {
|
||
$date = $monday->modify('+' . ($weekday - 1) . ' days');
|
||
$days[] = [
|
||
'date' => $date->format('Y-m-d'),
|
||
'label' => $dayLabels[$weekday],
|
||
'display' => $date->format('d/m'),
|
||
'in_month' => (int) $date->format('n') === $monthNumber,
|
||
];
|
||
}
|
||
$weeks[] = [
|
||
'value' => sprintf('%04d-W%02d', (int) $monday->format('o'), (int) $monday->format('W')),
|
||
'number' => (int) $monday->format('W'),
|
||
'date_debut' => $monday->format('Y-m-d'),
|
||
'date_fin' => $monday->modify('+4 days')->format('Y-m-d'),
|
||
'days' => $days,
|
||
];
|
||
}
|
||
|
||
JsonResponse::send(200, [
|
||
'agent' => $agent,
|
||
'month' => [
|
||
'value' => $monthValue,
|
||
'year' => $year,
|
||
'month' => $monthNumber,
|
||
'label' => $monthLabels[$monthNumber] . ' ' . $year,
|
||
'date_debut' => $firstDay->format('Y-m-d'),
|
||
'date_fin' => $lastDay->format('Y-m-d'),
|
||
'grid_start' => $gridStart->format('Y-m-d'),
|
||
'grid_end' => $gridEnd->format('Y-m-d'),
|
||
],
|
||
'weeks' => $weeks,
|
||
'quota' => $this->quotaModel->forDateForApi((int) $agentId, $firstDay->format('Y-m-d')),
|
||
'entries' => $this->agentModel->entriesForDateRange(
|
||
(int) $agentId,
|
||
$gridStart->format('Y-m-d'),
|
||
$gridEnd->format('Y-m-d')
|
||
),
|
||
]);
|
||
}
|
||
|
||
public function timeSummaryPdf(): void
|
||
{
|
||
$agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT);
|
||
$dateValue = trim((string) ($_GET['date'] ?? ''));
|
||
$year = filter_input(INPUT_GET, 'year', FILTER_VALIDATE_INT);
|
||
|
||
if ($dateValue === '' && $year) {
|
||
$dateValue = sprintf('%04d-01-01', (int) $year);
|
||
}
|
||
$date = DateTimeImmutable::createFromFormat('!Y-m-d', $dateValue);
|
||
|
||
if (!$agentId || !$date || $date->format('Y-m-d') !== $dateValue) {
|
||
http_response_code(400);
|
||
echo 'Agent ou date de référence invalide.';
|
||
return;
|
||
}
|
||
$this->access->requireAgentView((int) $agentId);
|
||
|
||
$agent = $this->agentModel->findActive((int) $agentId);
|
||
if ($agent === null) {
|
||
http_response_code(404);
|
||
echo 'Agent introuvable.';
|
||
return;
|
||
}
|
||
|
||
$quota = $this->quotaModel->forDateForApi((int) $agentId, $dateValue);
|
||
$summary = $this->agentModel->timeSummaryForRange(
|
||
(int) $agentId,
|
||
(string) $quota['date_debut_periode'],
|
||
(string) $quota['date_fin_periode']
|
||
);
|
||
$pdf = (new AgentTimeSummaryPdfService())->annualSummary($agent, $quota, $summary);
|
||
|
||
PdfResponse::inline(
|
||
$pdf,
|
||
sprintf(
|
||
'bilan_heures_%s_%s_%s_%s.pdf',
|
||
$agent['nom'],
|
||
$agent['prenom'],
|
||
str_replace('-', '', (string) $quota['date_debut_periode']),
|
||
str_replace('-', '', (string) $quota['date_fin_periode'])
|
||
)
|
||
);
|
||
}
|
||
|
||
public function pdf(): void
|
||
{
|
||
$agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT);
|
||
$weekValue = trim((string) ($_GET['week'] ?? ''));
|
||
$week = $this->parseWeek($weekValue);
|
||
$weekCount = filter_input(INPUT_GET, 'weeks', FILTER_VALIDATE_INT) ?: 7;
|
||
$weekCount = in_array((int) $weekCount, [6, 7], true) ? (int) $weekCount : 7;
|
||
|
||
if (!$agentId || $week === null) {
|
||
http_response_code(400);
|
||
echo 'Agent ou semaine invalide.';
|
||
return;
|
||
}
|
||
$this->access->requireAgentView((int) $agentId);
|
||
|
||
$agent = $this->agentModel->findActive((int) $agentId);
|
||
if ($agent === null) {
|
||
http_response_code(404);
|
||
echo 'Agent introuvable.';
|
||
return;
|
||
}
|
||
|
||
[$year, $weekNumber] = $week;
|
||
$firstMonday = (new DateTimeImmutable())->setISODate($year, $weekNumber, 1);
|
||
$weeks = [];
|
||
|
||
for ($index = 0; $index < $weekCount; $index++) {
|
||
$monday = $firstMonday->modify('+' . ($index * 7) . ' days');
|
||
$isoYear = (int) $monday->format('o');
|
||
$isoWeek = (int) $monday->format('W');
|
||
$weeks[] = [
|
||
'value' => sprintf('%04d-W%02d', $isoYear, $isoWeek),
|
||
'date_debut' => $monday->format('Y-m-d'),
|
||
'date_fin' => $monday->modify('+6 days')->format('Y-m-d'),
|
||
];
|
||
}
|
||
|
||
$lastFriday = $firstMonday->modify('+' . (($weekCount - 1) * 7 + 4) . ' days');
|
||
$entries = $this->agentModel->entriesForDateRange(
|
||
(int) $agentId,
|
||
$firstMonday->format('Y-m-d'),
|
||
$lastFriday->format('Y-m-d')
|
||
);
|
||
|
||
$pdf = (new PlanningPdfService())->agentWeeks(
|
||
$agent,
|
||
$entries,
|
||
$weeks,
|
||
$this->quotaModel->forDateForApi((int) $agentId, $firstMonday->format('Y-m-d'))
|
||
);
|
||
|
||
PdfResponse::inline(
|
||
$pdf,
|
||
sprintf(
|
||
'planning_%s_%s_%s_%d_semaines.pdf',
|
||
$agent['nom'],
|
||
$agent['prenom'],
|
||
str_replace('-W', '_S', $weekValue),
|
||
$weekCount
|
||
)
|
||
);
|
||
}
|
||
|
||
public function hoursContractPdf(): void
|
||
{
|
||
$agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT);
|
||
$dateValue = trim((string) ($_GET['date'] ?? ''));
|
||
$year = filter_input(INPUT_GET, 'year', FILTER_VALIDATE_INT);
|
||
|
||
if ($dateValue === '' && $year) {
|
||
$dateValue = sprintf('%04d-01-01', (int) $year);
|
||
}
|
||
$date = DateTimeImmutable::createFromFormat('!Y-m-d', $dateValue);
|
||
|
||
if (!$agentId || !$date || $date->format('Y-m-d') !== $dateValue) {
|
||
http_response_code(400);
|
||
echo 'Agent ou date de référence invalide.';
|
||
return;
|
||
}
|
||
$this->access->requireAgentView((int) $agentId);
|
||
|
||
$agent = $this->agentModel->findActive((int) $agentId);
|
||
if ($agent === null) {
|
||
http_response_code(404);
|
||
echo 'Agent introuvable.';
|
||
return;
|
||
}
|
||
|
||
$quota = $this->quotaModel->forDateForApi((int) $agentId, $dateValue);
|
||
$pdf = (new AgentHoursContractPdfService())->annualContract($agent, $quota);
|
||
|
||
PdfResponse::inline(
|
||
$pdf,
|
||
sprintf(
|
||
'contrat_horaire_%s_%s_%s.pdf',
|
||
$agent['nom'],
|
||
$agent['prenom'],
|
||
str_replace('-', '', (string) $quota['date_debut_periode'])
|
||
)
|
||
);
|
||
}
|
||
|
||
public function assignments(): void
|
||
{
|
||
$this->access->requireService();
|
||
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET') {
|
||
JsonResponse::send(200, ['agents' => $this->agentModel->allActive()]);
|
||
}
|
||
|
||
Request::requireMethod('POST');
|
||
$payload = Request::json();
|
||
Csrf::assertPayload($payload);
|
||
|
||
$agentId = filter_var($payload['agent_id'] ?? null, FILTER_VALIDATE_INT);
|
||
$rawStructure = $payload['structure_id'] ?? null;
|
||
$structureId = ($rawStructure === null || $rawStructure === '' || $rawStructure === 0)
|
||
? null
|
||
: filter_var($rawStructure, FILTER_VALIDATE_INT);
|
||
if (!$agentId) {
|
||
JsonResponse::send(422, ['error' => 'Agent invalide.']);
|
||
}
|
||
if ($this->agentModel->findActive((int) $agentId) === null) {
|
||
JsonResponse::send(404, ['error' => 'Agent introuvable.']);
|
||
}
|
||
if ($structureId !== null && $this->structureModel->findActive((int) $structureId) === null) {
|
||
JsonResponse::send(422, ['error' => 'Lieu d’affectation invalide ou inactif.']);
|
||
}
|
||
|
||
try {
|
||
$this->agentModel->updateAssignment((int) $agentId, $structureId !== null ? (int) $structureId : null);
|
||
} catch (Throwable $e) {
|
||
JsonResponse::send(500, [
|
||
'error' => 'Impossible de modifier les paramètres de l’agent.',
|
||
'details' => (getenv('PTA_DEBUG') ?: '1') !== '0' ? $e->getMessage() : null,
|
||
]);
|
||
}
|
||
|
||
JsonResponse::send(200, [
|
||
'message' => $structureId === null
|
||
? 'Les paramètres de l’agent ont été mis à jour sans lieu principal.'
|
||
: 'Le lieu principal de l’agent a été mis à jour.',
|
||
]);
|
||
}
|
||
|
||
public function create(): void
|
||
{
|
||
$this->access->requireService();
|
||
Request::requireMethod('POST');
|
||
$payload = Request::json();
|
||
Csrf::assertPayload($payload);
|
||
|
||
$matricule = trim((string) ($payload['matricule'] ?? ''));
|
||
$nom = trim((string) ($payload['nom'] ?? ''));
|
||
$prenom = trim((string) ($payload['prenom'] ?? ''));
|
||
$email = trim((string) ($payload['email'] ?? ''));
|
||
$telephone = trim((string) ($payload['telephone'] ?? ''));
|
||
$adresse = trim((string) ($payload['adresse'] ?? ''));
|
||
$estDiplome = filter_var($payload['est_diplome'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||
$diplomeLibelle = trim((string) ($payload['diplome_libelle'] ?? ''));
|
||
$structureId = filter_var($payload['structure_id'] ?? null, FILTER_VALIDATE_INT);
|
||
$rate = filter_var($payload['quotite_travail'] ?? null, FILTER_VALIDATE_FLOAT);
|
||
$contractStart = trim((string) ($payload['date_debut_contrat'] ?? ''));
|
||
$contractStartDate = DateTimeImmutable::createFromFormat('!Y-m-d', $contractStart);
|
||
$contractEnd = trim((string) ($payload['date_fin_contrat'] ?? ''));
|
||
$contractEndDate = $contractEnd !== '' ? DateTimeImmutable::createFromFormat('!Y-m-d', $contractEnd) : null;
|
||
$postId = filter_var($payload['id_poste'] ?? null, FILTER_VALIDATE_INT);
|
||
$contractType = strtoupper(trim((string) ($payload['type_contrat'] ?? 'PERMANENT')));
|
||
$trainingPlanned = filter_var($payload['formation_repartition_annuelle'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||
$ptaComment = trim((string) ($payload['commentaire_pta'] ?? ''));
|
||
$validPostIds = array_map(static fn(array $post): int => (int) $post['id_poste'], $this->agentModel->allPosts());
|
||
|
||
if ($matricule === '' || $nom === '' || $prenom === '' || !$structureId || !$postId
|
||
|| !in_array((int) $postId, $validPostIds, true)
|
||
|| !in_array($contractType, ['PERMANENT', 'TEMPORAIRE'], true)
|
||
|| !$contractStartDate || $contractStartDate->format('Y-m-d') !== $contractStart
|
||
|| ($contractEnd !== '' && (!$contractEndDate || $contractEndDate->format('Y-m-d') !== $contractEnd || $contractEndDate < $contractStartDate))) {
|
||
JsonResponse::send(422, ['error' => 'Le matricule, le nom, le prénom, le poste, le type de contrat, le lieu principal et des dates de contrat cohérentes sont obligatoires.']);
|
||
}
|
||
if ($rate === false || $rate <= 0 || $rate > 100) {
|
||
JsonResponse::send(422, ['error' => 'La quotité de travail doit être comprise entre 1 et 100 %.']);
|
||
}
|
||
if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
||
JsonResponse::send(422, ['error' => 'L’adresse e-mail saisie n’est pas valide.']);
|
||
}
|
||
if (strlen($matricule) > 50 || strlen($nom) > 100 || strlen($prenom) > 100 || strlen($email) > 255
|
||
|| strlen($telephone) > 30 || strlen($adresse) > 255 || strlen($diplomeLibelle) > 150 || strlen($ptaComment) > 1000) {
|
||
JsonResponse::send(422, ['error' => 'Un des champs dépasse la longueur autorisée.']);
|
||
}
|
||
if ($this->structureModel->findActive((int) $structureId) === null) {
|
||
JsonResponse::send(422, ['error' => 'Le lieu d’affectation principal sélectionné est invalide ou inactif.']);
|
||
}
|
||
if ($this->agentModel->matriculeExists($matricule)) {
|
||
JsonResponse::send(409, ['error' => 'Un agent utilise déjà ce matricule.']);
|
||
}
|
||
|
||
try {
|
||
$created = $this->agentModel->createWithDefaults([
|
||
'matricule' => $matricule,
|
||
'nom' => $nom,
|
||
'prenom' => $prenom,
|
||
'email' => $email !== '' ? $email : null,
|
||
'telephone' => $telephone !== '' ? $telephone : null,
|
||
'adresse' => $adresse !== '' ? $adresse : null,
|
||
'est_diplome' => $estDiplome,
|
||
'diplome_libelle' => $estDiplome && $diplomeLibelle !== '' ? $diplomeLibelle : null,
|
||
'structure_id' => (int) $structureId,
|
||
'quotite_travail' => (float) $rate,
|
||
'date_debut_contrat' => $contractStart,
|
||
'date_fin_contrat' => $contractEnd !== '' ? $contractEnd : null,
|
||
'id_poste' => (int) $postId,
|
||
'type_contrat' => $contractType,
|
||
'formation_repartition_annuelle' => $trainingPlanned,
|
||
'commentaire_pta' => $ptaComment !== '' ? $ptaComment : null,
|
||
]);
|
||
} catch (Throwable $e) {
|
||
JsonResponse::send(500, [
|
||
'error' => 'Impossible de créer l’agent.',
|
||
'details' => (getenv('PTA_DEBUG') ?: '1') !== '0' ? $e->getMessage() : null,
|
||
]);
|
||
}
|
||
|
||
$structure = $this->structureModel->findActive((int) $structureId);
|
||
JsonResponse::send(201, [
|
||
'message' => sprintf('%s %s a été ajouté avec le lieu principal « %s ».', $prenom, $nom, $structure['nom']),
|
||
'agent' => array_merge($created, [
|
||
'matricule' => $matricule,
|
||
'nom' => $nom,
|
||
'prenom' => $prenom,
|
||
'email' => $email !== '' ? $email : null,
|
||
'telephone' => $telephone !== '' ? $telephone : null,
|
||
'adresse' => $adresse !== '' ? $adresse : null,
|
||
'est_diplome' => $estDiplome ? 1 : 0,
|
||
'diplome_libelle' => $estDiplome && $diplomeLibelle !== '' ? $diplomeLibelle : null,
|
||
'id_structure' => (int) $structureId,
|
||
'structure_nom' => (string) $structure['nom'],
|
||
'structure_type_affectation' => (string) $structure['type_affectation'],
|
||
'quotite_travail' => (float) $rate,
|
||
'date_debut_contrat' => $contractStart,
|
||
'date_fin_contrat' => $contractEnd !== '' ? $contractEnd : null,
|
||
'id_poste' => (int) $postId,
|
||
'poste_libelle' => (string) (array_values(array_filter($this->agentModel->allPosts(), static fn(array $post): bool => (int) $post['id_poste'] === (int) $postId))[0]['libelle'] ?? ''),
|
||
'type_contrat' => $contractType,
|
||
'formation_repartition_annuelle' => $trainingPlanned ? 1 : 0,
|
||
'commentaire_pta' => $ptaComment !== '' ? $ptaComment : null,
|
||
]),
|
||
]);
|
||
}
|
||
|
||
public function updateProfile(): void
|
||
{
|
||
$this->access->requireService();
|
||
Request::requireMethod('POST');
|
||
$payload = Request::json();
|
||
Csrf::assertPayload($payload);
|
||
|
||
$agentId = filter_var($payload['agent_id'] ?? null, FILTER_VALIDATE_INT);
|
||
$email = trim((string) ($payload['email'] ?? ''));
|
||
$telephone = trim((string) ($payload['telephone'] ?? ''));
|
||
$adresse = trim((string) ($payload['adresse'] ?? ''));
|
||
$estDiplome = filter_var($payload['est_diplome'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||
$diplomeLibelle = trim((string) ($payload['diplome_libelle'] ?? ''));
|
||
$contractStart = trim((string) ($payload['date_debut_contrat'] ?? ''));
|
||
$contractStartDate = DateTimeImmutable::createFromFormat('!Y-m-d', $contractStart);
|
||
$contractEnd = trim((string) ($payload['date_fin_contrat'] ?? ''));
|
||
$contractEndDate = $contractEnd !== '' ? DateTimeImmutable::createFromFormat('!Y-m-d', $contractEnd) : null;
|
||
$postId = filter_var($payload['id_poste'] ?? null, FILTER_VALIDATE_INT);
|
||
$contractType = strtoupper(trim((string) ($payload['type_contrat'] ?? 'PERMANENT')));
|
||
$trainingPlanned = filter_var($payload['formation_repartition_annuelle'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||
$ptaComment = trim((string) ($payload['commentaire_pta'] ?? ''));
|
||
$validPostIds = array_map(static fn(array $post): int => (int) $post['id_poste'], $this->agentModel->allPosts());
|
||
$rawStructure = $payload['structure_id'] ?? null;
|
||
$structureId = ($rawStructure === null || $rawStructure === '' || $rawStructure === 0)
|
||
? null
|
||
: filter_var($rawStructure, FILTER_VALIDATE_INT);
|
||
|
||
if (!$agentId) {
|
||
JsonResponse::send(422, ['error' => 'Agent invalide.']);
|
||
}
|
||
if ($this->agentModel->findActive((int) $agentId) === null) {
|
||
JsonResponse::send(404, ['error' => 'Agent introuvable.']);
|
||
}
|
||
if (!$postId || !in_array((int) $postId, $validPostIds, true)
|
||
|| !in_array($contractType, ['PERMANENT', 'TEMPORAIRE'], true)
|
||
|| !$contractStartDate || $contractStartDate->format('Y-m-d') !== $contractStart
|
||
|| ($contractEnd !== '' && (!$contractEndDate || $contractEndDate->format('Y-m-d') !== $contractEnd || $contractEndDate < $contractStartDate))) {
|
||
JsonResponse::send(422, ['error' => 'Le poste, le type de contrat et les dates du contrat doivent être valides.']);
|
||
}
|
||
if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
||
JsonResponse::send(422, ['error' => 'L’adresse e-mail saisie n’est pas valide.']);
|
||
}
|
||
if (strlen($email) > 255 || strlen($telephone) > 30 || strlen($adresse) > 255 || strlen($diplomeLibelle) > 150 || strlen($ptaComment) > 1000) {
|
||
JsonResponse::send(422, ['error' => 'Un des champs dépasse la longueur autorisée.']);
|
||
}
|
||
if ($structureId !== null && $this->structureModel->findActive((int) $structureId) === null) {
|
||
JsonResponse::send(422, ['error' => 'Lieu d’affectation principal invalide ou inactif.']);
|
||
}
|
||
|
||
try {
|
||
$this->agentModel->updateProfile((int) $agentId, [
|
||
'email' => $email !== '' ? $email : null,
|
||
'telephone' => $telephone !== '' ? $telephone : null,
|
||
'adresse' => $adresse !== '' ? $adresse : null,
|
||
'est_diplome' => $estDiplome,
|
||
'diplome_libelle' => $estDiplome && $diplomeLibelle !== '' ? $diplomeLibelle : null,
|
||
'date_debut_contrat' => $contractStart,
|
||
'date_fin_contrat' => $contractEnd !== '' ? $contractEnd : null,
|
||
'id_poste' => (int) $postId,
|
||
'type_contrat' => $contractType,
|
||
'formation_repartition_annuelle' => $trainingPlanned,
|
||
'commentaire_pta' => $ptaComment !== '' ? $ptaComment : null,
|
||
'structure_id' => $structureId !== null ? (int) $structureId : null,
|
||
]);
|
||
} catch (Throwable $e) {
|
||
JsonResponse::send(500, [
|
||
'error' => 'Impossible de modifier les informations de l’agent.',
|
||
'details' => (getenv('PTA_DEBUG') ?: '1') !== '0' ? $e->getMessage() : null,
|
||
]);
|
||
}
|
||
|
||
JsonResponse::send(200, [
|
||
'message' => 'Les informations de l’agent ont été mises à jour.',
|
||
'agent' => $this->agentModel->findActive((int) $agentId),
|
||
]);
|
||
}
|
||
|
||
private function parseWeek(string $value): ?array
|
||
{
|
||
if (!preg_match('/^(\d{4})-W(\d{2})$/', $value, $matches)) {
|
||
return null;
|
||
}
|
||
$week = (int) $matches[2];
|
||
return $week >= 1 && $week <= 53 ? [(int) $matches[1], $week] : null;
|
||
}
|
||
}
|