format('Y'); } $year = (int) $date->format('Y'); $startMonthDay = $user->getReferencePeriodStart(); // e.g. "06-01" $currentMonthDay = $date->format('m-d'); $startYear = $currentMonthDay >= $startMonthDay ? $year : $year - 1; return sprintf('%d-%d', $startYear, $startYear + 1); } public function getOrCreateBalance(User $user, AbsenceType $type, string $period): AbsenceBalance { $balance = $this->balanceRepository->findOneForPeriod($user, $type, $period); if (null === $balance) { $balance = new AbsenceBalance() ->setUser($user) ->setType($type) ->setPeriod($period) ; $this->entityManager->persist($balance); } return $balance; } /** Reserve the requested days in the PENDING bucket. */ public function reservePending(AbsenceRequest $request): void { if (!$this->shouldTrack($request)) { return; } $balance = $this->balanceForRequest($request); $balance->setPending($balance->getPending() + $request->getCountedDays()); } /** Move reserved days from PENDING to TAKEN on approval. */ public function applyApproval(AbsenceRequest $request): void { if (!$this->shouldTrack($request)) { return; } $balance = $this->balanceForRequest($request); $balance->setPending(max(0.0, $balance->getPending() - $request->getCountedDays())); $balance->setTaken($balance->getTaken() + $request->getCountedDays()); } /** * Give days back when a request is cancelled or rejected. * * @param bool $wasApproved true if the request had already been approved * (days were in TAKEN), false if still PENDING */ public function release(AbsenceRequest $request, bool $wasApproved): void { if (!$this->shouldTrack($request)) { return; } $balance = $this->balanceForRequest($request); if ($wasApproved) { $balance->setTaken(max(0.0, $balance->getTaken() - $request->getCountedDays())); } else { $balance->setPending(max(0.0, $balance->getPending() - $request->getCountedDays())); } } private function balanceForRequest(AbsenceRequest $request): AbsenceBalance { /** @var User $user */ $user = $request->getUser(); $type = $request->getType(); $period = $this->periodFor($user, $type, $request->getStartDate()); return $this->getOrCreateBalance($user, $type, $period); } private function shouldTrack(AbsenceRequest $request): bool { $type = $request->getType(); return null !== $type && $type->decrementsBalance() && null !== $request->getUser(); } }