246 lines
8.1 KiB
PHP
246 lines
8.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\State;
|
|
|
|
use ApiPlatform\Metadata\Operation;
|
|
use ApiPlatform\State\ProviderInterface;
|
|
use App\Enum\ContractNature;
|
|
use App\Enum\HalfDay;
|
|
use App\Repository\AbsenceRepository;
|
|
use App\Repository\EmployeeRepository;
|
|
use App\Service\PublicHolidayServiceInterface;
|
|
use DateInterval;
|
|
use DateTimeImmutable;
|
|
use Dompdf\Dompdf;
|
|
use Dompdf\Options;
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Throwable;
|
|
use Twig\Environment;
|
|
use Twig\Error\LoaderError;
|
|
use Twig\Error\RuntimeError;
|
|
use Twig\Error\SyntaxError;
|
|
|
|
class AbsencePrintProvider implements ProviderInterface
|
|
{
|
|
public function __construct(
|
|
private Environment $twig,
|
|
private readonly RequestStack $requestStack,
|
|
private EmployeeRepository $employeeRepository,
|
|
private AbsenceRepository $absenceRepository,
|
|
private PublicHolidayServiceInterface $publicHolidayService,
|
|
) {}
|
|
|
|
/**
|
|
* @throws SyntaxError
|
|
* @throws RuntimeError
|
|
* @throws LoaderError
|
|
*/
|
|
public function provide(Operation $operation, array $uriVariables = [], array $context = []): Response
|
|
{
|
|
$request = $this->requestStack->getCurrentRequest();
|
|
if (!$request) {
|
|
return new Response('Missing request.', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$from = $request->query->get('from');
|
|
$to = $request->query->get('to');
|
|
if (!$from || !$to) {
|
|
return new Response('Missing from/to query params.', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$fromDate = DateTimeImmutable::createFromFormat('Y-m-d', $from);
|
|
$toDate = DateTimeImmutable::createFromFormat('Y-m-d', $to);
|
|
|
|
$siteIds = $this->parseIds($request->query->get('sites'));
|
|
$workContractIds = $this->parseIds($request->query->get('workContracts'));
|
|
$contractNatures = $this->parseContractNatures($request->query->get('contractNatures'));
|
|
|
|
$employees = $this->loadEmployees($siteIds, $contractNatures, $workContractIds);
|
|
$absences = $this->loadAbsences($fromDate, $toDate, $employees);
|
|
|
|
$days = $this->buildDays($fromDate, $toDate);
|
|
$absenceMap = $this->buildAbsenceMap($absences, $fromDate, $toDate);
|
|
$holidayMap = $this->buildHolidayMap($fromDate, $toDate);
|
|
|
|
$options = new Options();
|
|
$options->set('isRemoteEnabled', true);
|
|
|
|
$dompdf = new Dompdf($options);
|
|
$html = $this->twig->render('absence/print.html.twig', [
|
|
'from' => $fromDate,
|
|
'to' => $toDate,
|
|
'days' => $days,
|
|
'employees' => $employees,
|
|
'absenceMap' => $absenceMap,
|
|
'holidayMap' => $holidayMap,
|
|
]);
|
|
|
|
$dompdf->loadHtml($html);
|
|
$dompdf->setPaper('A3', 'landscape');
|
|
$dompdf->render();
|
|
|
|
$filename = sprintf(
|
|
'absences_du_%s_au_%s.pdf',
|
|
$fromDate->format('d-m-Y'),
|
|
$toDate->format('d-m-Y')
|
|
);
|
|
|
|
return new Response($dompdf->output(), Response::HTTP_OK, [
|
|
'Content-Type' => 'application/pdf',
|
|
'Content-Disposition' => 'inline; filename="'.$filename.'"',
|
|
]);
|
|
}
|
|
|
|
private function parseIds(?string $value): array
|
|
{
|
|
if (null === $value || '' === trim($value)) {
|
|
return [];
|
|
}
|
|
|
|
$ids = [];
|
|
foreach (explode(',', $value) as $part) {
|
|
$id = (int) trim($part);
|
|
if ($id > 0) {
|
|
$ids[] = $id;
|
|
}
|
|
}
|
|
|
|
return array_values(array_unique($ids));
|
|
}
|
|
|
|
private function loadEmployees(array $siteIds, array $contractNatures, array $workContractIds): array
|
|
{
|
|
$employees = $this->employeeRepository->findForPrintBySiteIds($siteIds);
|
|
|
|
return array_values(array_filter($employees, static function ($employee) use ($contractNatures, $workContractIds): bool {
|
|
$employeeNature = (string) $employee->getCurrentContractNature();
|
|
$employeeContractId = $employee->getContract()?->getId();
|
|
|
|
$natureMatches = [] === $contractNatures || in_array($employeeNature, $contractNatures, true);
|
|
$contractMatches = [] === $workContractIds || (null !== $employeeContractId && in_array($employeeContractId, $workContractIds, true));
|
|
|
|
return $natureMatches && $contractMatches;
|
|
}));
|
|
}
|
|
|
|
private function loadAbsences(DateTimeImmutable $from, DateTimeImmutable $to, array $employees): array
|
|
{
|
|
return $this->absenceRepository->findForPrint($from, $to, $employees);
|
|
}
|
|
|
|
private function buildDays(DateTimeImmutable $from, DateTimeImmutable $to): array
|
|
{
|
|
$days = [];
|
|
$current = $from;
|
|
|
|
while ($current <= $to) {
|
|
$days[] = [
|
|
'date' => $current->format('Y-m-d'),
|
|
'label' => $current->format('d'),
|
|
];
|
|
|
|
$current = $current->add(new DateInterval('P1D'));
|
|
}
|
|
|
|
return $days;
|
|
}
|
|
|
|
private function buildAbsenceMap(array $absences, DateTimeImmutable $from, DateTimeImmutable $to): array
|
|
{
|
|
$map = [];
|
|
|
|
foreach ($absences as $absence) {
|
|
$employeeId = $absence->getEmployee()?->getId();
|
|
$type = $absence->getType();
|
|
|
|
if (!$employeeId || !$type) {
|
|
continue;
|
|
}
|
|
|
|
$absenceStart = DateTimeImmutable::createFromInterface($absence->getStartDate());
|
|
$absenceEnd = DateTimeImmutable::createFromInterface($absence->getEndDate());
|
|
$startHalf = $absence->getStartHalf();
|
|
$endHalf = $absence->getEndHalf();
|
|
|
|
$start = max($absenceStart, $from);
|
|
$end = min($absenceEnd, $to);
|
|
|
|
$current = $start;
|
|
while ($current <= $end) {
|
|
$dateKey = $current->format('Y-m-d');
|
|
$isSameDay = $absenceStart->format('Y-m-d') === $absenceEnd->format('Y-m-d');
|
|
$isStartDay = $current->format('Y-m-d') === $absenceStart->format('Y-m-d');
|
|
$isEndDay = $current->format('Y-m-d') === $absenceEnd->format('Y-m-d');
|
|
$halfLabel = null;
|
|
|
|
if ($isSameDay) {
|
|
if ($startHalf === $endHalf) {
|
|
$halfLabel = $startHalf->value;
|
|
}
|
|
} else {
|
|
if ($isStartDay && HalfDay::PM === $startHalf) {
|
|
$halfLabel = 'PM';
|
|
}
|
|
if ($isEndDay && HalfDay::AM === $endHalf) {
|
|
$halfLabel = 'AM';
|
|
}
|
|
}
|
|
|
|
$map[$employeeId][$dateKey] = [
|
|
'code' => (string) $type->getCode(),
|
|
'color' => (string) $type->getColor(),
|
|
'half' => null !== $halfLabel,
|
|
'halfLabel' => $halfLabel,
|
|
];
|
|
|
|
$current = $current->add(new DateInterval('P1D'));
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
private function buildHolidayMap(DateTimeImmutable $from, DateTimeImmutable $to): array
|
|
{
|
|
$map = [];
|
|
$startYear = (int) $from->format('Y');
|
|
$endYear = (int) $to->format('Y');
|
|
|
|
try {
|
|
for ($year = $startYear; $year <= $endYear; ++$year) {
|
|
$holidays = $this->publicHolidayService->getHolidaysDayByYears('metropole', (string) $year);
|
|
foreach ($holidays as $date => $label) {
|
|
$map[$date] = (string) $label;
|
|
}
|
|
}
|
|
} catch (Throwable) {
|
|
return [];
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
/**
|
|
* @return list<string>
|
|
*/
|
|
private function parseContractNatures(?string $value): array
|
|
{
|
|
if (null === $value || '' === trim($value)) {
|
|
return [];
|
|
}
|
|
|
|
$values = [];
|
|
foreach (explode(',', $value) as $part) {
|
|
$nature = strtoupper(trim($part));
|
|
if (null !== ContractNature::tryFrom($nature)) {
|
|
$values[] = $nature;
|
|
}
|
|
}
|
|
|
|
return array_values(array_unique($values));
|
|
}
|
|
}
|