diff --git a/src/Service/WorkHours/NightContingentExportBuilder.php b/src/Service/WorkHours/NightContingentExportBuilder.php index c9dae57..e5ab2af 100644 --- a/src/Service/WorkHours/NightContingentExportBuilder.php +++ b/src/Service/WorkHours/NightContingentExportBuilder.php @@ -47,6 +47,14 @@ final readonly class NightContingentExportBuilder $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(); @@ -61,7 +69,8 @@ final readonly class NightContingentExportBuilder foreach ($byEmployee[$employeeId] ?? [] as $wh) { $date = DateTimeImmutable::createFromInterface($wh->getWorkDate()); - $isDriver = $this->contractResolver->resolveIsDriverForEmployeeAndDate($employee, $date); + $ymd = $date->format('Y-m-d'); + $isDriver = $driverMap[$employeeId][$ymd] ?? false; $nightMin = $this->nightHoursCalculator->nightMinutesForWorkHour($wh, $isDriver); if ($nightMin <= 0) { continue; @@ -76,7 +85,7 @@ final readonly class NightContingentExportBuilder $rows[] = new NightContingentRow( employeeId: $employeeId, - employeeName: trim(($employee->getLastName() ?? '').' '.($employee->getFirstName() ?? '')), + employeeName: trim($employee->getLastName().' '.$employee->getFirstName()), months: $months, ); } diff --git a/tests/Service/WorkHours/NightContingentExportBuilderTest.php b/tests/Service/WorkHours/NightContingentExportBuilderTest.php index 7e75714..b29887d 100644 --- a/tests/Service/WorkHours/NightContingentExportBuilderTest.php +++ b/tests/Service/WorkHours/NightContingentExportBuilderTest.php @@ -37,7 +37,9 @@ final class NightContingentExportBuilderTest extends TestCase $workHourRepo->method('findByDateRangeAndEmployees')->willReturn([$whFull, $whShort]); $contractResolver = $this->createStub(EmployeeContractResolver::class); - $contractResolver->method('resolveIsDriverForEmployeeAndDate')->willReturn(false); + $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([ + 1 => ['2026-01-10' => false, '2026-01-11' => false], + ]); $builder = new NightContingentExportBuilder( $workHourRepo, @@ -68,7 +70,9 @@ final class NightContingentExportBuilderTest extends TestCase $workHourRepo->method('findByDateRangeAndEmployees')->willReturn([$wh]); $contractResolver = $this->createStub(EmployeeContractResolver::class); - $contractResolver->method('resolveIsDriverForEmployeeAndDate')->willReturn(true); + $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([ + 2 => ['2026-03-05' => true], + ]); $builder = new NightContingentExportBuilder( $workHourRepo, @@ -82,6 +86,31 @@ final class NightContingentExportBuilderTest extends TestCase self::assertSame(1, $rows[0]->months[3]['nightDays']); // 300 >= 240 } + public function testEmployeeWithoutWorkHoursYieldsAllZeroMonths(): void + { + $employee = $this->makeEmployee(3, 'Durand', 'Marie'); + + $workHourRepo = $this->createStub(WorkHourReadRepositoryInterface::class); + $workHourRepo->method('findByDateRangeAndEmployees')->willReturn([]); + + $contractResolver = $this->createStub(EmployeeContractResolver::class); + $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([]); + + $builder = new NightContingentExportBuilder( + $workHourRepo, + $contractResolver, + new NightHoursCalculator(), + ); + + $rows = $builder->buildRows([$employee], 2026); + + self::assertCount(1, $rows); + for ($m = 1; $m <= 12; ++$m) { + self::assertSame(0, $rows[0]->months[$m]['nightMinutes']); + self::assertSame(0, $rows[0]->months[$m]['nightDays']); + } + } + private function makeEmployee(int $id, string $last, string $first): Employee { $employee = new Employee();