feat : ajout d'un onglet formation
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
This commit is contained in:
@@ -17,8 +17,16 @@ final class DayContextRow
|
||||
public int $creditedMinutes = 0,
|
||||
public float $creditedPresenceUnits = 0.0,
|
||||
public bool $isDriverContract = false,
|
||||
public bool $hasFormation = false,
|
||||
public ?string $formationLabel = null,
|
||||
) {}
|
||||
|
||||
public function setFormation(string $label): void
|
||||
{
|
||||
$this->hasFormation = true;
|
||||
$this->formationLabel = $label;
|
||||
}
|
||||
|
||||
public function addAbsence(
|
||||
?string $label,
|
||||
?string $color,
|
||||
@@ -64,7 +72,10 @@ final class DayContextRow
|
||||
* absentMorning:bool,
|
||||
* absentAfternoon:bool,
|
||||
* creditedMinutes:int,
|
||||
* creditedPresenceUnits:float
|
||||
* creditedPresenceUnits:float,
|
||||
* isDriverContract:bool,
|
||||
* hasFormation:bool,
|
||||
* formationLabel:?string
|
||||
* }
|
||||
*/
|
||||
public function toArray(): array
|
||||
@@ -80,6 +91,8 @@ final class DayContextRow
|
||||
'creditedMinutes' => $this->creditedMinutes,
|
||||
'creditedPresenceUnits' => $this->creditedPresenceUnits,
|
||||
'isDriverContract' => $this->isDriverContract,
|
||||
'hasFormation' => $this->hasFormation,
|
||||
'formationLabel' => $this->formationLabel,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
192
src/Entity/Formation.php
Normal file
192
src/Entity/Formation.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
|
||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
||||
use ApiPlatform\Metadata\ApiFilter;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use App\Repository\FormationRepository;
|
||||
use App\State\FormationDeleteProcessor;
|
||||
use App\State\FormationJustificatifDownloadProvider;
|
||||
use App\State\FormationJustificatifUploadProcessor;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new GetCollection(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new Post(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new Patch(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new Delete(
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
processor: FormationDeleteProcessor::class,
|
||||
),
|
||||
new Post(
|
||||
uriTemplate: '/formations/{id}/justificatif',
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
deserialize: false,
|
||||
processor: FormationJustificatifUploadProcessor::class,
|
||||
),
|
||||
new Get(
|
||||
uriTemplate: '/formations/{id}/justificatif',
|
||||
security: "is_granted('ROLE_ADMIN')",
|
||||
provider: FormationJustificatifDownloadProvider::class,
|
||||
),
|
||||
],
|
||||
normalizationContext: [
|
||||
'groups' => ['formation:read', 'employee:read'],
|
||||
'datetime_format' => 'Y-m-d',
|
||||
],
|
||||
denormalizationContext: [
|
||||
'groups' => ['formation:write'],
|
||||
'datetime_format' => 'Y-m-d',
|
||||
],
|
||||
order: ['startDate' => 'DESC'],
|
||||
paginationEnabled: false,
|
||||
)]
|
||||
#[ApiFilter(DateFilter::class, properties: ['startDate', 'endDate'])]
|
||||
#[ApiFilter(SearchFilter::class, properties: ['employee' => 'exact'])]
|
||||
#[ORM\Entity(repositoryClass: FormationRepository::class)]
|
||||
#[ORM\Table(name: 'formations')]
|
||||
class Formation
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[Groups(['formation:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Employee::class)]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[Groups(['formation:read', 'formation:write'])]
|
||||
private ?Employee $employee = null;
|
||||
|
||||
#[ORM\Column(type: 'date_immutable')]
|
||||
#[Groups(['formation:read', 'formation:write'])]
|
||||
private ?DateTimeImmutable $startDate = null;
|
||||
|
||||
#[ORM\Column(type: 'date_immutable')]
|
||||
#[Groups(['formation:read', 'formation:write'])]
|
||||
private ?DateTimeImmutable $endDate = null;
|
||||
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
#[Groups(['formation:read', 'formation:write'])]
|
||||
private ?string $comment = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
#[Groups(['formation:read'])]
|
||||
private ?string $justificatifPath = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
#[Groups(['formation:read'])]
|
||||
private ?string $justificatifName = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime_immutable')]
|
||||
#[Groups(['formation:read'])]
|
||||
private DateTimeImmutable $createdAt;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createdAt = new DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getEmployee(): ?Employee
|
||||
{
|
||||
return $this->employee;
|
||||
}
|
||||
|
||||
public function setEmployee(?Employee $employee): self
|
||||
{
|
||||
$this->employee = $employee;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStartDate(): ?DateTimeImmutable
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
public function setStartDate(?DateTimeImmutable $startDate): self
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEndDate(): ?DateTimeImmutable
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
public function setEndDate(?DateTimeImmutable $endDate): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getComment(): ?string
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
public function setComment(?string $comment): self
|
||||
{
|
||||
$this->comment = $comment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getJustificatifPath(): ?string
|
||||
{
|
||||
return $this->justificatifPath;
|
||||
}
|
||||
|
||||
public function setJustificatifPath(?string $justificatifPath): self
|
||||
{
|
||||
$this->justificatifPath = $justificatifPath;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getJustificatifName(): ?string
|
||||
{
|
||||
return $this->justificatifName;
|
||||
}
|
||||
|
||||
public function setJustificatifName(?string $justificatifName): self
|
||||
{
|
||||
$this->justificatifName = $justificatifName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
}
|
||||
26
src/Repository/Contract/FormationReadRepositoryInterface.php
Normal file
26
src/Repository/Contract/FormationReadRepositoryInterface.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository\Contract;
|
||||
|
||||
use App\Entity\Employee;
|
||||
use App\Entity\Formation;
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface FormationReadRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @param list<Employee> $employees
|
||||
*
|
||||
* @return list<Formation>
|
||||
*/
|
||||
public function findByDateAndEmployees(DateTimeImmutable $date, array $employees): array;
|
||||
|
||||
/**
|
||||
* @param list<Employee> $employees
|
||||
*
|
||||
* @return list<Formation>
|
||||
*/
|
||||
public function findByDateRangeAndEmployees(DateTimeImmutable $from, DateTimeImmutable $to, array $employees): array;
|
||||
}
|
||||
74
src/Repository/FormationRepository.php
Normal file
74
src/Repository/FormationRepository.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Employee;
|
||||
use App\Entity\Formation;
|
||||
use App\Repository\Contract\FormationReadRepositoryInterface;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Formation>
|
||||
*/
|
||||
final class FormationRepository extends ServiceEntityRepository implements FormationReadRepositoryInterface
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Formation::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Employee> $employees
|
||||
*
|
||||
* @return list<Formation>
|
||||
*/
|
||||
public function findByDateAndEmployees(DateTimeImmutable $date, array $employees): array
|
||||
{
|
||||
if ([] === $employees) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$qb = $this->createQueryBuilder('f')
|
||||
->leftJoin('f.employee', 'e')
|
||||
->addSelect('e')
|
||||
->andWhere('f.startDate <= :date')
|
||||
->andWhere('f.endDate >= :date')
|
||||
->andWhere('f.employee IN (:employees)')
|
||||
->setParameter('date', $date)
|
||||
->setParameter('employees', $employees)
|
||||
;
|
||||
|
||||
// @var list<Formation>
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Employee> $employees
|
||||
*
|
||||
* @return list<Formation>
|
||||
*/
|
||||
public function findByDateRangeAndEmployees(DateTimeImmutable $from, DateTimeImmutable $to, array $employees): array
|
||||
{
|
||||
if ([] === $employees) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$qb = $this->createQueryBuilder('f')
|
||||
->leftJoin('f.employee', 'e')
|
||||
->addSelect('e')
|
||||
->andWhere('f.startDate <= :to')
|
||||
->andWhere('f.endDate >= :from')
|
||||
->andWhere('f.employee IN (:employees)')
|
||||
->setParameter('from', $from)
|
||||
->setParameter('to', $to)
|
||||
->setParameter('employees', $employees)
|
||||
;
|
||||
|
||||
// @var list<Formation>
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,11 @@ namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Entity\Formation;
|
||||
use App\Enum\ContractNature;
|
||||
use App\Enum\HalfDay;
|
||||
use App\Repository\AbsenceRepository;
|
||||
use App\Repository\Contract\FormationReadRepositoryInterface;
|
||||
use App\Repository\EmployeeRepository;
|
||||
use App\Service\PublicHolidayServiceInterface;
|
||||
use DateInterval;
|
||||
@@ -30,6 +32,7 @@ class AbsencePrintProvider implements ProviderInterface
|
||||
private readonly RequestStack $requestStack,
|
||||
private EmployeeRepository $employeeRepository,
|
||||
private AbsenceRepository $absenceRepository,
|
||||
private FormationReadRepositoryInterface $formationRepository,
|
||||
private PublicHolidayServiceInterface $publicHolidayService,
|
||||
) {}
|
||||
|
||||
@@ -58,24 +61,27 @@ class AbsencePrintProvider implements ProviderInterface
|
||||
$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);
|
||||
$employees = $this->loadEmployees($siteIds, $contractNatures, $workContractIds);
|
||||
$absences = $this->loadAbsences($fromDate, $toDate, $employees);
|
||||
$formations = $this->formationRepository->findByDateRangeAndEmployees($fromDate, $toDate, $employees);
|
||||
|
||||
$days = $this->buildDays($fromDate, $toDate);
|
||||
$absenceMap = $this->buildAbsenceMap($absences, $fromDate, $toDate);
|
||||
$holidayMap = $this->buildHolidayMap($fromDate, $toDate);
|
||||
$days = $this->buildDays($fromDate, $toDate);
|
||||
$absenceMap = $this->buildAbsenceMap($absences, $fromDate, $toDate);
|
||||
$formationMap = $this->buildFormationMap($formations, $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,
|
||||
'from' => $fromDate,
|
||||
'to' => $toDate,
|
||||
'days' => $days,
|
||||
'employees' => $employees,
|
||||
'absenceMap' => $absenceMap,
|
||||
'formationMap' => $formationMap,
|
||||
'holidayMap' => $holidayMap,
|
||||
]);
|
||||
|
||||
$dompdf->loadHtml($html);
|
||||
@@ -203,6 +209,37 @@ class AbsencePrintProvider implements ProviderInterface
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Formation> $formations
|
||||
*
|
||||
* @return array<int, array<string, bool>>
|
||||
*/
|
||||
private function buildFormationMap(array $formations, DateTimeImmutable $from, DateTimeImmutable $to): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
foreach ($formations as $formation) {
|
||||
$employeeId = $formation->getEmployee()?->getId();
|
||||
if (!$employeeId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$formationStart = DateTimeImmutable::createFromInterface($formation->getStartDate());
|
||||
$formationEnd = DateTimeImmutable::createFromInterface($formation->getEndDate());
|
||||
|
||||
$start = max($formationStart, $from);
|
||||
$end = min($formationEnd, $to);
|
||||
|
||||
$current = $start;
|
||||
while ($current <= $end) {
|
||||
$map[$employeeId][$current->format('Y-m-d')] = true;
|
||||
$current = $current->add(new DateInterval('P1D'));
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
private function buildHolidayMap(DateTimeImmutable $from, DateTimeImmutable $to): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
42
src/State/FormationDeleteProcessor.php
Normal file
42
src/State/FormationDeleteProcessor.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use App\Entity\Formation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
|
||||
final readonly class FormationDeleteProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
#[Autowire('%kernel.project_dir%/var/uploads')]
|
||||
private string $uploadDir,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): null
|
||||
{
|
||||
if (!$data instanceof Formation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$justificatifPath = $data->getJustificatifPath();
|
||||
|
||||
if (null !== $justificatifPath) {
|
||||
$absolutePath = sprintf('%s/%s', $this->uploadDir, $justificatifPath);
|
||||
|
||||
if (file_exists($absolutePath)) {
|
||||
unlink($absolutePath);
|
||||
}
|
||||
}
|
||||
|
||||
$this->entityManager->remove($data);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
53
src/State/FormationJustificatifDownloadProvider.php
Normal file
53
src/State/FormationJustificatifDownloadProvider.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Entity\Formation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
final readonly class FormationJustificatifDownloadProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
#[Autowire('%kernel.project_dir%/var/uploads')]
|
||||
private string $uploadDir,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): BinaryFileResponse
|
||||
{
|
||||
$formation = $this->entityManager->find(Formation::class, $uriVariables['id']);
|
||||
|
||||
if (null === $formation) {
|
||||
throw new NotFoundHttpException('Formation not found.');
|
||||
}
|
||||
|
||||
$justificatifPath = $formation->getJustificatifPath();
|
||||
|
||||
if (null === $justificatifPath) {
|
||||
throw new NotFoundHttpException('No justificatif found for this formation.');
|
||||
}
|
||||
|
||||
$absolutePath = sprintf('%s/%s', $this->uploadDir, $justificatifPath);
|
||||
|
||||
if (!file_exists($absolutePath)) {
|
||||
throw new NotFoundHttpException('Justificatif file not found.');
|
||||
}
|
||||
|
||||
$response = new BinaryFileResponse($absolutePath);
|
||||
$disposition = HeaderUtils::makeDisposition(
|
||||
HeaderUtils::DISPOSITION_ATTACHMENT,
|
||||
$formation->getJustificatifName() ?? 'justificatif.pdf'
|
||||
);
|
||||
$response->headers->set('Content-Disposition', $disposition);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
75
src/State/FormationJustificatifUploadProcessor.php
Normal file
75
src/State/FormationJustificatifUploadProcessor.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use App\Entity\Formation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
final readonly class FormationJustificatifUploadProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private RequestStack $requestStack,
|
||||
#[Autowire('%kernel.project_dir%/var/uploads')]
|
||||
private string $uploadDir,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): JsonResponse
|
||||
{
|
||||
if (!$data instanceof Formation) {
|
||||
throw new BadRequestHttpException('Invalid entity.');
|
||||
}
|
||||
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
$file = $request?->files->get('file');
|
||||
|
||||
if (null === $file) {
|
||||
throw new BadRequestHttpException('No file uploaded.');
|
||||
}
|
||||
|
||||
if ('application/pdf' !== $file->getMimeType()) {
|
||||
throw new BadRequestHttpException('Only PDF files are accepted.');
|
||||
}
|
||||
|
||||
$startDate = $data->getStartDate();
|
||||
$year = $startDate?->format('Y') ?? date('Y');
|
||||
$monthNumber = $startDate?->format('m') ?? date('m');
|
||||
$relativePath = sprintf('formations/%s/%s', $year, $monthNumber);
|
||||
$absoluteDir = sprintf('%s/%s', $this->uploadDir, $relativePath);
|
||||
|
||||
if (!is_dir($absoluteDir)) {
|
||||
mkdir($absoluteDir, 0o755, true);
|
||||
}
|
||||
|
||||
$filename = Uuid::v4()->toRfc4122().'.pdf';
|
||||
$fullRelative = sprintf('%s/%s', $relativePath, $filename);
|
||||
$originalName = $file->getClientOriginalName();
|
||||
|
||||
$previousPath = $data->getJustificatifPath();
|
||||
|
||||
$file->move($absoluteDir, $filename);
|
||||
|
||||
$data->setJustificatifPath($fullRelative);
|
||||
$data->setJustificatifName($originalName);
|
||||
$this->entityManager->flush();
|
||||
|
||||
if (null !== $previousPath) {
|
||||
$previousAbsolute = sprintf('%s/%s', $this->uploadDir, $previousPath);
|
||||
if (file_exists($previousAbsolute)) {
|
||||
unlink($previousAbsolute);
|
||||
}
|
||||
}
|
||||
|
||||
return new JsonResponse(['path' => $fullRelative, 'name' => $originalName], Response::HTTP_OK);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ use App\Dto\WorkHours\DayContextRow;
|
||||
use App\Entity\User;
|
||||
use App\Repository\Contract\AbsenceReadRepositoryInterface;
|
||||
use App\Repository\Contract\EmployeeScopedRepositoryInterface;
|
||||
use App\Repository\Contract\FormationReadRepositoryInterface;
|
||||
use App\Service\Contracts\EmployeeContractResolver;
|
||||
use App\Service\WorkHours\AbsenceSegmentsResolver;
|
||||
use App\Service\WorkHours\WorkedHoursCreditPolicy;
|
||||
@@ -27,6 +28,7 @@ final readonly class WorkHourDayContextProvider implements ProviderInterface
|
||||
private RequestStack $requestStack,
|
||||
private EmployeeScopedRepositoryInterface $employeeRepository,
|
||||
private AbsenceReadRepositoryInterface $absenceRepository,
|
||||
private FormationReadRepositoryInterface $formationRepository,
|
||||
private EmployeeContractResolver $contractResolver,
|
||||
private AbsenceSegmentsResolver $absenceSegmentsResolver,
|
||||
private WorkedHoursCreditPolicy $workedHoursCreditPolicy,
|
||||
@@ -40,9 +42,10 @@ final readonly class WorkHourDayContextProvider implements ProviderInterface
|
||||
throw new AccessDeniedHttpException('Authentication required.');
|
||||
}
|
||||
|
||||
$workDate = $this->resolveWorkDate();
|
||||
$employees = $this->employeeRepository->findScoped($user);
|
||||
$absences = $this->absenceRepository->findByDateAndEmployees($workDate, $employees);
|
||||
$workDate = $this->resolveWorkDate();
|
||||
$employees = $this->employeeRepository->findScoped($user);
|
||||
$absences = $this->absenceRepository->findByDateAndEmployees($workDate, $employees);
|
||||
$formations = $this->formationRepository->findByDateAndEmployees($workDate, $employees);
|
||||
|
||||
$rowsByEmployeeId = [];
|
||||
foreach ($employees as $employee) {
|
||||
@@ -87,6 +90,14 @@ final readonly class WorkHourDayContextProvider implements ProviderInterface
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($formations as $formation) {
|
||||
$employeeId = $formation->getEmployee()?->getId();
|
||||
if (!$employeeId || !isset($rowsByEmployeeId[$employeeId])) {
|
||||
continue;
|
||||
}
|
||||
$rowsByEmployeeId[$employeeId]->setFormation('Formation');
|
||||
}
|
||||
|
||||
$response = new WorkHourDayContext();
|
||||
$response->workDate = $dateKey;
|
||||
$response->rows = array_map(
|
||||
|
||||
Reference in New Issue
Block a user