Files
SIRH/src/Repository/WorkHourRepository.php
tristan 4a2c3a8eed
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
feat : Ajout du système de RTT sur la page employé avec le repport annuel des heures
2026-03-13 10:26:33 +01:00

213 lines
7.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\Employee;
use App\Entity\WorkHour;
use App\Repository\Contract\WorkHourReadRepositoryInterface;
use DateTimeImmutable;
use DateTimeInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<WorkHour>
*/
final class WorkHourRepository extends ServiceEntityRepository implements WorkHourReadRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, WorkHour::class);
}
/**
* @param list<Employee> $employees
*
* @return array<int, WorkHour>
*/
public function findByDateAndEmployeesIndexedByEmployeeId(DateTimeImmutable $workDate, array $employees): array
{
if ([] === $employees) {
return [];
}
$qb = $this->createQueryBuilder('w')
->leftJoin('w.employee', 'e')
->addSelect('e')
->andWhere('w.workDate = :workDate')
->andWhere('w.employee IN (:employees)')
->setParameter('workDate', $workDate)
->setParameter('employees', $employees)
;
/** @var list<WorkHour> $workHours */
$workHours = $qb->getQuery()->getResult();
$byEmployeeId = [];
foreach ($workHours as $workHour) {
$employeeId = $workHour->getEmployee()?->getId();
if ($employeeId) {
$byEmployeeId[$employeeId] = $workHour;
}
}
return $byEmployeeId;
}
/**
* @param list<Employee> $employees
*
* @return list<WorkHour>
*/
public function findByDateRangeAndEmployees(DateTimeImmutable $from, DateTimeImmutable $to, array $employees): array
{
if ([] === $employees) {
return [];
}
$qb = $this->createQueryBuilder('w')
->leftJoin('w.employee', 'e')
->addSelect('e')
->andWhere('w.workDate >= :from')
->andWhere('w.workDate <= :to')
->andWhere('w.employee IN (:employees)')
->setParameter('from', $from)
->setParameter('to', $to)
->setParameter('employees', $employees)
;
// @var list<WorkHour> $workHours
return $qb->getQuery()->getResult();
}
public function hasValidatedInRange(Employee $employee, DateTimeInterface $from, DateTimeInterface $to): bool
{
$fromDate = DateTimeImmutable::createFromInterface($from);
$toDate = DateTimeImmutable::createFromInterface($to);
$qb = $this->createQueryBuilder('w')
->select('COUNT(w.id)')
->andWhere('w.employee = :employee')
->andWhere('w.workDate >= :from')
->andWhere('w.workDate <= :to')
->andWhere('w.isValid = :isValid')
->setParameter('employee', $employee)
->setParameter('from', $fromDate)
->setParameter('to', $toDate)
->setParameter('isValid', true)
;
return ((int) $qb->getQuery()->getSingleScalarResult()) > 0;
}
public function hasSiteValidatedInRange(Employee $employee, DateTimeInterface $from, DateTimeInterface $to): bool
{
$fromDate = DateTimeImmutable::createFromInterface($from);
$toDate = DateTimeImmutable::createFromInterface($to);
$qb = $this->createQueryBuilder('w')
->select('COUNT(w.id)')
->andWhere('w.employee = :employee')
->andWhere('w.workDate >= :from')
->andWhere('w.workDate <= :to')
->andWhere('w.isSiteValid = :isSiteValid')
->setParameter('employee', $employee)
->setParameter('from', $fromDate)
->setParameter('to', $toDate)
->setParameter('isSiteValid', true)
;
return ((int) $qb->getQuery()->getSingleScalarResult()) > 0;
}
public function findOneByEmployeeAndDate(Employee $employee, DateTimeInterface $date): ?WorkHour
{
$workDate = DateTimeImmutable::createFromInterface($date);
$qb = $this->createQueryBuilder('w')
->andWhere('w.employee = :employee')
->andWhere('w.workDate = :workDate')
->setParameter('employee', $employee)
->setParameter('workDate', $workDate)
->setMaxResults(1)
;
// @var null|WorkHour $workHour
return $qb->getQuery()->getOneOrNullResult();
}
/**
* Count weekend worked days by month.
* >= 5h total = 1.0 day, < 5h = 0.5 day.
*
* @return array<string, float> YYYY-MM => weekend worked day count
*/
public function countWeekendWorkedDaysByMonth(Employee $employee, DateTimeImmutable $from, DateTimeImmutable $to): array
{
$sql = <<<'SQL'
SELECT TO_CHAR(work_date, 'YYYY-MM') AS month,
SUM(
CASE
WHEN total_minutes >= 300 THEN 1.0
WHEN total_minutes > 0 THEN 0.5
ELSE 0
END
) AS cnt
FROM (
SELECT work_date,
COALESCE(
EXTRACT(EPOCH FROM (morning_to::time - morning_from::time)) / 60, 0
)
+ COALESCE(
EXTRACT(EPOCH FROM (afternoon_to::time - afternoon_from::time)) / 60, 0
)
+ COALESCE(
EXTRACT(EPOCH FROM (evening_to::time - evening_from::time)) / 60, 0
) AS total_minutes
FROM work_hours
WHERE employee_id = :employee
AND work_date >= :from
AND work_date <= :to
AND EXTRACT(ISODOW FROM work_date) IN (6, 7)
AND (morning_from IS NOT NULL OR afternoon_from IS NOT NULL OR evening_from IS NOT NULL)
) sub
GROUP BY month
SQL;
$conn = $this->getEntityManager()->getConnection();
$rows = $conn->fetchAllAssociative($sql, [
'employee' => $employee->getId(),
'from' => $from->format('Y-m-d'),
'to' => $to->format('Y-m-d'),
]);
$result = [];
foreach ($rows as $row) {
$result[(string) $row['month']] = (float) $row['cnt'];
}
return $result;
}
public function hasPendingSiteValidationForSiteAndDate(int $siteId, DateTimeInterface $date): bool
{
$workDate = DateTimeImmutable::createFromInterface($date);
$qb = $this->createQueryBuilder('w')
->select('COUNT(w.id)')
->leftJoin('w.employee', 'e')
->leftJoin('e.site', 's')
->andWhere('s.id = :siteId')
->andWhere('w.workDate = :workDate')
->andWhere('w.isSiteValid = :isSiteValid')
->setParameter('siteId', $siteId)
->setParameter('workDate', $workDate)
->setParameter('isSiteValid', false)
;
return ((int) $qb->getQuery()->getSingleScalarResult()) > 0;
}
}