security->isGranted('ROLE_USER')) { throw new AccessDeniedException('Access denied: ROLE_USER required.'); } $user = $this->userRepository->find($userId) ?? throw new InvalidArgumentException(sprintf('User with ID %d not found.', $userId)); $typeEnum = AbsenceType::tryFrom($type) ?? throw new InvalidArgumentException(sprintf('Unknown absence type "%s".', $type)); $start = new DateTimeImmutable($startDate); $end = new DateTimeImmutable($endDate); if ($end < $start) { throw new InvalidArgumentException('End date must be on or after start date.'); } $startHd = null !== $startHalfDay ? (HalfDay::tryFrom($startHalfDay) ?? throw new InvalidArgumentException(sprintf('Unknown half day "%s".', $startHalfDay))) : null; $endHd = null !== $endHalfDay ? (HalfDay::tryFrom($endHalfDay) ?? throw new InvalidArgumentException(sprintf('Unknown half day "%s".', $endHalfDay))) : null; $policy = $this->policyRepository->findOneByType($typeEnum); if (null === $policy || !$policy->isActive()) { throw new InvalidArgumentException('This absence type is not available.'); } if ($this->requestRepository->hasOverlap($user, $start, $end)) { throw new InvalidArgumentException('This request overlaps an existing absence.'); } $countedDays = $this->calculator->countWorkingDays($start, $end, $startHd, $endHd, $policy->isCountWorkingDaysOnly()); if ($countedDays <= 0.0) { throw new InvalidArgumentException('The selected range contains no working day.'); } $request = new AbsenceRequest(); $request->setUser($user); $request->setType($typeEnum); $request->setStartDate($start); $request->setEndDate($end); $request->setStartHalfDay($startHd); $request->setEndHalfDay($endHd); $request->setReason($reason); $request->setCountedDays($countedDays); $request->setStatus(AbsenceStatus::Pending); $request->setRejectionReason(null); $request->setCreatedAt(new DateTimeImmutable()); $this->entityManager->persist($request); $this->balanceService->reservePending($request); $this->entityManager->flush(); return json_encode(Serializer::absenceRequest($request)); } }