From 380c72c2429dcc5a5d1921d58718c2efa9fdcd4c Mon Sep 17 00:00:00 2001 From: tristan Date: Mon, 2 Mar 2026 10:33:42 +0100 Subject: [PATCH] =?UTF-8?q?fix=20:=20r=C3=A8gle=20de=20calcule=20des=20heu?= =?UTF-8?q?res=20travaill=C3=A9es=20sur=20les=20contrats=20Forfait?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/composables/useHoursPage.ts | 7 +++++-- src/Service/WorkHours/WorkedHoursCreditPolicy.php | 14 +++++++------- src/State/WorkHourWeeklySummaryProvider.php | 12 +++++++++--- tests/State/WorkHourWeeklySummaryProviderTest.php | 2 +- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/frontend/composables/useHoursPage.ts b/frontend/composables/useHoursPage.ts index b8379ad..36ffa21 100644 --- a/frontend/composables/useHoursPage.ts +++ b/frontend/composables/useHoursPage.ts @@ -427,8 +427,11 @@ export const useHoursPage = () => { const getPresenceDayValue = (employeeId: number) => { const row = rows.value[employeeId] - const basePresence = (row?.isPresentMorning ? 0.5 : 0) + (row?.isPresentAfternoon ? 0.5 : 0) - const creditedPresence = dayContextByEmployeeId.value.get(employeeId)?.creditedPresenceUnits ?? 0 + const dayRow = dayContextByEmployeeId.value.get(employeeId) + const absentMorning = dayRow?.absentMorning ?? false + const absentAfternoon = dayRow?.absentAfternoon ?? false + const basePresence = ((row?.isPresentMorning && !absentMorning) ? 0.5 : 0) + ((row?.isPresentAfternoon && !absentAfternoon) ? 0.5 : 0) + const creditedPresence = dayRow?.creditedPresenceUnits ?? 0 const total = Math.min(1, basePresence + creditedPresence) return Number.isInteger(total) ? String(total) : total.toFixed(1) } diff --git a/src/Service/WorkHours/WorkedHoursCreditPolicy.php b/src/Service/WorkHours/WorkedHoursCreditPolicy.php index 9454e86..7a4f72f 100644 --- a/src/Service/WorkHours/WorkedHoursCreditPolicy.php +++ b/src/Service/WorkHours/WorkedHoursCreditPolicy.php @@ -60,11 +60,6 @@ final readonly class WorkedHoursCreditPolicy bool $absentMorning, bool $absentAfternoon ): float { - $type = $absence->getType(); - if (!$type?->getCountAsWorkedHours()) { - return 0.0; - } - $employee = $absence->getEmployee(); if (null === $employee) { return 0.0; @@ -74,9 +69,14 @@ final readonly class WorkedHoursCreditPolicy return 0.0; } - $halfUnits = ($absentMorning ? 1 : 0) + ($absentAfternoon ? 1 : 0); + // Règle forfait: + // - demi-journée d'absence => 0.5 travaillé + // - journée complète d'absence => 0 travaillé + if ($absentMorning xor $absentAfternoon) { + return 0.5; + } - return $halfUnits * 0.5; + return 0.0; } public function resolveContractDayMinutes(?int $weeklyHours, int $isoWeekDay): int diff --git a/src/State/WorkHourWeeklySummaryProvider.php b/src/State/WorkHourWeeklySummaryProvider.php index b11922b..526e2fe 100644 --- a/src/State/WorkHourWeeklySummaryProvider.php +++ b/src/State/WorkHourWeeklySummaryProvider.php @@ -135,6 +135,8 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface $creditedByEmployeeDate = []; $creditedPresenceByEmployeeDate = []; $absenceByEmployeeDate = []; + $absentMorningByEmployeeDate = []; + $absentAfternoonByEmployeeDate = []; $absenceLabelByEmployeeDate = []; $absenceColorByEmployeeDate = []; foreach ($absences as $absence) { @@ -153,7 +155,9 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface [$absentMorning, $absentAfternoon] = $this->absenceSegmentsResolver->resolveForDate($absence, $date); if ($absentMorning || $absentAfternoon) { - $absenceByEmployeeDate[$employeeId][$date] = true; + $absenceByEmployeeDate[$employeeId][$date] = true; + $absentMorningByEmployeeDate[$employeeId][$date] = ($absentMorningByEmployeeDate[$employeeId][$date] ?? false) || $absentMorning; + $absentAfternoonByEmployeeDate[$employeeId][$date] = ($absentAfternoonByEmployeeDate[$employeeId][$date] ?? false) || $absentAfternoon; if (!isset($absenceLabelByEmployeeDate[$employeeId][$date])) { $absenceLabelByEmployeeDate[$employeeId][$date] = $absence->getType()?->getLabel(); } @@ -202,8 +206,10 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface $metrics->addCreditedMinutes($creditedMinutes); $present = null; if ($isPresenceTracking) { - $morning = ($entry['isPresentMorning'] ?? false) ? 0.5 : 0.0; - $afternoon = ($entry['isPresentAfternoon'] ?? false) ? 0.5 : 0.0; + $absentMorning = $absentMorningByEmployeeDate[$employeeId][$date] ?? false; + $absentAfternoon = $absentAfternoonByEmployeeDate[$employeeId][$date] ?? false; + $morning = (($entry['isPresentMorning'] ?? false) && !$absentMorning) ? 0.5 : 0.0; + $afternoon = (($entry['isPresentAfternoon'] ?? false) && !$absentAfternoon) ? 0.5 : 0.0; $creditedPresence = $creditedPresenceByEmployeeDate[$employeeId][$date] ?? 0.0; $present = min(1.0, $morning + $afternoon + $creditedPresence); } diff --git a/tests/State/WorkHourWeeklySummaryProviderTest.php b/tests/State/WorkHourWeeklySummaryProviderTest.php index 24ac5ab..a3a441d 100644 --- a/tests/State/WorkHourWeeklySummaryProviderTest.php +++ b/tests/State/WorkHourWeeklySummaryProviderTest.php @@ -135,7 +135,7 @@ final class WorkHourWeeklySummaryProviderTest extends TestCase self::assertSame(210, $result->rows[0]->weeklyOvertime50Minutes); self::assertSame(1230, $result->rows[0]->weeklyRecoveryMinutes); - self::assertSame(1.0, $result->rows[1]->weeklyPresenceCount); + self::assertSame(0.0, $result->rows[1]->weeklyPresenceCount); self::assertTrue($result->rows[1]->daily[0]->hasAbsence); self::assertSame('Congé', $result->rows[1]->daily[0]->absenceLabel); self::assertSame('#000', $result->rows[1]->daily[0]->absenceColor);