Les administrateurs ont besoin d'un moyen simple pour inviter les parents à rejoindre la plateforme. Cette fonctionnalité permet de générer des codes d'invitation uniques (8 caractères alphanumériques) avec une validité de 48h, de les envoyer par email, et de les activer via une page publique dédiée qui crée automatiquement le compte parent. L'interface d'administration offre l'envoi unitaire et en masse, le renvoi, le filtrage par statut, ainsi que la visualisation de l'état de chaque invitation (en attente, activée, expirée).
124 lines
4.3 KiB
PHP
124 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Administration\Application\Command\SendParentInvitation;
|
|
|
|
use App\Administration\Application\Command\SendParentInvitation\SendParentInvitationCommand;
|
|
use App\Administration\Application\Command\SendParentInvitation\SendParentInvitationHandler;
|
|
use App\Administration\Application\Service\InvitationCodeGenerator;
|
|
use App\Administration\Domain\Event\InvitationParentEnvoyee;
|
|
use App\Administration\Domain\Model\Invitation\InvitationStatus;
|
|
use App\Administration\Domain\Model\User\Role;
|
|
use App\Administration\Domain\Model\User\StatutCompte;
|
|
use App\Administration\Domain\Model\User\User;
|
|
use App\Administration\Domain\Model\User\UserId;
|
|
use App\Administration\Infrastructure\Persistence\InMemory\InMemoryParentInvitationRepository;
|
|
use App\Administration\Infrastructure\Persistence\InMemory\InMemoryUserRepository;
|
|
use App\Shared\Domain\Clock;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class SendParentInvitationHandlerTest extends TestCase
|
|
{
|
|
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440002';
|
|
|
|
private InMemoryParentInvitationRepository $repository;
|
|
private InMemoryUserRepository $userRepository;
|
|
private SendParentInvitationHandler $handler;
|
|
private string $studentId;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->repository = new InMemoryParentInvitationRepository();
|
|
$this->userRepository = new InMemoryUserRepository();
|
|
|
|
$this->studentId = (string) UserId::generate();
|
|
|
|
$student = User::reconstitute(
|
|
id: UserId::fromString($this->studentId),
|
|
email: null,
|
|
roles: [Role::ELEVE],
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
schoolName: 'Test School',
|
|
statut: StatutCompte::INSCRIT,
|
|
dateNaissance: null,
|
|
createdAt: new DateTimeImmutable('2026-01-01'),
|
|
hashedPassword: null,
|
|
activatedAt: null,
|
|
consentementParental: null,
|
|
firstName: 'Camille',
|
|
lastName: 'Test',
|
|
);
|
|
$this->userRepository->save($student);
|
|
|
|
$clock = new class implements Clock {
|
|
public function now(): DateTimeImmutable
|
|
{
|
|
return new DateTimeImmutable('2026-02-07 10:00:00');
|
|
}
|
|
};
|
|
|
|
$this->handler = new SendParentInvitationHandler(
|
|
$this->repository,
|
|
$this->userRepository,
|
|
new InvitationCodeGenerator(),
|
|
$clock,
|
|
);
|
|
}
|
|
|
|
#[Test]
|
|
public function itCreatesAndSendsInvitation(): void
|
|
{
|
|
$createdBy = (string) UserId::generate();
|
|
|
|
$invitation = ($this->handler)(new SendParentInvitationCommand(
|
|
tenantId: self::TENANT_ID,
|
|
studentId: $this->studentId,
|
|
parentEmail: 'parent@example.com',
|
|
createdBy: $createdBy,
|
|
));
|
|
|
|
self::assertSame(InvitationStatus::SENT, $invitation->status);
|
|
self::assertSame('parent@example.com', (string) $invitation->parentEmail);
|
|
self::assertSame($this->studentId, (string) $invitation->studentId);
|
|
self::assertNotNull($invitation->sentAt);
|
|
}
|
|
|
|
#[Test]
|
|
public function itPersistsTheInvitation(): void
|
|
{
|
|
$createdBy = (string) UserId::generate();
|
|
|
|
$invitation = ($this->handler)(new SendParentInvitationCommand(
|
|
tenantId: self::TENANT_ID,
|
|
studentId: $this->studentId,
|
|
parentEmail: 'parent@example.com',
|
|
createdBy: $createdBy,
|
|
));
|
|
|
|
$found = $this->repository->findById($invitation->id, TenantId::fromString(self::TENANT_ID));
|
|
self::assertNotNull($found);
|
|
self::assertSame((string) $invitation->id, (string) $found->id);
|
|
}
|
|
|
|
#[Test]
|
|
public function itRecordsInvitationSentEvent(): void
|
|
{
|
|
$createdBy = (string) UserId::generate();
|
|
|
|
$invitation = ($this->handler)(new SendParentInvitationCommand(
|
|
tenantId: self::TENANT_ID,
|
|
studentId: $this->studentId,
|
|
parentEmail: 'parent@example.com',
|
|
createdBy: $createdBy,
|
|
));
|
|
|
|
$events = $invitation->pullDomainEvents();
|
|
self::assertCount(1, $events);
|
|
self::assertInstanceOf(InvitationParentEnvoyee::class, $events[0]);
|
|
}
|
|
}
|