Files
Classeo/backend/tests/Unit/Scolarite/Application/Command/TruncateSlotRecurrence/TruncateSlotRecurrenceHandlerTest.php
Mathias STRASSER ae640e91ac
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Naming Conventions (push) Has been cancelled
CI / Build Check (push) Has been cancelled
feat: Permettre la définition d'une semaine type récurrente pour l'emploi du temps
Les administrateurs devaient recréer manuellement l'emploi du temps chaque
semaine. Cette implémentation introduit un système de récurrence hebdomadaire
avec gestion des exceptions par occurrence, permettant de modifier ou annuler
un cours spécifique sans affecter les autres semaines.

Le ScheduleResolver calcule dynamiquement l'EDT réel en combinant les créneaux
récurrents, les exceptions ponctuelles et le calendrier scolaire (vacances/fériés).
2026-03-05 02:36:34 +01:00

115 lines
4.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Unit\Scolarite\Application\Command\TruncateSlotRecurrence;
use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Application\Command\TruncateSlotRecurrence\TruncateSlotRecurrenceCommand;
use App\Scolarite\Application\Command\TruncateSlotRecurrence\TruncateSlotRecurrenceHandler;
use App\Scolarite\Domain\Exception\DateExceptionInvalideException;
use App\Scolarite\Domain\Model\Schedule\DayOfWeek;
use App\Scolarite\Domain\Model\Schedule\ScheduleSlot;
use App\Scolarite\Domain\Model\Schedule\TimeSlot;
use App\Scolarite\Infrastructure\Persistence\InMemory\InMemoryScheduleSlotRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
final class TruncateSlotRecurrenceHandlerTest extends TestCase
{
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
private const string CLASS_ID = '550e8400-e29b-41d4-a716-446655440020';
private const string SUBJECT_ID = '550e8400-e29b-41d4-a716-446655440030';
private const string TEACHER_ID = '550e8400-e29b-41d4-a716-446655440010';
private const string UPDATER_ID = '550e8400-e29b-41d4-a716-446655440099';
private InMemoryScheduleSlotRepository $slotRepository;
private TruncateSlotRecurrenceHandler $handler;
protected function setUp(): void
{
$this->slotRepository = new InMemoryScheduleSlotRepository();
$clock = new class implements Clock {
public function now(): DateTimeImmutable
{
return new DateTimeImmutable('2026-10-01 10:00:00');
}
};
$this->handler = new TruncateSlotRecurrenceHandler(
$this->slotRepository,
$clock,
);
}
#[Test]
public function truncatesRecurrenceOneDayBeforeGivenDate(): void
{
$slot = $this->createAndSaveSlot(
recurrenceStart: new DateTimeImmutable('2026-09-01'),
recurrenceEnd: new DateTimeImmutable('2027-07-04'),
);
$command = new TruncateSlotRecurrenceCommand(
tenantId: self::TENANT_ID,
slotId: (string) $slot->id,
fromDate: '2026-10-05',
updatedBy: self::UPDATER_ID,
);
($this->handler)($command);
$tenantId = TenantId::fromString(self::TENANT_ID);
$updated = $this->slotRepository->get($slot->id, $tenantId);
self::assertSame('2026-10-04', $updated->recurrenceEnd->format('Y-m-d'));
}
#[Test]
public function throwsWhenDateIsNotActiveForSlot(): void
{
$slot = $this->createAndSaveSlot(
recurrenceStart: new DateTimeImmutable('2026-09-01'),
recurrenceEnd: new DateTimeImmutable('2026-09-28'),
);
$command = new TruncateSlotRecurrenceCommand(
tenantId: self::TENANT_ID,
slotId: (string) $slot->id,
fromDate: '2026-10-05',
updatedBy: self::UPDATER_ID,
);
$this->expectException(DateExceptionInvalideException::class);
($this->handler)($command);
}
private function createAndSaveSlot(
?DateTimeImmutable $recurrenceStart = null,
?DateTimeImmutable $recurrenceEnd = null,
): ScheduleSlot {
$slot = ScheduleSlot::creer(
tenantId: TenantId::fromString(self::TENANT_ID),
classId: ClassId::fromString(self::CLASS_ID),
subjectId: SubjectId::fromString(self::SUBJECT_ID),
teacherId: UserId::fromString(self::TEACHER_ID),
dayOfWeek: DayOfWeek::MONDAY,
timeSlot: new TimeSlot('08:00', '09:00'),
room: null,
isRecurring: true,
now: new DateTimeImmutable('2026-09-01 10:00:00'),
recurrenceStart: $recurrenceStart,
recurrenceEnd: $recurrenceEnd,
);
$this->slotRepository->save($slot);
return $slot;
}
}