feat : modification de la gestion des jours fériés
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
This commit is contained in:
@@ -9,6 +9,7 @@ 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;
|
||||
@@ -20,7 +21,7 @@ final class WorkedHoursCreditPolicyTest extends TestCase
|
||||
{
|
||||
public function testComputeCreditedMinutesFor35hHalfDay(): void
|
||||
{
|
||||
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub());
|
||||
$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);
|
||||
@@ -28,19 +29,52 @@ final class WorkedHoursCreditPolicyTest extends TestCase
|
||||
self::assertSame(210, $minutes);
|
||||
}
|
||||
|
||||
public function testComputeCreditedMinutesFor4hContractFullDay(): void
|
||||
public function testComputeCreditedMinutesFor4hContractUsesWorkDaysSchedule(): void
|
||||
{
|
||||
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub());
|
||||
$absence = $this->buildAbsence(trackMode: Contract::TRACKING_TIME, weeklyHours: 4, countAsWorked: true);
|
||||
// 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);
|
||||
|
||||
$minutes = $policy->computeCreditedMinutes($absence, '2026-02-16', true, 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));
|
||||
}
|
||||
|
||||
self::assertSame(120, $minutes);
|
||||
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());
|
||||
$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.
|
||||
@@ -50,15 +84,20 @@ final class WorkedHoursCreditPolicyTest extends TestCase
|
||||
|
||||
public function testNoCreditWhenAbsenceTypeDoesNotCount(): void
|
||||
{
|
||||
$policy = new WorkedHoursCreditPolicy($this->buildResolverStub());
|
||||
$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): Absence
|
||||
{
|
||||
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)
|
||||
@@ -79,18 +118,25 @@ final class WorkedHoursCreditPolicyTest extends TestCase
|
||||
return new Absence()
|
||||
->setEmployee($employee)
|
||||
->setType($type)
|
||||
->setStartDate(new DateTime('2026-02-16'))
|
||||
->setEndDate(new DateTime('2026-02-16'))
|
||||
->setStartDate(new DateTime($start))
|
||||
->setEndDate(new DateTime($end))
|
||||
;
|
||||
}
|
||||
|
||||
private function buildResolverStub(): EmployeeContractResolver
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ use App\Enum\HalfDay;
|
||||
use App\Repository\Contract\AbsenceReadRepositoryInterface;
|
||||
use App\Repository\Contract\WorkHourReadRepositoryInterface;
|
||||
use App\Service\AuditLogger;
|
||||
use App\Service\PublicHolidayServiceInterface;
|
||||
use App\State\AbsenceWriteProcessor;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -37,7 +36,7 @@ final class AbsenceWriteProcessorTest extends TestCase
|
||||
$absenceRepository = $this->createMock(AbsenceReadRepositoryInterface::class);
|
||||
$workHourRepository = $this->createMock(WorkHourReadRepositoryInterface::class);
|
||||
$security = $this->createAdminSecurityStub();
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createEmptyHolidayServiceStub(), $this->createStub(AuditLogger::class));
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createStub(AuditLogger::class));
|
||||
|
||||
$absence = $this->buildAbsence('2026-02-16', '2026-02-18', HalfDay::AM, HalfDay::PM);
|
||||
|
||||
@@ -65,7 +64,7 @@ final class AbsenceWriteProcessorTest extends TestCase
|
||||
$absenceRepository = $this->createStub(AbsenceReadRepositoryInterface::class);
|
||||
$workHourRepository = $this->createMock(WorkHourReadRepositoryInterface::class);
|
||||
$security = $this->createAdminSecurityStub();
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createEmptyHolidayServiceStub(), $this->createStub(AuditLogger::class));
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createStub(AuditLogger::class));
|
||||
|
||||
$absence = $this->buildAbsence('2026-02-16', '2026-02-16', HalfDay::AM, HalfDay::PM);
|
||||
|
||||
@@ -86,7 +85,7 @@ final class AbsenceWriteProcessorTest extends TestCase
|
||||
$absenceRepository = $this->createStub(AbsenceReadRepositoryInterface::class);
|
||||
$workHourRepository = $this->createMock(WorkHourReadRepositoryInterface::class);
|
||||
$security = $this->createAdminSecurityStub();
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createEmptyHolidayServiceStub(), $this->createStub(AuditLogger::class));
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createStub(AuditLogger::class));
|
||||
|
||||
$absence = $this->buildAbsence('2026-02-16', '2026-02-16', HalfDay::AM, HalfDay::PM);
|
||||
|
||||
@@ -108,7 +107,7 @@ final class AbsenceWriteProcessorTest extends TestCase
|
||||
$absenceRepository = $this->createStub(AbsenceReadRepositoryInterface::class);
|
||||
$workHourRepository = $this->createStub(WorkHourReadRepositoryInterface::class);
|
||||
$security = $this->createAdminSecurityStub();
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createEmptyHolidayServiceStub(), $this->createStub(AuditLogger::class));
|
||||
$this->processor = new AbsenceWriteProcessor($entityManager, $absenceRepository, $workHourRepository, $security, $this->createStub(AuditLogger::class));
|
||||
|
||||
$absence = $this->buildAbsence('2026-02-16', '2026-02-16', HalfDay::PM, HalfDay::AM);
|
||||
|
||||
@@ -142,12 +141,4 @@ final class AbsenceWriteProcessorTest extends TestCase
|
||||
|
||||
return $security;
|
||||
}
|
||||
|
||||
private function createEmptyHolidayServiceStub(): PublicHolidayServiceInterface
|
||||
{
|
||||
$service = $this->createStub(PublicHolidayServiceInterface::class);
|
||||
$service->method('getHolidaysDayByYears')->willReturn([]);
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ use App\Repository\Contract\AbsenceReadRepositoryInterface;
|
||||
use App\Repository\Contract\EmployeeScopedRepositoryInterface;
|
||||
use App\Repository\Contract\FormationReadRepositoryInterface;
|
||||
use App\Service\Contracts\EmployeeContractResolver;
|
||||
use App\Service\PublicHolidayServiceInterface;
|
||||
use App\Service\WorkHours\AbsenceSegmentsResolver;
|
||||
use App\Service\WorkHours\DailyReferenceMinutesResolver;
|
||||
use App\Service\WorkHours\HolidayVirtualHoursResolver;
|
||||
use App\Service\WorkHours\WorkedHoursCreditPolicy;
|
||||
use App\State\WorkHourDayContextProvider;
|
||||
use DateTime;
|
||||
@@ -60,7 +63,8 @@ final class WorkHourDayContextProviderTest extends TestCase
|
||||
$this->formationRepository,
|
||||
$this->buildResolverStub(),
|
||||
new AbsenceSegmentsResolver(),
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub())
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver()),
|
||||
$this->buildHolidayResolver(),
|
||||
);
|
||||
|
||||
$this->expectException(AccessDeniedHttpException::class);
|
||||
@@ -80,7 +84,8 @@ final class WorkHourDayContextProviderTest extends TestCase
|
||||
$this->formationRepository,
|
||||
$this->buildResolverStub(),
|
||||
new AbsenceSegmentsResolver(),
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub())
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver()),
|
||||
$this->buildHolidayResolver(),
|
||||
);
|
||||
|
||||
$this->expectException(UnprocessableEntityHttpException::class);
|
||||
@@ -106,7 +111,8 @@ final class WorkHourDayContextProviderTest extends TestCase
|
||||
$this->formationRepository,
|
||||
$this->buildResolverStub(),
|
||||
new AbsenceSegmentsResolver(),
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub())
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver()),
|
||||
$this->buildHolidayResolver(),
|
||||
);
|
||||
|
||||
$result = $provider->provide(new Get());
|
||||
@@ -173,4 +179,16 @@ final class WorkHourDayContextProviderTest extends TestCase
|
||||
|
||||
return $resolver;
|
||||
}
|
||||
|
||||
private function buildHolidayResolver(): HolidayVirtualHoursResolver
|
||||
{
|
||||
$service = $this->createStub(PublicHolidayServiceInterface::class);
|
||||
$service->method('getHolidaysDayByYears')->willReturn([]);
|
||||
|
||||
return new HolidayVirtualHoursResolver(
|
||||
new DailyReferenceMinutesResolver(),
|
||||
$service,
|
||||
$this->createStub(EmployeeContractResolver::class),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@ use App\Repository\Contract\AbsenceReadRepositoryInterface;
|
||||
use App\Repository\Contract\EmployeeScopedRepositoryInterface;
|
||||
use App\Repository\Contract\WorkHourReadRepositoryInterface;
|
||||
use App\Service\Contracts\EmployeeContractResolver;
|
||||
use App\Service\PublicHolidayServiceInterface;
|
||||
use App\Service\WorkHours\AbsenceSegmentsResolver;
|
||||
use App\Service\WorkHours\DailyReferenceMinutesResolver;
|
||||
use App\Service\WorkHours\HolidayVirtualHoursResolver;
|
||||
use App\Service\WorkHours\WorkedHoursCreditPolicy;
|
||||
use App\State\WorkHourWeeklySummaryProvider;
|
||||
use DateTime;
|
||||
@@ -59,8 +62,10 @@ final class WorkHourWeeklySummaryProviderTest extends TestCase
|
||||
$this->workHourRepository,
|
||||
$this->absenceRepository,
|
||||
new AbsenceSegmentsResolver(),
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub()),
|
||||
$this->buildResolverStub()
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver()),
|
||||
$this->buildResolverStub(),
|
||||
new DailyReferenceMinutesResolver(),
|
||||
$this->buildHolidayResolver(),
|
||||
);
|
||||
|
||||
$this->expectException(AccessDeniedHttpException::class);
|
||||
@@ -119,8 +124,10 @@ final class WorkHourWeeklySummaryProviderTest extends TestCase
|
||||
$this->workHourRepository,
|
||||
$this->absenceRepository,
|
||||
new AbsenceSegmentsResolver(),
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub()),
|
||||
$this->buildWeeklyResolverStub($employees)
|
||||
new WorkedHoursCreditPolicy($this->buildResolverStub(), new DailyReferenceMinutesResolver()),
|
||||
$this->buildWeeklyResolverStub($employees),
|
||||
new DailyReferenceMinutesResolver(),
|
||||
$this->buildHolidayResolver(),
|
||||
);
|
||||
|
||||
$result = $provider->provide(new Get());
|
||||
@@ -171,6 +178,18 @@ final class WorkHourWeeklySummaryProviderTest extends TestCase
|
||||
$property->setValue($entity, $id);
|
||||
}
|
||||
|
||||
private function buildHolidayResolver(array $holidayMap = []): HolidayVirtualHoursResolver
|
||||
{
|
||||
$service = $this->createStub(PublicHolidayServiceInterface::class);
|
||||
$service->method('getHolidaysDayByYears')->willReturn($holidayMap);
|
||||
|
||||
return new HolidayVirtualHoursResolver(
|
||||
new DailyReferenceMinutesResolver(),
|
||||
$service,
|
||||
$this->createStub(EmployeeContractResolver::class),
|
||||
);
|
||||
}
|
||||
|
||||
private function buildResolverStub(): EmployeeContractResolver
|
||||
{
|
||||
$resolver = $this->createStub(EmployeeContractResolver::class);
|
||||
|
||||
Reference in New Issue
Block a user