getType(); // Certaines absences ne doivent jamais générer d'heures créditées. if (!$type?->getCountAsWorkedHours()) { return 0; } $employee = $absence->getEmployee(); if (null === $employee) { return 0; } $workDate = new DateTimeImmutable($dateYmd); $contract = $this->contractResolver->resolveForEmployeeAndDate($employee, $workDate); // Les contrats suivis en "présence" ne cumulent pas d'heures en minutes. if (TrackingMode::TIME->value !== $contract?->getTrackingMode()) { return 0; } $weekday = (int) $workDate->format('N'); $workDaysMinutes = $this->contractResolver->resolveWorkDaysMinutesForEmployeeAndDate($employee, $workDate); // Quand un planning est configuré sur la période (contrats non-standards), // il prime : jour non programmé = 0 crédit, sinon on utilise les minutes prévues. $dayMinutes = $this->resolveContractDayMinutes($contract?->getWeeklyHours(), $weekday, $workDaysMinutes); if ($dayMinutes <= 0) { return 0; } // Crédit en demi-journées: matin = 0.5, après-midi = 0.5. $halfUnits = ($absentMorning ? 1 : 0) + ($absentAfternoon ? 1 : 0); return (int) round(($dayMinutes / 2) * $halfUnits); } /** * @throws DateMalformedStringException */ public function computeCreditedPresenceUnits( Absence $absence, string $dateYmd, bool $absentMorning, bool $absentAfternoon ): float { $employee = $absence->getEmployee(); if (null === $employee) { return 0.0; } $contract = $this->contractResolver->resolveForEmployeeAndDate($employee, new DateTimeImmutable($dateYmd)); if (TrackingMode::PRESENCE->value !== $contract?->getTrackingMode()) { return 0.0; } // Règle forfait: les absences ne créditent jamais de présence. // Seules les checkboxes cochées par l'employé comptent. return 0.0; } /** * Single source of truth = {@see DailyReferenceMinutesResolver}. Weekend=0, * schedule precedence, 35h/39h fixed rules, fallback = weeklyHours/5. * * @param null|array $workDaysMinutes planning iso-day → minutes (priorité absolue si fourni) */ public function resolveContractDayMinutes(?int $weeklyHours, int $isoWeekDay, ?array $workDaysMinutes = null): int { return $this->dailyReferenceResolver->resolve($weeklyHours, $isoWeekDay, $workDaysMinutes); } }