Files
SIRH/tests/Service/WorkHours/WorkedHoursCreditPolicyTest.php
tristan a8fe244b5c
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
feat : modification de la gestion des jours fériés
2026-04-16 15:52:19 +02:00

144 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Service\WorkHours;
use App\Entity\Absence;
use App\Entity\AbsenceType;
use App\Entity\Contract;
use App\Entity\Employee;
use App\Service\Contracts\EmployeeContractResolver;
use App\Service\WorkHours\DailyReferenceMinutesResolver;
use App\Service\WorkHours\WorkedHoursCreditPolicy;
use DateTime;
use PHPUnit\Framework\TestCase;
/**
* @internal
*/
final class WorkedHoursCreditPolicyTest extends TestCase
{
public function testComputeCreditedMinutesFor35hHalfDay(): void
{
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver());
$absence = $this->buildAbsence(trackMode: Contract::TRACKING_TIME, weeklyHours: 35, countAsWorked: true);
$minutes = $policy->computeCreditedMinutes($absence, '2026-02-16', true, false);
self::assertSame(210, $minutes);
}
public function testComputeCreditedMinutesFor4hContractUsesWorkDaysSchedule(): void
{
// 4h contract with schedule Mon 2h + Thu 2h
$schedule = [1 => 120, 4 => 120];
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub($schedule), new DailyReferenceMinutesResolver());
$absence = $this->buildAbsence(trackMode: Contract::TRACKING_TIME, weeklyHours: 4, countAsWorked: true);
// 2026-02-16 is a Monday: full day absence credits 2h (matches scheduled Monday)
self::assertSame(120, $policy->computeCreditedMinutes($absence, '2026-02-16', true, true));
}
public function testComputeCreditedMinutesFor4hContractOnUnscheduledDayReturnsZero(): void
{
// 4h contract with schedule Mon 2h + Thu 2h
$schedule = [1 => 120, 4 => 120];
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub($schedule), new DailyReferenceMinutesResolver());
$absence = $this->buildAbsence(
trackMode: Contract::TRACKING_TIME,
weeklyHours: 4,
countAsWorked: true,
start: '2026-02-17',
end: '2026-02-17',
);
// 2026-02-17 is a Tuesday — not a scheduled workday → 0 credit
self::assertSame(0, $policy->computeCreditedMinutes($absence, '2026-02-17', true, true));
}
public function testComputeCreditedMinutesHalfDayOnAsymmetricScheduleDay(): void
{
// Asymmetric schedule: Monday is a 3h day (180 min)
$schedule = [1 => 180];
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub($schedule), new DailyReferenceMinutesResolver());
$absence = $this->buildAbsence(trackMode: Contract::TRACKING_TIME, weeklyHours: 3, countAsWorked: true);
// 2026-02-16 Monday, morning only → round(180/2 * 1) = 90 min
self::assertSame(90, $policy->computeCreditedMinutes($absence, '2026-02-16', true, false));
// Afternoon only → same 90 min (half of day)
self::assertSame(90, $policy->computeCreditedMinutes($absence, '2026-02-16', false, true));
// Full day → 180 min
self::assertSame(180, $policy->computeCreditedMinutes($absence, '2026-02-16', true, true));
}
public function testComputeCreditedPresenceUnitsForPresenceContract(): void
{
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver());
$absence = $this->buildAbsence(trackMode: Contract::TRACKING_PRESENCE, weeklyHours: null, countAsWorked: true);
// Forfait : les absences ne créditent jamais de présence, seules les checkboxes comptent.
self::assertSame(0.0, $policy->computeCreditedPresenceUnits($absence, '2026-02-16', true, false));
self::assertSame(0.0, $policy->computeCreditedPresenceUnits($absence, '2026-02-16', true, true));
}
public function testNoCreditWhenAbsenceTypeDoesNotCount(): void
{
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver());
$absence = $this->buildAbsence(trackMode: Contract::TRACKING_TIME, weeklyHours: 35, countAsWorked: false);
self::assertSame(0, $policy->computeCreditedMinutes($absence, '2026-02-16', true, true));
self::assertSame(0.0, $policy->computeCreditedPresenceUnits($absence, '2026-02-16', true, true));
}
private function buildAbsence(
string $trackMode,
?int $weeklyHours,
bool $countAsWorked,
string $start = '2026-02-16',
string $end = '2026-02-16',
): Absence {
$contract = new Contract()
->setName('Contrat test')
->setTrackingMode($trackMode)
->setWeeklyHours($weeklyHours)
;
$employee = new Employee()
->setFirstName('Alice')
->setLastName('Durand')
->setContract($contract)
;
$type = new AbsenceType()
->setCode('CP')
->setLabel('Congés')
->setColor('#000')
->setCountAsWorkedHours($countAsWorked)
;
return new Absence()
->setEmployee($employee)
->setType($type)
->setStartDate(new DateTime($start))
->setEndDate(new DateTime($end))
;
}
/**
* @param null|array<int, int> $schedule
*/
private function buildResolverStub(?array $schedule = null): EmployeeContractResolver
{
$resolver = $this->createStub(EmployeeContractResolver::class);
$resolver
->method('resolveForEmployeeAndDate')
->willReturnCallback(static fn (Employee $employee): ?Contract => $employee->getContract())
;
$resolver
->method('resolveWorkDaysMinutesForEmployeeAndDate')
->willReturn($schedule)
;
return $resolver;
}
}