fix : wip
This commit is contained in:
50
src/Service/WorkHours/AbsenceSegmentsResolver.php
Normal file
50
src/Service/WorkHours/AbsenceSegmentsResolver.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\WorkHours;
|
||||
|
||||
use App\Entity\Absence;
|
||||
use App\Enum\HalfDay;
|
||||
|
||||
final class AbsenceSegmentsResolver
|
||||
{
|
||||
/**
|
||||
* @return array{bool, bool}
|
||||
*/
|
||||
public function resolveForDate(Absence $absence, string $dateYmd): array
|
||||
{
|
||||
$startDate = $absence->getStartDate()->format('Y-m-d');
|
||||
$endDate = $absence->getEndDate()->format('Y-m-d');
|
||||
$startHalf = $absence->getStartHalf();
|
||||
$endHalf = $absence->getEndHalf();
|
||||
|
||||
// Cas d'une absence sur une seule date: on déduit matin/après-midi depuis les bornes.
|
||||
if ($startDate === $endDate) {
|
||||
if (HalfDay::AM === $startHalf && HalfDay::AM === $endHalf) {
|
||||
// Uniquement le matin absent.
|
||||
return [true, false];
|
||||
}
|
||||
if (HalfDay::PM === $startHalf && HalfDay::PM === $endHalf) {
|
||||
// Uniquement l'après-midi absent.
|
||||
return [false, true];
|
||||
}
|
||||
|
||||
// Sinon, on considère la journée complète absente.
|
||||
return [true, true];
|
||||
}
|
||||
|
||||
// Premier jour d'une absence multi-jours qui commence l'après-midi.
|
||||
if ($dateYmd === $startDate && HalfDay::PM === $startHalf) {
|
||||
return [false, true];
|
||||
}
|
||||
|
||||
// Dernier jour d'une absence multi-jours qui se termine le matin.
|
||||
if ($dateYmd === $endDate && HalfDay::AM === $endHalf) {
|
||||
return [true, false];
|
||||
}
|
||||
|
||||
// Les jours intermédiaires sont entièrement absents.
|
||||
return [true, true];
|
||||
}
|
||||
}
|
||||
91
src/Service/WorkHours/WorkedHoursCreditPolicy.php
Normal file
91
src/Service/WorkHours/WorkedHoursCreditPolicy.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\WorkHours;
|
||||
|
||||
use App\Entity\Absence;
|
||||
use App\Entity\Contract;
|
||||
use DateMalformedStringException;
|
||||
use DateTimeImmutable;
|
||||
|
||||
final class WorkedHoursCreditPolicy
|
||||
{
|
||||
/**
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function computeCreditedMinutes(Absence $absence, string $dateYmd, bool $absentMorning, bool $absentAfternoon): int
|
||||
{
|
||||
$type = $absence->getType();
|
||||
// Certaines absences ne doivent jamais générer d'heures créditées.
|
||||
if (!$type?->getCountAsWorkedHours()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$employee = $absence->getEmployee();
|
||||
// Les contrats suivis en "présence" ne cumulent pas d'heures en minutes.
|
||||
if (Contract::TRACKING_TIME !== $employee?->getContract()?->getTrackingMode()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$weekday = (int) new DateTimeImmutable($dateYmd)->format('N');
|
||||
// On applique la règle de crédit dépendante du contrat (35h / 39h / fallback).
|
||||
$dayMinutes = $this->resolveContractDayMinutes($employee->getContract()?->getWeeklyHours(), $weekday);
|
||||
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);
|
||||
}
|
||||
|
||||
public function computeCreditedPresenceUnits(Absence $absence, bool $absentMorning, bool $absentAfternoon): float
|
||||
{
|
||||
$type = $absence->getType();
|
||||
if (!$type?->getCountAsWorkedHours()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$employee = $absence->getEmployee();
|
||||
if (Contract::TRACKING_PRESENCE !== $employee?->getContract()?->getTrackingMode()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$halfUnits = ($absentMorning ? 1 : 0) + ($absentAfternoon ? 1 : 0);
|
||||
|
||||
return $halfUnits * 0.5;
|
||||
}
|
||||
|
||||
public function resolveContractDayMinutes(?int $weeklyHours, int $isoWeekDay): int
|
||||
{
|
||||
// Week-end non travaillé dans cette politique.
|
||||
if ($isoWeekDay >= 6) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Règle fixe: 35h => 7h/jour.
|
||||
if (35 === $weeklyHours) {
|
||||
return 7 * 60;
|
||||
}
|
||||
|
||||
// Règle fixe: 39h => 8h lundi-jeudi, 7h le vendredi.
|
||||
if (39 === $weeklyHours) {
|
||||
return 5 === $isoWeekDay ? 7 * 60 : 8 * 60;
|
||||
}
|
||||
|
||||
// Cas spécifique métier: contrat 4h/semaine réparti sur 2 jours => 2h/jour.
|
||||
if (4 === $weeklyHours) {
|
||||
return 2 * 60;
|
||||
}
|
||||
|
||||
// Contrat non renseigné/invalide: aucun crédit.
|
||||
if (null === $weeklyHours || $weeklyHours <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fallback générique: répartition homogène sur 5 jours ouvrés.
|
||||
return (int) round(($weeklyHours * 60) / 5);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user