setLastName('Martin')->setFirstName('Luc'); $idRef = new ReflectionProperty(Employee::class, 'id'); $idRef->setValue($driverEmp, 7); // Paiement : exercice 2027, mois 9 -> civil 2026, mois 9 ; base 100+20. $payment = new EmployeeRttPayment() ->setEmployee($driverEmp) ->setYear(2027)->setMonth(9) ->setBase25Minutes(100)->setBase50Minutes(20) ; $repo = $this->createStub(EmployeeRttPaymentRepository::class); $repo->method('findByEmployeesAndYears')->willReturn([$payment]); $builder = new OvertimeContingentExportBuilder($repo, new OvertimePaidContingentCalculator(), new StructuralOvertimeContingentCalculator()); $rows = $builder->buildRows([$driverEmp], 2026); self::assertCount(1, $rows); self::assertSame(7, $rows[0]->employeeId); self::assertSame('Martin Luc', $rows[0]->employeeName); self::assertSame(120, $rows[0]->months[9]); self::assertSame(0, $rows[0]->months[1]); self::assertSame(120, $rows[0]->totalMinutes); self::assertSame(350, $rows[0]->capHours); // chauffeur } public function testEmployeeWithNoPaymentsYieldsZeroRow(): void { $emp = new Employee(); $emp->setLastName('Durand')->setFirstName('Alice'); $idRef = new ReflectionProperty(Employee::class, 'id'); $idRef->setValue($emp, 99); $repo = $this->createStub(EmployeeRttPaymentRepository::class); $repo->method('findByEmployeesAndYears')->willReturn([]); $builder = new OvertimeContingentExportBuilder($repo, new OvertimePaidContingentCalculator(), new StructuralOvertimeContingentCalculator()); $rows = $builder->buildRows([$emp], 2026); self::assertCount(1, $rows); self::assertSame(0, $rows[0]->totalMinutes); self::assertSame(0, $rows[0]->months[6]); self::assertSame(220, $rows[0]->capHours); // non-driver } public function testStructuralHoursOf39hAreAddedToPaidBase(): void { $contract = new Contract() ->setName('CDI') ->setTrackingMode(TrackingMode::TIME) ->setWeeklyHours(39) ; $period = new EmployeeContractPeriod() ->setContract($contract) ->setStartDate(new DateTimeImmutable('2020-01-01')) ; $emp = new Employee(); $emp->setLastName('Petit')->setFirstName('Marc'); $emp->getContractPeriods()->add($period); $idRef = new ReflectionProperty(Employee::class, 'id'); $idRef->setValue($emp, 11); $repo = $this->createStub(EmployeeRttPaymentRepository::class); $repo->method('findByEmployeesAndYears')->willReturn([]); $builder = new OvertimeContingentExportBuilder($repo, new OvertimePaidContingentCalculator(), new StructuralOvertimeContingentCalculator()); $rows = $builder->buildRows([$emp], 2026); // Aucun paiement RTT, mais 12 × 1040 min de structurel (39h plein sur l'année). self::assertSame(1040, $rows[0]->months[1]); self::assertSame(12 * 1040, $rows[0]->totalMinutes); } }