src/Entity/CRM/LeaveRequest.php line 19
<?phpnamespace App\Entity\CRM;use App\Repository\LeaveRequestRepository;use DateTime;use Doctrine\Common\Collections\ArrayCollection;use Doctrine\Common\Collections\Collection;use Doctrine\DBAL\Types\Types;use Doctrine\ORM\Mapping as ORM;use Symfony\Component\Validator\Context\ExecutionContextInterface;use Symfony\Component\Validator\Constraints as Assert;use App\Validator\Constraints as AppAssert;#[AppAssert\NoLeaveRequestIfWorked]#[AppAssert\NoOverlappingLeaveRequest]#[AppAssert\EnoughLeaveBalance]#[ORM\Entity(repositoryClass: LeaveRequestRepository::class)]class LeaveRequest{#[ORM\Id]#[ORM\GeneratedValue]#[ORM\Column]private ?int $id = null;#[ORM\ManyToOne(inversedBy: 'leaveRequests')]#[ORM\JoinColumn(nullable: true)]private ?Consultant $consultant = null;#[ORM\Column(type: Types::DATETIME_MUTABLE)]private ?\DateTimeInterface $startTime = null;#[ORM\Column(type: Types::DATETIME_MUTABLE)]private ?\DateTimeInterface $endTime = null;#[ORM\Column]private ?bool $accepted = null;#[ORM\ManyToOne(inversedBy: 'acceptedLeaveRequests')]private ?Admin $acceptedBy = null;#[ORM\Column]private ?bool $rejected = null;#[ORM\ManyToOne(inversedBy: 'rejectedLeaveRequests')]private ?Admin $rejectedBy = null;#[ORM\ManyToOne(inversedBy: 'LeaveRequest')]private ?LeaveRequestType $leaveRequestType = null;#[ORM\Column]private ?bool $acceptedByHr = false;#[ORM\ManyToOne]private ?Admin $acceptedByHrBy = null;#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]private ?\DateTimeInterface $addedDate = null;#[ORM\Column]private ?int $leaveCategory = 1;#[ORM\ManyToOne(inversedBy: 'leaveRequests')]private ?Admin $admin = null;#[ORM\OneToMany(mappedBy: 'leaveRequest', targetEntity: LeaveRequestAllocation::class, cascade: ['persist', 'remove'])]private Collection $leaveRequestAllocations;#[ORM\Column(length: 255, nullable: true)]private ?string $workTimeSettlement = null;#[ORM\Column]private ?bool $forHourlySettlement = null;#[ORM\Column(nullable: true)]private ?int $employmentFactor = null;public function __construct(){$this->consultant = null;$this->admin = null;$this->accepted = false;$this->rejected = false;$this->acceptedByHr = false;$this->addedDate = new DateTime();$this->leaveRequestAllocations = new ArrayCollection();$this->workTimeSettlement = NULL;}public function getId(): ?int{return $this->id;}public function getConsultant(): ?Consultant{return $this->consultant;}public function setConsultant(?Consultant $consultant): static{$this->consultant = $consultant;return $this;}public function getStartTime(): ?\DateTimeInterface{return $this->startTime;}public function setStartTime(\DateTimeInterface $startTime): static{$this->startTime = $startTime;return $this;}public function getEndTime(): ?\DateTimeInterface{return $this->endTime;}public function setEndTime(\DateTimeInterface $endTime): static{$this->endTime = $endTime;return $this;}public function isAccepted(): ?bool{return $this->accepted;}public function setAccepted(bool $accepted): static{$this->accepted = $accepted;return $this;}public function getAcceptedBy(): ?Admin{return $this->acceptedBy;}public function setAcceptedBy(?Admin $acceptedBy): static{$this->acceptedBy = $acceptedBy;return $this;}public function isRejected(): ?bool{return $this->rejected;}public function setRejected(bool $rejected): static{$this->rejected = $rejected;return $this;}public function getRejectedBy(): ?Admin{return $this->rejectedBy;}public function setRejectedBy(?Admin $rejectedBy): static{$this->rejectedBy = $rejectedBy;return $this;}public function getLeaveRequestType(): ?LeaveRequestType{return $this->leaveRequestType;}public function setLeaveRequestType(LeaveRequestType $leaveRequestType): void{$this->leaveRequestType = $leaveRequestType;}public function getDuration(): string{//method doesn't count public holidays, suitable for daily(leaveCategory == 2) leave requestsif (!$this->getStartTime() || !$this->getEndTime()) {return 'N/A';}$category = $this->getLeaveCategory();$isChildCare = $this->leaveRequestType ? $this->leaveRequestType->isChildCare() : false;// Kategoria 1: Dzienne — zwracaj liczbę dni roboczych (bez weekendów), bez jednostkiif ($category === 1 && !$isChildCare) {$startTime = clone $this->getStartTime();$endTime = clone $this->getEndTime();// Ustaw tylko datę, aby liczyć pełne dni$currentDay = (clone $startTime)->setTime(0, 0, 0);$lastDay = (clone $endTime)->setTime(0, 0, 0);// Jeśli zakres jest odwróconyif ($lastDay < $currentDay) {return '0';}$workingDays = 0;while ($currentDay <= $lastDay) {$dayOfWeek = (int)$currentDay->format('N'); // 1=pon, ..., 7=niedzif ($dayOfWeek !== 6 && $dayOfWeek !== 7) {$workingDays++;}$currentDay = (clone $currentDay)->modify('+1 day');}return (string)$workingDays.' dni';}// Kategoria 2: Godzinowe — zwracaj różnicę czasu jako "Xh Ym"if ($category === 2 || $isChildCare) {$start = $this->getStartTime();$end = $this->getEndTime();if ($end < $start) {return '0 godz.';}$diffSeconds = $end->getTimestamp() - $start->getTimestamp();$totalMinutes = (int)floor($diffSeconds / 60);$hours = intdiv($totalMinutes, 60);$minutes = $totalMinutes % 60;if ($hours > 0 && $minutes > 0) {return sprintf('%d godz. %dm', $hours, $minutes);}if ($hours > 0) {return sprintf('%d godz.', $hours);}return sprintf('%d godz.', $minutes);}// Fallback: licz dni robocze jak w kategorii dziennej$startTime = clone $this->getStartTime();$endTime = clone $this->getEndTime();$currentDay = (clone $startTime)->setTime(0, 0, 0);$lastDay = (clone $endTime)->setTime(0, 0, 0);if ($lastDay < $currentDay) {return '0';}$workingDays = 0;while ($currentDay <= $lastDay) {$dayOfWeek = (int)$currentDay->format('N');if ($dayOfWeek !== 6 && $dayOfWeek !== 7) {$workingDays++;}$currentDay = (clone $currentDay)->modify('+1 day');}return (string)$workingDays.' dni';}public function getAcceptedOrRejected():string{if($this->isRejected()){return 'Odrzucone';}if($this->isAccepted()){return 'Zaakceptowany';}return 'w trakcie';}public function isAcceptedByHr(): ?bool{return $this->acceptedByHr;}public function getAcceptedByHr(): bool{return $this->acceptedByHr;}public function setAcceptedByHr(bool $acceptedByHr): static{$this->acceptedByHr = $acceptedByHr;return $this;}public function getAcceptedByHrBy(): ?Admin{return $this->acceptedByHrBy;}public function setAcceptedByHrBy(?Admin $acceptedByHrBy): static{$this->acceptedByHrBy = $acceptedByHrBy;return $this;}public function getAddedDate(): ?\DateTimeInterface{return $this->addedDate;}public function setAddedDate(?\DateTimeInterface $addedDate): static{$this->addedDate = $addedDate;return $this;}public function getLeaveCategory(): ?int{return $this->leaveCategory;}public function setLeaveCategory(int $leaveCategory): static{$this->leaveCategory = $leaveCategory;return $this;}public function getAdmin(): ?Admin{return $this->admin;}public function setAdmin(?Admin $admin): static{$this->admin = $admin;return $this;}/*** @return Collection<int, LeaveRequestAllocation>*/public function getLeaveRequestAllocations(): Collection{return $this->leaveRequestAllocations;}public function getLeaveRequestPlannedMinutes(): int{return (int) (($this->endTime->getTimestamp() - $this->startTime->getTimestamp()) / 60);}public function getLeaveRequestUsedMinutes(){$sum = 0;foreach ($this->leaveRequestAllocations as $allocation) {$sum += $allocation->getMinutesUsed();}return $sum;}public function getLeaveRequestRemainingMinutes(): int{return $this->getLeaveRequestPlannedMinutes() - $this->getLeaveRequestUsedMinutes();}public function addLeaveRequestAllocation(LeaveRequestAllocation $leaveRequestAllocation): static{if (!$this->leaveRequestAllocations->contains($leaveRequestAllocation)) {$this->leaveRequestAllocations->add($leaveRequestAllocation);$leaveRequestAllocation->setLeaveRequest($this);}return $this;}public function removeLeaveRequestAllocation(LeaveRequestAllocation $leaveRequestAllocation): static{if ($this->leaveRequestAllocations->removeElement($leaveRequestAllocation)) {// set the owning side to null (unless already changed)if ($leaveRequestAllocation->getLeaveRequest() === $this) {$leaveRequestAllocation->setLeaveRequest(null);}}return $this;}public function getWorkTimeSettlement(): ?string{return $this->workTimeSettlement;}public function setWorkTimeSettlement(?string $workTimeSettlement): static{$this->workTimeSettlement = $workTimeSettlement;return $this;}#[Assert\Callback]public function validateSingleLeaveRequestUser(ExecutionContextInterface $context): void{$hasAdmin = $this->getAdmin() !== null;$hasConsultant = $this->getConsultant() !== null;if ($hasAdmin !== $hasConsultant) {return;}$message = $hasAdmin? 'Wybierz tylko jedno pole: Admin albo Consultant.': 'Wybierz Admina albo Consultanta.';$context->buildViolation($message)->atPath('admin')->addViolation();$context->buildViolation($message)->atPath('consultant')->addViolation();}#[Assert\Callback]public function validateMinDailyDuration(ExecutionContextInterface $context): void{$start = $this->getStartTime();$end = $this->getEndTime();$leaveRequestType = $this->getLeaveRequestType();$isChildCare = $leaveRequestType->isChildCare();if (!$start || !$end) {return;}$user = $this->getAdmin() ?? $this->getConsultant();$nominalHours = $this->resolveEmploymentFactorForValidation($user);if (($end->getTimestamp() - $start->getTimestamp()) < ($nominalHours * 3600) && !$isChildCare) {$context->buildViolation('Wniosek urlopowy musi obejmować co najmniej {{ h }} godzin, aby pokryć nominalny czas pracy.')->setParameter('{{ h }}', (string)$nominalHours)->atPath('endTime')->addViolation();}}private function resolveEmploymentFactorForValidation(mixed $user): int{if ($user instanceof Admin) {return $this->resolveEmploymentFactor($user->isDisability(),$user->getAdminContractType(),$user->getNominalWorkTime()?->getEmploymentFactor());}if ($user instanceof Consultant) {return $this->resolveEmploymentFactor($user->isDisability(),$user->getConsultantContractType(),$user->getNominalWorkTime()?->getEmploymentFactor());}return 8;}private function resolveEmploymentFactor(bool $hasDisability, ?EmploymentContractType $contractType, ?int $nominalEmploymentFactor): int{if ($hasDisability && $this->isFullTimeContract($contractType)) {return 8;}return $nominalEmploymentFactor ?? 8;}private function isFullTimeContract(?EmploymentContractType $contractType): bool{return $contractType !== null && abs(($contractType->getMultiplier() ?? 0.0) - 1.0) < 0.0001;}public function isForHourlySettlement(): ?bool{return $this->forHourlySettlement;}public function setForHourlySettlement(bool $forHourlySettlement): static{$this->forHourlySettlement = $forHourlySettlement;return $this;}public function getEmploymentFactor(): ?int{return $this->employmentFactor;}public function setEmploymentFactor(?int $employmentFactor): void{$this->employmentFactor = $employmentFactor;}}