146 lines
4.8 KiB
PHP
146 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\State;
|
|
|
|
use ApiPlatform\Metadata\Operation;
|
|
use ApiPlatform\State\ProviderInterface;
|
|
use App\ApiResource\EmployeeLeaveRecap;
|
|
use App\Entity\Contract;
|
|
use App\Entity\Employee;
|
|
use App\Entity\User;
|
|
use App\Enum\ContractType;
|
|
use App\Repository\EmployeeRepository;
|
|
use App\Security\EmployeeScopeService;
|
|
use App\Service\Leave\LeaveRecapRowBuilder;
|
|
use App\Util\LeaveRecapCutoff;
|
|
use DateTimeImmutable;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Bundle\SecurityBundle\Security;
|
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
|
|
final readonly class EmployeeLeaveRecapProvider implements ProviderInterface
|
|
{
|
|
public function __construct(
|
|
private Security $security,
|
|
private EmployeeRepository $employeeRepository,
|
|
private EmployeeScopeService $employeeScopeService,
|
|
private LeaveRecapRowBuilder $rowBuilder,
|
|
private EntityManagerInterface $entityManager,
|
|
) {}
|
|
|
|
/**
|
|
* @return list<EmployeeLeaveRecap>
|
|
*/
|
|
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
|
{
|
|
$user = $this->security->getUser();
|
|
if (!$user instanceof User) {
|
|
throw new AccessDeniedHttpException('Authentication required.');
|
|
}
|
|
|
|
if (!$user->hasLeaveRecapAccess()) {
|
|
throw new AccessDeniedHttpException('Leave recap access not granted.');
|
|
}
|
|
|
|
$cutoff = LeaveRecapCutoff::resolveCutoff(new DateTimeImmutable('today'));
|
|
$cutoffYmd = $cutoff->format('Y-m-d');
|
|
$employees = $this->resolveScopedEmployees($user);
|
|
$rows = [];
|
|
|
|
foreach ($employees as $employee) {
|
|
if (!$employee->getHasActiveContract()) {
|
|
continue;
|
|
}
|
|
|
|
$row = $this->rowBuilder->build($employee, $cutoff);
|
|
|
|
$resource = new EmployeeLeaveRecap();
|
|
$resource->employeeId = (int) $employee->getId();
|
|
$resource->lastName = $row['lastName'] ?? '';
|
|
$resource->firstName = $row['firstName'] ?? '';
|
|
$site = $employee->getSite();
|
|
$resource->siteId = $site?->getId();
|
|
$resource->siteName = $site?->getName();
|
|
$resource->siteColor = $site?->getColor();
|
|
$resource->contractName = $row['contractName'] ?? null;
|
|
$resource->contractSortKey = $this->resolveContractSortKey($employee->getContract());
|
|
$resource->cpN1Remaining = is_numeric($row['cpN1Remaining']) ? (float) $row['cpN1Remaining'] : 0.0;
|
|
$resource->cpN = (string) $row['cpN'];
|
|
$resource->acquiredSaturdays = (string) $row['acquiredSaturdays'];
|
|
$resource->rtt = (string) $row['rtt'];
|
|
$resource->cutoffDate = $cutoffYmd;
|
|
|
|
$rows[] = $resource;
|
|
$this->entityManager->clear();
|
|
}
|
|
|
|
usort($rows, static function (EmployeeLeaveRecap $a, EmployeeLeaveRecap $b): int {
|
|
$siteCmp = strcmp((string) ($a->siteName ?? 'zzz'), (string) ($b->siteName ?? 'zzz'));
|
|
if (0 !== $siteCmp) {
|
|
return $siteCmp;
|
|
}
|
|
$contractCmp = $a->contractSortKey <=> $b->contractSortKey;
|
|
if (0 !== $contractCmp) {
|
|
return $contractCmp;
|
|
}
|
|
$lastCmp = strcmp($a->lastName, $b->lastName);
|
|
if (0 !== $lastCmp) {
|
|
return $lastCmp;
|
|
}
|
|
|
|
return strcmp($a->firstName, $b->firstName);
|
|
});
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* Sort order: FORFAIT → 39h → 35h → 25h → 4h → autres.
|
|
*/
|
|
private function resolveContractSortKey(?Contract $contract): int
|
|
{
|
|
if (null === $contract) {
|
|
return 99;
|
|
}
|
|
|
|
if (ContractType::FORFAIT === $contract->getType()) {
|
|
return 0;
|
|
}
|
|
|
|
$weeklyHours = $contract->getWeeklyHours();
|
|
|
|
return match ($weeklyHours) {
|
|
39 => 1,
|
|
35 => 2,
|
|
25 => 3,
|
|
4 => 4,
|
|
default => 99,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @return list<Employee>
|
|
*/
|
|
private function resolveScopedEmployees(User $user): array
|
|
{
|
|
if (in_array('ROLE_ADMIN', $user->getRoles(), true)) {
|
|
return $this->employeeRepository->findForPrintBySiteIds([]);
|
|
}
|
|
|
|
if (in_array('ROLE_SELF', $user->getRoles(), true)) {
|
|
$employee = $user->getEmployee();
|
|
|
|
return $employee instanceof Employee ? [$employee] : [];
|
|
}
|
|
|
|
$siteIds = $this->employeeScopeService->getAllowedSiteIds($user);
|
|
if ([] === $siteIds) {
|
|
return [];
|
|
}
|
|
|
|
return $this->employeeRepository->findForPrintBySiteIds($siteIds);
|
|
}
|
|
}
|