= 4h de nuit dans la journee). Fenetre 21h->6h via * NightHoursCalculator. Conducteurs : minutes saisies (nightHoursMinutes). * Aucun credit absence/ferie : seules les heures reellement travaillees comptent. */ final readonly class NightContingentExportBuilder { private const int NIGHT_DAY_THRESHOLD_MINUTES = 240; public function __construct( private WorkHourReadRepositoryInterface $workHourRepository, private EmployeeContractResolver $contractResolver, private NightHoursCalculator $nightHoursCalculator, ) {} /** * @param list $employees * * @return list */ public function buildRows(array $employees, int $year): array { $from = new DateTimeImmutable(sprintf('%d-01-01', $year)); $to = new DateTimeImmutable(sprintf('%d-12-31', $year)); $workHours = $this->workHourRepository->findByDateRangeAndEmployees($from, $to, $employees); $byEmployee = []; foreach ($workHours as $wh) { $employeeId = $wh->getEmployee()?->getId(); if (null === $employeeId) { continue; } $byEmployee[$employeeId][] = $wh; } $days = []; foreach ($workHours as $wh) { $days[$wh->getWorkDate()->format('Y-m-d')] = true; } $days = array_keys($days); $driverMap = $this->contractResolver->resolveIsDriverForEmployeesAndDays($employees, $days); $rows = []; foreach ($employees as $employee) { $employeeId = $employee->getId(); if (null === $employeeId) { continue; } $months = []; for ($m = 1; $m <= 12; ++$m) { $months[$m] = ['nightMinutes' => 0, 'nightDays' => 0]; } foreach ($byEmployee[$employeeId] ?? [] as $wh) { $date = DateTimeImmutable::createFromInterface($wh->getWorkDate()); $ymd = $date->format('Y-m-d'); $isDriver = $driverMap[$employeeId][$ymd] ?? false; $nightMin = $this->nightHoursCalculator->nightMinutesForWorkHour($wh, $isDriver); if ($nightMin <= 0) { continue; } $month = (int) $date->format('n'); $months[$month]['nightMinutes'] += $nightMin; if ($nightMin >= self::NIGHT_DAY_THRESHOLD_MINUTES) { ++$months[$month]['nightDays']; } } $rows[] = new NightContingentRow( employeeId: $employeeId, employeeName: trim($employee->getLastName().' '.$employee->getFirstName()), months: $months, ); } return $rows; } }