feat: Bloquer la création de devoirs non conformes en mode hard
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.
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Application\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\Shared\Domain\Tenant\TenantId;
|
||||
|
||||
use function count;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ValidDueDateSuggesterTest extends TestCase
|
||||
{
|
||||
private ValidDueDateSuggester $suggester;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->suggester = new ValidDueDateSuggester(new HomeworkRulesValidator());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestsNextValidDatesForMinimumDelay(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecDelai(3);
|
||||
$creationDate = new DateTimeImmutable('2026-03-18 10:00'); // mercredi
|
||||
|
||||
// Requested date is too soon (jeudi 19 mars, only 1 day)
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-19'),
|
||||
$rules,
|
||||
$creationDate,
|
||||
);
|
||||
|
||||
self::assertNotEmpty($suggestions);
|
||||
self::assertLessThanOrEqual(3, count($suggestions));
|
||||
|
||||
// Each suggestion must be valid against the rules
|
||||
$validator = new HomeworkRulesValidator();
|
||||
foreach ($suggestions as $date) {
|
||||
self::assertInstanceOf(DateTimeImmutable::class, $date);
|
||||
$result = $validator->valider($rules, $date, $creationDate);
|
||||
self::assertTrue($result->estValide(), 'Suggested date ' . $date->format('Y-m-d') . ' should be valid');
|
||||
}
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestsUpToMaxSuggestions(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecDelai(3);
|
||||
$creationDate = new DateTimeImmutable('2026-03-18 10:00');
|
||||
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-19'),
|
||||
$rules,
|
||||
$creationDate,
|
||||
maxSuggestions: 5,
|
||||
);
|
||||
|
||||
self::assertCount(5, $suggestions);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function skipsWeekends(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecDelai(3);
|
||||
// Jeudi 19 mars, creation date is mercredi 18 mars
|
||||
$creationDate = new DateTimeImmutable('2026-03-18 10:00');
|
||||
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-19'),
|
||||
$rules,
|
||||
$creationDate,
|
||||
);
|
||||
|
||||
foreach ($suggestions as $date) {
|
||||
$dayOfWeek = (int) $date->format('N');
|
||||
self::assertLessThanOrEqual(5, $dayOfWeek, 'Suggested date ' . $date->format('Y-m-d') . ' should not be a weekend');
|
||||
}
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestsDatesInChronologicalOrder(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecDelai(3);
|
||||
$creationDate = new DateTimeImmutable('2026-03-18 10:00');
|
||||
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-19'),
|
||||
$rules,
|
||||
$creationDate,
|
||||
);
|
||||
|
||||
for ($i = 1; $i < count($suggestions); ++$i) {
|
||||
self::assertGreaterThan(
|
||||
$suggestions[$i - 1]->format('Y-m-d'),
|
||||
$suggestions[$i]->format('Y-m-d'),
|
||||
'Suggestions should be in chronological order',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function returnsEmptyWhenRulesDisabled(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecDelai(3, EnforcementMode::DISABLED, false);
|
||||
$creationDate = new DateTimeImmutable('2026-03-18 10:00');
|
||||
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-19'),
|
||||
$rules,
|
||||
$creationDate,
|
||||
);
|
||||
|
||||
self::assertEmpty($suggestions);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function searchIsBoundedAndDoesNotRunForever(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecDelai(30);
|
||||
$creationDate = new DateTimeImmutable('2026-03-18 10:00');
|
||||
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-19'),
|
||||
$rules,
|
||||
$creationDate,
|
||||
maxSuggestions: 100,
|
||||
);
|
||||
|
||||
// La recherche est bornée à 60 jours. Avec un délai de 30 jours,
|
||||
// seules les dates après le 17 avril sont valides (~21 jours ouvrés).
|
||||
self::assertNotEmpty($suggestions);
|
||||
self::assertLessThan(100, count($suggestions));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestsValidDatesForMondayRule(): void
|
||||
{
|
||||
$rules = $this->creerRulesAvecLundi();
|
||||
// Samedi 21 mars, trying to create homework for lundi 23 mars (after friday cutoff)
|
||||
$creationDate = new DateTimeImmutable('2026-03-21 10:00');
|
||||
|
||||
$suggestions = $this->suggester->suggerer(
|
||||
new DateTimeImmutable('2026-03-23'), // lundi
|
||||
$rules,
|
||||
$creationDate,
|
||||
);
|
||||
|
||||
self::assertNotEmpty($suggestions);
|
||||
|
||||
$validator = new HomeworkRulesValidator();
|
||||
foreach ($suggestions as $date) {
|
||||
$result = $validator->valider($rules, $date, $creationDate);
|
||||
self::assertTrue($result->estValide(), 'Suggested date ' . $date->format('Y-m-d') . ' should be valid');
|
||||
}
|
||||
}
|
||||
|
||||
private function creerRulesAvecDelai(
|
||||
int $days,
|
||||
EnforcementMode $mode = EnforcementMode::HARD,
|
||||
bool $enabled = true,
|
||||
): HomeworkRules {
|
||||
$rules = HomeworkRules::creer(
|
||||
tenantId: TenantId::fromString('550e8400-e29b-41d4-a716-446655440001'),
|
||||
now: new DateTimeImmutable('2026-03-01'),
|
||||
);
|
||||
|
||||
$rules->mettreAJour(
|
||||
rules: [new HomeworkRule(RuleType::MINIMUM_DELAY, ['days' => $days])],
|
||||
enforcementMode: $mode,
|
||||
enabled: $enabled,
|
||||
now: new DateTimeImmutable('2026-03-01'),
|
||||
);
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
private function creerRulesAvecLundi(
|
||||
EnforcementMode $mode = EnforcementMode::HARD,
|
||||
): HomeworkRules {
|
||||
$rules = HomeworkRules::creer(
|
||||
tenantId: TenantId::fromString('550e8400-e29b-41d4-a716-446655440001'),
|
||||
now: new DateTimeImmutable('2026-03-01'),
|
||||
);
|
||||
|
||||
$rules->mettreAJour(
|
||||
rules: [new HomeworkRule(RuleType::NO_MONDAY_AFTER, ['day' => 'friday', 'time' => '12:00'])],
|
||||
enforcementMode: $mode,
|
||||
enabled: true,
|
||||
now: new DateTimeImmutable('2026-03-01'),
|
||||
);
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
@@ -158,6 +158,33 @@ final class CreateHomeworkHandlerTest extends TestCase
|
||||
$handler($this->createCommand(acknowledgeWarning: true));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function hardBlockingExceptionCarriesSuggestedDatesAndBloquantFlag(): void
|
||||
{
|
||||
$warning = new RuleWarning(
|
||||
ruleType: 'minimum_delay',
|
||||
message: 'Le devoir doit être créé au moins 7 jours avant.',
|
||||
params: ['days' => 7],
|
||||
);
|
||||
$suggestedDates = ['2026-03-25', '2026-03-26', '2026-03-27'];
|
||||
$rulesResult = new HomeworkRulesCheckResult(
|
||||
warnings: [$warning],
|
||||
bloquant: true,
|
||||
suggestedDates: $suggestedDates,
|
||||
);
|
||||
$handler = $this->createHandler(affecte: true, rulesResult: $rulesResult);
|
||||
|
||||
try {
|
||||
$handler($this->createCommand(acknowledgeWarning: false));
|
||||
self::fail('Expected ReglesDevoirsNonRespecteesException');
|
||||
} catch (ReglesDevoirsNonRespecteesException $e) {
|
||||
self::assertTrue($e->bloquant);
|
||||
self::assertSame($suggestedDates, $e->suggestedDates);
|
||||
self::assertCount(1, $e->warnings);
|
||||
self::assertSame('minimum_delay', $e->warnings[0]['ruleType']);
|
||||
}
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function itCreatesHomeworkWhenSoftRulesViolatedButAcknowledged(): void
|
||||
{
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Scolarite\Application\Port;
|
||||
|
||||
use App\Scolarite\Application\Port\HomeworkRulesCheckResult;
|
||||
use App\Scolarite\Application\Port\RuleWarning;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class HomeworkRulesCheckResultTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function okReturnsValidNonBlockingResult(): void
|
||||
{
|
||||
$result = HomeworkRulesCheckResult::ok();
|
||||
|
||||
self::assertTrue($result->estValide());
|
||||
self::assertFalse($result->estAvertissement());
|
||||
self::assertFalse($result->estBloquant());
|
||||
self::assertEmpty($result->warnings);
|
||||
self::assertEmpty($result->suggestedDates);
|
||||
self::assertFalse($result->bloquant);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function estBloquantReturnsTrueWhenBloquantWithWarnings(): void
|
||||
{
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [$this->uneWarning()],
|
||||
bloquant: true,
|
||||
);
|
||||
|
||||
self::assertTrue($result->estBloquant());
|
||||
self::assertFalse($result->estAvertissement());
|
||||
self::assertFalse($result->estValide());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function estAvertissementReturnsTrueWhenNonBloquantWithWarnings(): void
|
||||
{
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [$this->uneWarning()],
|
||||
bloquant: false,
|
||||
);
|
||||
|
||||
self::assertTrue($result->estAvertissement());
|
||||
self::assertFalse($result->estBloquant());
|
||||
self::assertFalse($result->estValide());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function estValideReturnsFalseWhenBloquantWithoutWarnings(): void
|
||||
{
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [],
|
||||
bloquant: true,
|
||||
);
|
||||
|
||||
self::assertTrue($result->estValide());
|
||||
self::assertFalse($result->estBloquant());
|
||||
self::assertFalse($result->estAvertissement());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestedDatesAreStoredAndAccessible(): void
|
||||
{
|
||||
$dates = ['2026-03-25', '2026-03-26', '2026-03-27'];
|
||||
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [$this->uneWarning()],
|
||||
bloquant: true,
|
||||
suggestedDates: $dates,
|
||||
);
|
||||
|
||||
self::assertSame($dates, $result->suggestedDates);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function messagesReturnsWarningMessages(): void
|
||||
{
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [
|
||||
new RuleWarning('minimum_delay', 'Au moins 3 jours.', ['days' => 3]),
|
||||
new RuleWarning('no_monday_after', 'Pas après vendredi 12h.', []),
|
||||
],
|
||||
bloquant: false,
|
||||
);
|
||||
|
||||
self::assertSame([
|
||||
'Au moins 3 jours.',
|
||||
'Pas après vendredi 12h.',
|
||||
], $result->messages());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function ruleTypesReturnsWarningRuleTypes(): void
|
||||
{
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [
|
||||
new RuleWarning('minimum_delay', 'msg1', []),
|
||||
new RuleWarning('no_monday_after', 'msg2', []),
|
||||
],
|
||||
bloquant: false,
|
||||
);
|
||||
|
||||
self::assertSame(['minimum_delay', 'no_monday_after'], $result->ruleTypes());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function toArrayReturnsStructuredWarnings(): void
|
||||
{
|
||||
$result = new HomeworkRulesCheckResult(
|
||||
warnings: [
|
||||
new RuleWarning('minimum_delay', 'Au moins 3 jours.', ['days' => 3]),
|
||||
],
|
||||
bloquant: true,
|
||||
);
|
||||
|
||||
$expected = [
|
||||
[
|
||||
'ruleType' => 'minimum_delay',
|
||||
'message' => 'Au moins 3 jours.',
|
||||
'params' => ['days' => 3],
|
||||
],
|
||||
];
|
||||
|
||||
self::assertSame($expected, $result->toArray());
|
||||
}
|
||||
|
||||
private function uneWarning(): RuleWarning
|
||||
{
|
||||
return new RuleWarning(
|
||||
ruleType: 'minimum_delay',
|
||||
message: 'Le devoir doit être créé au moins 3 jours avant.',
|
||||
params: ['days' => 3],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Scolarite\Domain\Exception;
|
||||
|
||||
use App\Scolarite\Domain\Exception\ReglesDevoirsNonRespecteesException;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ReglesDevoirsNonRespecteesExceptionTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function blockingExceptionHasBlockingMessage(): void
|
||||
{
|
||||
$exception = new ReglesDevoirsNonRespecteesException(
|
||||
warnings: [['ruleType' => 'minimum_delay', 'message' => 'msg', 'params' => []]],
|
||||
bloquant: true,
|
||||
);
|
||||
|
||||
self::assertStringContainsString('Impossible de créer ce devoir', $exception->getMessage());
|
||||
self::assertStringContainsString('msg', $exception->getMessage());
|
||||
self::assertTrue($exception->bloquant);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function warningExceptionHasWarningMessage(): void
|
||||
{
|
||||
$exception = new ReglesDevoirsNonRespecteesException(
|
||||
warnings: [['ruleType' => 'minimum_delay', 'message' => 'msg', 'params' => []]],
|
||||
);
|
||||
|
||||
self::assertStringContainsString('ne respecte pas', $exception->getMessage());
|
||||
self::assertFalse($exception->bloquant);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestedDatesAreAccessible(): void
|
||||
{
|
||||
$dates = ['2026-03-25', '2026-03-26'];
|
||||
|
||||
$exception = new ReglesDevoirsNonRespecteesException(
|
||||
warnings: [['ruleType' => 'minimum_delay', 'message' => 'msg', 'params' => []]],
|
||||
bloquant: true,
|
||||
suggestedDates: $dates,
|
||||
);
|
||||
|
||||
self::assertSame($dates, $exception->suggestedDates);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function suggestedDatesDefaultToEmpty(): void
|
||||
{
|
||||
$exception = new ReglesDevoirsNonRespecteesException(
|
||||
warnings: [['ruleType' => 'minimum_delay', 'message' => 'msg', 'params' => []]],
|
||||
bloquant: true,
|
||||
);
|
||||
|
||||
self::assertEmpty($exception->suggestedDates);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function warningsAreAccessible(): void
|
||||
{
|
||||
$warnings = [
|
||||
['ruleType' => 'minimum_delay', 'message' => 'Au moins 3 jours.', 'params' => ['days' => 3]],
|
||||
['ruleType' => 'no_monday_after', 'message' => 'Pas après vendredi.', 'params' => []],
|
||||
];
|
||||
|
||||
$exception = new ReglesDevoirsNonRespecteesException(
|
||||
warnings: $warnings,
|
||||
bloquant: true,
|
||||
);
|
||||
|
||||
self::assertSame($warnings, $exception->warnings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user