feat : add contract end notification service and command
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user