feat: Permettre la création et modification de l'emploi du temps des classes
L'administration a besoin de construire et maintenir les emplois du temps hebdomadaires pour chaque classe, en s'assurant que les enseignants ne sont pas en conflit (même créneau, classes différentes) et que les affectations enseignant-matière-classe sont respectées. Cette implémentation couvre le CRUD complet des créneaux (ScheduleSlot), la détection de conflits (classe, enseignant, salle) avec possibilité de forcer, la validation des affectations côté serveur (AC2), l'intégration calendrier pour les jours bloqués, une vue mobile-first avec onglets jour par jour, et le drag-and-drop pour réorganiser les créneaux sur desktop.
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Scolarite\Application\Query\GetBlockedDates;
|
||||
|
||||
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntry;
|
||||
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId;
|
||||
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryType;
|
||||
use App\Administration\Domain\Model\SchoolCalendar\SchoolCalendar;
|
||||
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
|
||||
use App\Administration\Infrastructure\Persistence\InMemory\InMemorySchoolCalendarRepository;
|
||||
use App\Scolarite\Application\Query\GetBlockedDates\GetBlockedDatesHandler;
|
||||
use App\Scolarite\Application\Query\GetBlockedDates\GetBlockedDatesQuery;
|
||||
use App\Shared\Domain\Tenant\TenantId;
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class GetBlockedDatesHandlerTest extends TestCase
|
||||
{
|
||||
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
|
||||
private const string ACADEMIC_YEAR_ID = '550e8400-e29b-41d4-a716-446655440050';
|
||||
|
||||
private InMemorySchoolCalendarRepository $calendarRepository;
|
||||
private GetBlockedDatesHandler $handler;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->calendarRepository = new InMemorySchoolCalendarRepository();
|
||||
$this->handler = new GetBlockedDatesHandler($this->calendarRepository);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function returnsWeekendsAsBlocked(): void
|
||||
{
|
||||
// 2026-03-02 est un lundi, 2026-03-08 est un dimanche
|
||||
$result = ($this->handler)(new GetBlockedDatesQuery(
|
||||
tenantId: self::TENANT_ID,
|
||||
academicYearId: self::ACADEMIC_YEAR_ID,
|
||||
startDate: '2026-03-02',
|
||||
endDate: '2026-03-08',
|
||||
));
|
||||
|
||||
$weekendDates = array_filter($result, static fn ($d) => $d->type === 'weekend');
|
||||
|
||||
self::assertCount(2, $weekendDates);
|
||||
$dates = array_map(static fn ($d) => $d->date, array_values($weekendDates));
|
||||
self::assertContains('2026-03-07', $dates);
|
||||
self::assertContains('2026-03-08', $dates);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function returnsHolidaysAsBlocked(): void
|
||||
{
|
||||
$calendar = $this->createCalendarWithHoliday(
|
||||
new DateTimeImmutable('2026-03-04'),
|
||||
'Jour de test',
|
||||
);
|
||||
$this->calendarRepository->save($calendar);
|
||||
|
||||
$result = ($this->handler)(new GetBlockedDatesQuery(
|
||||
tenantId: self::TENANT_ID,
|
||||
academicYearId: self::ACADEMIC_YEAR_ID,
|
||||
startDate: '2026-03-02',
|
||||
endDate: '2026-03-06',
|
||||
));
|
||||
|
||||
$holidays = array_filter($result, static fn ($d) => $d->type === CalendarEntryType::HOLIDAY->value);
|
||||
|
||||
self::assertCount(1, $holidays);
|
||||
$holiday = array_values($holidays)[0];
|
||||
self::assertSame('2026-03-04', $holiday->date);
|
||||
self::assertSame('Jour de test', $holiday->reason);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function returnsEmptyForWeekWithNoBlockedDates(): void
|
||||
{
|
||||
// Lundi à vendredi sans calendrier configuré
|
||||
$result = ($this->handler)(new GetBlockedDatesQuery(
|
||||
tenantId: self::TENANT_ID,
|
||||
academicYearId: self::ACADEMIC_YEAR_ID,
|
||||
startDate: '2026-03-02',
|
||||
endDate: '2026-03-06',
|
||||
));
|
||||
|
||||
self::assertEmpty($result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function returnsVacationsAsBlocked(): void
|
||||
{
|
||||
$calendar = $this->createCalendarWithVacation(
|
||||
new DateTimeImmutable('2026-03-02'),
|
||||
new DateTimeImmutable('2026-03-06'),
|
||||
'Vacances de printemps',
|
||||
);
|
||||
$this->calendarRepository->save($calendar);
|
||||
|
||||
$result = ($this->handler)(new GetBlockedDatesQuery(
|
||||
tenantId: self::TENANT_ID,
|
||||
academicYearId: self::ACADEMIC_YEAR_ID,
|
||||
startDate: '2026-03-02',
|
||||
endDate: '2026-03-06',
|
||||
));
|
||||
|
||||
$vacations = array_filter($result, static fn ($d) => $d->type === CalendarEntryType::VACATION->value);
|
||||
|
||||
self::assertCount(5, $vacations);
|
||||
}
|
||||
|
||||
private function createCalendarWithHoliday(DateTimeImmutable $date, string $label): SchoolCalendar
|
||||
{
|
||||
$tenantId = TenantId::fromString(self::TENANT_ID);
|
||||
$academicYearId = AcademicYearId::fromString(self::ACADEMIC_YEAR_ID);
|
||||
|
||||
$calendar = SchoolCalendar::initialiser($tenantId, $academicYearId);
|
||||
$calendar->ajouterEntree(new CalendarEntry(
|
||||
id: CalendarEntryId::generate(),
|
||||
type: CalendarEntryType::HOLIDAY,
|
||||
startDate: $date,
|
||||
endDate: $date,
|
||||
label: $label,
|
||||
));
|
||||
|
||||
return $calendar;
|
||||
}
|
||||
|
||||
private function createCalendarWithVacation(
|
||||
DateTimeImmutable $startDate,
|
||||
DateTimeImmutable $endDate,
|
||||
string $label,
|
||||
): SchoolCalendar {
|
||||
$tenantId = TenantId::fromString(self::TENANT_ID);
|
||||
$academicYearId = AcademicYearId::fromString(self::ACADEMIC_YEAR_ID);
|
||||
|
||||
$calendar = SchoolCalendar::initialiser($tenantId, $academicYearId);
|
||||
$calendar->ajouterEntree(new CalendarEntry(
|
||||
id: CalendarEntryId::generate(),
|
||||
type: CalendarEntryType::VACATION,
|
||||
startDate: $startDate,
|
||||
endDate: $endDate,
|
||||
label: $label,
|
||||
));
|
||||
|
||||
return $calendar;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user