Les établissements utilisant le mode "Hard" des règles de devoirs empêchent désormais les enseignants de créer des devoirs hors règles. Contrairement au mode "Soft" (avertissement avec possibilité de passer outre), le mode "Hard" est un blocage strict : même acknowledgeWarning ne permet pas de contourner. L'API retourne 422 (au lieu de 409 pour le soft) avec des dates conformes suggérées calculées via le calendrier scolaire (weekends, fériés, vacances exclus). Le frontend affiche un modal de blocage avec les raisons, des dates cliquables, et une validation client inline qui empêche la soumission de dates non conformes.
190 lines
6.4 KiB
PHP
190 lines
6.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Scolarite\Infrastructure\Service;
|
|
|
|
use App\Administration\Application\Service\HomeworkRulesValidator;
|
|
use App\Administration\Application\Service\ValidDueDateSuggester;
|
|
use App\Administration\Domain\Model\HomeworkRules\EnforcementMode;
|
|
use App\Administration\Domain\Model\HomeworkRules\HomeworkRule;
|
|
use App\Administration\Domain\Model\HomeworkRules\HomeworkRules;
|
|
use App\Administration\Domain\Model\HomeworkRules\RuleType;
|
|
use App\Administration\Domain\Model\SchoolCalendar\SchoolCalendar;
|
|
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
|
|
use App\Administration\Domain\Repository\HomeworkRulesRepository;
|
|
use App\Scolarite\Application\Port\CurrentCalendarProvider;
|
|
use App\Scolarite\Infrastructure\Service\AdministrationHomeworkRulesChecker;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
use RuntimeException;
|
|
|
|
final class AdministrationHomeworkRulesCheckerTest extends TestCase
|
|
{
|
|
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
|
|
|
|
private HomeworkRulesValidator $validator;
|
|
private ValidDueDateSuggester $suggester;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->validator = new HomeworkRulesValidator();
|
|
$this->suggester = new ValidDueDateSuggester($this->validator);
|
|
}
|
|
|
|
#[Test]
|
|
public function returnsOkWhenNoRulesConfigured(): void
|
|
{
|
|
$checker = $this->createChecker(rules: null);
|
|
$tenantId = TenantId::fromString(self::TENANT_ID);
|
|
|
|
$result = $checker->verifier(
|
|
$tenantId,
|
|
new DateTimeImmutable('2026-03-25'),
|
|
new DateTimeImmutable('2026-03-18 10:00'),
|
|
);
|
|
|
|
self::assertTrue($result->estValide());
|
|
self::assertFalse($result->bloquant);
|
|
self::assertEmpty($result->suggestedDates);
|
|
}
|
|
|
|
#[Test]
|
|
public function returnsOkWhenRulesRespected(): void
|
|
{
|
|
$rules = $this->creerRulesAvecDelai(3, EnforcementMode::HARD);
|
|
$checker = $this->createChecker(rules: $rules);
|
|
$tenantId = TenantId::fromString(self::TENANT_ID);
|
|
|
|
$result = $checker->verifier(
|
|
$tenantId,
|
|
new DateTimeImmutable('2026-03-25'), // 7 days ahead, > 3 day min
|
|
new DateTimeImmutable('2026-03-18 10:00'),
|
|
);
|
|
|
|
self::assertTrue($result->estValide());
|
|
self::assertEmpty($result->suggestedDates);
|
|
}
|
|
|
|
#[Test]
|
|
public function returnsBlockingResultWithSuggestedDatesInHardMode(): void
|
|
{
|
|
$rules = $this->creerRulesAvecDelai(7, EnforcementMode::HARD);
|
|
$checker = $this->createChecker(rules: $rules);
|
|
$tenantId = TenantId::fromString(self::TENANT_ID);
|
|
|
|
$result = $checker->verifier(
|
|
$tenantId,
|
|
new DateTimeImmutable('2026-03-19'), // only 1 day ahead, < 7 day min
|
|
new DateTimeImmutable('2026-03-18 10:00'),
|
|
);
|
|
|
|
self::assertTrue($result->estBloquant());
|
|
self::assertTrue($result->bloquant);
|
|
self::assertNotEmpty($result->suggestedDates);
|
|
self::assertCount(3, $result->suggestedDates);
|
|
|
|
// Suggested dates are formatted as Y-m-d strings
|
|
foreach ($result->suggestedDates as $date) {
|
|
self::assertMatchesRegularExpression('/^\d{4}-\d{2}-\d{2}$/', $date);
|
|
}
|
|
}
|
|
|
|
#[Test]
|
|
public function returnsWarningWithoutSuggestedDatesInSoftMode(): void
|
|
{
|
|
$rules = $this->creerRulesAvecDelai(7, EnforcementMode::SOFT);
|
|
$checker = $this->createChecker(rules: $rules);
|
|
$tenantId = TenantId::fromString(self::TENANT_ID);
|
|
|
|
$result = $checker->verifier(
|
|
$tenantId,
|
|
new DateTimeImmutable('2026-03-19'), // only 1 day ahead, < 7 day min
|
|
new DateTimeImmutable('2026-03-18 10:00'),
|
|
);
|
|
|
|
self::assertTrue($result->estAvertissement());
|
|
self::assertFalse($result->bloquant);
|
|
self::assertEmpty($result->suggestedDates);
|
|
}
|
|
|
|
#[Test]
|
|
public function warningsContainRuleParams(): void
|
|
{
|
|
$rules = $this->creerRulesAvecDelai(5, EnforcementMode::SOFT);
|
|
$checker = $this->createChecker(rules: $rules);
|
|
$tenantId = TenantId::fromString(self::TENANT_ID);
|
|
|
|
$result = $checker->verifier(
|
|
$tenantId,
|
|
new DateTimeImmutable('2026-03-19'),
|
|
new DateTimeImmutable('2026-03-18 10:00'),
|
|
);
|
|
|
|
self::assertCount(1, $result->warnings);
|
|
self::assertSame('minimum_delay', $result->warnings[0]->ruleType);
|
|
self::assertSame(['days' => 5], $result->warnings[0]->params);
|
|
}
|
|
|
|
private function createChecker(?HomeworkRules $rules): AdministrationHomeworkRulesChecker
|
|
{
|
|
$repository = new class($rules) implements HomeworkRulesRepository {
|
|
public function __construct(private readonly ?HomeworkRules $rules)
|
|
{
|
|
}
|
|
|
|
public function save(HomeworkRules $homeworkRules): void
|
|
{
|
|
}
|
|
|
|
public function get(TenantId $tenantId): HomeworkRules
|
|
{
|
|
return $this->rules ?? throw new RuntimeException('Not found');
|
|
}
|
|
|
|
public function findByTenantId(TenantId $tenantId): ?HomeworkRules
|
|
{
|
|
return $this->rules;
|
|
}
|
|
};
|
|
|
|
$calendarProvider = new class implements CurrentCalendarProvider {
|
|
public function forCurrentYear(TenantId $tenantId): SchoolCalendar
|
|
{
|
|
return SchoolCalendar::reconstitute(
|
|
tenantId: $tenantId,
|
|
academicYearId: AcademicYearId::fromString('550e8400-e29b-41d4-a716-446655440002'),
|
|
zone: null,
|
|
entries: [],
|
|
);
|
|
}
|
|
};
|
|
|
|
return new AdministrationHomeworkRulesChecker(
|
|
$repository,
|
|
$this->validator,
|
|
$this->suggester,
|
|
$calendarProvider,
|
|
);
|
|
}
|
|
|
|
private function creerRulesAvecDelai(int $days, EnforcementMode $mode): HomeworkRules
|
|
{
|
|
$rules = HomeworkRules::creer(
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
now: new DateTimeImmutable('2026-03-01'),
|
|
);
|
|
|
|
$rules->mettreAJour(
|
|
rules: [new HomeworkRule(RuleType::MINIMUM_DELAY, ['days' => $days])],
|
|
enforcementMode: $mode,
|
|
enabled: true,
|
|
now: new DateTimeImmutable('2026-03-01'),
|
|
);
|
|
|
|
return $rules;
|
|
}
|
|
}
|