getContract(); $contractName = $contract?->getName(); $isForfait = ContractType::FORFAIT === $contract?->getType(); $nature = ContractNature::tryFrom($employee->getCurrentContractNature()); $isInterim = ContractNature::INTERIM === $nature; $rttReference = $asOfDate ?? new DateTimeImmutable('today'); $cpN1Remaining = 0.0; $cpN = '-'; $acquiredSaturdays = '-'; $rtt = '-'; if (!$isInterim) { $leaveYear = $this->leaveSummaryProvider->resolveLeaveYearForToday($employee); $yearSummary = $this->leaveSummaryProvider->computeYearSummary($employee, $leaveYear, 0.0, $asOfDate); if (null !== $yearSummary) { if ($isForfait) { $paidLeaveDays = $this->leaveSummaryProvider->resolvePaidLeaveDays($employee, $yearSummary['ruleCode'], $leaveYear); if ($paidLeaveDays > 0.0) { $recomputed = $this->leaveSummaryProvider->computeYearSummary($employee, $leaveYear, $paidLeaveDays, $asOfDate); if (null !== $recomputed) { $yearSummary = $recomputed; } } $cpN1Remaining = round($yearSummary['previousYearRemainingDays'], 2); $cpN = (string) round($yearSummary['remainingDays'], 2); $acquiredSaturdays = '-'; } else { $cpN1Remaining = round($yearSummary['remainingDays'], 2); $cpN = (string) round($yearSummary['accruingDays'], 2); $acquiredSaturdays = (string) round($yearSummary['remainingSaturdays'], 2); } } if (!$isForfait && TrackingMode::PRESENCE->value !== $contract?->getTrackingMode()) { try { $rtt = $this->formatMinutes($this->computeAvailableRttMinutes($employee, $rttReference)); } catch (Throwable) { $rtt = '-'; } } } return [ 'lastName' => $employee->getLastName(), 'firstName' => $employee->getFirstName(), 'contractName' => $contractName, 'cpN1Remaining' => $cpN1Remaining, 'cpN' => $cpN, 'acquiredSaturdays' => $acquiredSaturdays, 'rtt' => $rtt, ]; } private function computeAvailableRttMinutes(Employee $employee, DateTimeImmutable $reference): int { $month = (int) $reference->format('n'); $year = (int) $reference->format('Y'); $exerciseYear = $month >= 6 ? $year + 1 : $year; // Exclude incomplete current week: limit to last Sunday $isoDay = (int) $reference->format('N'); $limitDate = 7 === $isoDay ? $reference : $reference->modify('last sunday'); // Include the current week if all existing days are admin-validated if (7 !== $isoDay) { $currentWeekStart = $reference->modify('monday this week'); $currentWeekEnd = $currentWeekStart->modify('+6 days'); $checkEnd = $this->resolveWeekEndForEmployee($employee, $currentWeekStart, $currentWeekEnd, $reference); if ($this->workHourRepository->isWeekFullyValidated($employee, $currentWeekStart, $checkEnd)) { $limitDate = $currentWeekEnd; } } // Carry from previous exercise $carry = 0; $balance = $this->rttBalanceRepository->findOneByEmployeeAndYear($employee, $exerciseYear); if (null !== $balance) { $carry = $balance->getTotalOpeningMinutes(); } else { $previousTotal = $this->rttRecoveryService->computeTotalRecoveryForExercise($employee, $exerciseYear - 1); $carry = $previousTotal->totalMinutes; } // Current exercise (limited to completed weeks) $current = $this->rttRecoveryService->computeTotalRecoveryForExercise($employee, $exerciseYear, $limitDate); // Paid RTT $paid = 0; $payments = $this->rttPaymentRepository->findByEmployeeAndYear($employee, $exerciseYear); foreach ($payments as $payment) { $paid += $payment->getBase25Minutes() + $payment->getBonus25Minutes() + $payment->getBase50Minutes() + $payment->getBonus50Minutes(); } return $carry + $current->totalMinutes - $paid; } private function resolveWeekEndForEmployee(Employee $employee, DateTimeImmutable $weekStart, DateTimeImmutable $weekEnd, DateTimeImmutable $today): DateTimeImmutable { foreach ($employee->getContractPeriods() as $period) { if ($period->getStartDate() > $today) { continue; } $endDate = $period->getEndDate(); if (null === $endDate) { continue; } if ($endDate >= $weekStart && $endDate <= $weekEnd) { return $endDate; } } return $weekEnd; } private function formatMinutes(int $minutes): string { if (0 === $minutes) { return '0 h'; } $sign = $minutes < 0 ? '- ' : ''; $abs = abs($minutes); $h = intdiv($abs, 60); $m = $abs % 60; return 0 === $m ? "{$sign}{$h} h" : "{$sign}{$h} h {$m} m"; } }