feat : notification de fin de contrat (veille ouvrée du dernier jour) #35

Merged
tristan merged 10 commits from feature/SIRH-43-ajouter-une-notif-la-veille-d-un-contrat-qui-se-te into develop 2026-06-24 14:04:54 +00:00
3 changed files with 164 additions and 0 deletions
Showing only changes of commit baa824d2d2 - Show all commits
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace App\Command;
use App\Service\Notification\ContractEndNotificationService;
use DateTimeImmutable;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Throwable;
use function is_string;
#[AsCommand(
name: 'app:contract:end-notifications',
description: 'Notify admins on the last working day before a contract ends.'
)]
final class ContractEndNotificationCommand extends Command
{
public function __construct(
private readonly ContractEndNotificationService $service,
#[Autowire(service: 'monolog.logger.cron')]
private readonly LoggerInterface $logger,
) {
parent::__construct();
}
protected function configure(): void
{
$this->addOption(
'date',
null,
InputOption::VALUE_REQUIRED,
'Override the reference day (YYYY-MM-DD) for testing or manual catch-up.'
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$dateOption = $input->getOption('date');
try {
$today = is_string($dateOption) && '' !== $dateOption
? new DateTimeImmutable($dateOption)
: new DateTimeImmutable('today');
} catch (Throwable $exception) {
$io->error(sprintf('Invalid --date value: %s', $exception->getMessage()));
return Command::INVALID;
}
$result = $this->service->run($today);
$this->logger->info('Contract end notifications generated.', [
'date' => $today->format('Y-m-d'),
'contractsMatched' => $result->contractsMatched,
'notificationsCreated' => $result->notificationsCreated,
]);
$io->success(sprintf(
'%d notification(s) créée(s) pour %d fin(s) de contrat (%s).',
$result->notificationsCreated,
$result->contractsMatched,
$today->format('Y-m-d'),
));
return Command::SUCCESS;
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Service\Notification;
final readonly class ContractEndNotificationResult
{
public function __construct(
public int $notificationsCreated,
public int $contractsMatched,
) {}
}
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace App\Service\Notification;
use App\Entity\Notification;
use App\Repository\EmployeeContractPeriodRepository;
use App\Repository\NotificationRepository;
use App\Repository\UserRepository;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use function count;
final readonly class ContractEndNotificationService
{
private const CATEGORY = 'Contrat';
public function __construct(
private EmployeeContractPeriodRepository $periodRepository,
private NotificationRepository $notificationRepository,
private UserRepository $userRepository,
private ContractEndNotificationPlanner $planner,
private EntityManagerInterface $entityManager,
) {}
public function run(DateTimeImmutable $today): ContractEndNotificationResult
{
$latestPeriods = $this->periodRepository->findLatestPeriodsForAllEmployees();
$notices = $this->planner->plan($latestPeriods, $today);
if ([] === $notices) {
return new ContractEndNotificationResult(0, 0);
}
$admins = $this->userRepository->findAllAdmins();
$created = 0;
foreach ($notices as $notice) {
if (null === $notice->employeeId) {
continue;
}
$target = '/employees/'.$notice->employeeId;
foreach ($admins as $admin) {
if ($this->notificationRepository->existsForRecipientCategoryTargetMessage(
$admin,
self::CATEGORY,
$target,
$notice->message,
)) {
continue;
}
$notification = new Notification();
$notification->setRecipient($admin)
->setMessage($notice->message)
->setCategory(self::CATEGORY)
->setTarget($target)
;
$this->entityManager->persist($notification);
++$created;
}
}
$this->entityManager->flush();
return new ContractEndNotificationResult($created, count($notices));
}
}