From 00d5b810be07c5a80b7737a757a7a36b0ba173be Mon Sep 17 00:00:00 2001 From: tristan Date: Thu, 11 Jun 2026 17:04:53 +0200 Subject: [PATCH] =?UTF-8?q?feat(overtime-contingent)=20:=20DTO=20+=20build?= =?UTF-8?q?er=20export=20PDF=20(heures=20supp=20pay=C3=A9es)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/Dto/WorkHours/OvertimeContingentRow.php | 19 +++++ .../OvertimeContingentExportBuilder.php | 65 ++++++++++++++++ .../OvertimeContingentExportBuilderTest.php | 75 +++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 src/Dto/WorkHours/OvertimeContingentRow.php create mode 100644 src/Service/WorkHours/OvertimeContingentExportBuilder.php create mode 100644 tests/Service/WorkHours/OvertimeContingentExportBuilderTest.php diff --git a/src/Dto/WorkHours/OvertimeContingentRow.php b/src/Dto/WorkHours/OvertimeContingentRow.php new file mode 100644 index 0000000..ca2b20f --- /dev/null +++ b/src/Dto/WorkHours/OvertimeContingentRow.php @@ -0,0 +1,19 @@ + $months clé 1..12 -> minutes base payées + */ + public function __construct( + public readonly int $employeeId, + public readonly string $employeeName, + public readonly array $months, + public readonly int $totalMinutes, + public readonly int $capHours, + ) {} +} diff --git a/src/Service/WorkHours/OvertimeContingentExportBuilder.php b/src/Service/WorkHours/OvertimeContingentExportBuilder.php new file mode 100644 index 0000000..94b76c3 --- /dev/null +++ b/src/Service/WorkHours/OvertimeContingentExportBuilder.php @@ -0,0 +1,65 @@ + $employees + * + * @return list + */ + public function buildRows(array $employees, int $civilYear): array + { + // Année civile Y = exercice Y (mois 1-5) + exercice Y+1 (mois 6-12). + $payments = $this->rttPaymentRepository->findByEmployeesAndYears( + $employees, + [$civilYear, $civilYear + 1], + ); + + $byEmployee = []; + foreach ($payments as $payment) { + $employeeId = $payment->getEmployee()?->getId(); + if (null === $employeeId) { + continue; + } + $byEmployee[$employeeId][] = $payment; + } + + $rows = []; + foreach ($employees as $employee) { + $employeeId = $employee->getId(); + if (null === $employeeId) { + continue; + } + + $employeePayments = $byEmployee[$employeeId] ?? []; + $months = $this->calculator->monthlyBaseMinutes($employeePayments, $civilYear); + + $rows[] = new OvertimeContingentRow( + employeeId: $employeeId, + employeeName: trim($employee->getLastName().' '.$employee->getFirstName()), + months: $months, + totalMinutes: array_sum($months), + capHours: $this->calculator->capHours($employee->getIsDriver()), + ); + } + + return $rows; + } +} diff --git a/tests/Service/WorkHours/OvertimeContingentExportBuilderTest.php b/tests/Service/WorkHours/OvertimeContingentExportBuilderTest.php new file mode 100644 index 0000000..d9213b8 --- /dev/null +++ b/tests/Service/WorkHours/OvertimeContingentExportBuilderTest.php @@ -0,0 +1,75 @@ +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()); + + $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()); + $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 + } +}