diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml index 06b67a2..cf2b085 100644 --- a/config/packages/monolog.yaml +++ b/config/packages/monolog.yaml @@ -1,14 +1,19 @@ monolog: - channels: [deprecation] + channels: [deprecation, cron] when@dev: monolog: handlers: + cron: + type: stream + path: "%kernel.logs_dir%/cron.log" + level: info + channels: [cron] main: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" level: debug - channels: ["!event"] + channels: ["!event", "!cron"] console: type: console process_psr_3_messages: false @@ -17,11 +22,16 @@ when@dev: when@prod: monolog: handlers: + cron: + type: stream + path: "%kernel.logs_dir%/cron.log" + level: info + channels: [cron] main: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" level: debug - channels: ["!deprecation"] + channels: ["!deprecation", "!cron"] deprecation: type: stream channels: [deprecation] diff --git a/doc/leave-rollover.md b/doc/leave-rollover.md index 50e953e..3b26087 100644 --- a/doc/leave-rollover.md +++ b/doc/leave-rollover.md @@ -168,11 +168,11 @@ employee_id;rule_code;year;opening_days;opening_saturdays;source_date;comment Exemple cron (tous les jours a 02:10): Dev ```cron -10 2 * * * cd /var/www/html && php bin/console app:leave:rollover --no-interaction >> var/log/leave-rollover.log 2>&1 +10 2 * * * cd /var/www/html && php bin/console app:leave:rollover --no-interaction 2>&1 ``` Prod ```cron -10 2 * * * cd /var/www/sirh && php bin/console app:leave:rollover --no-interaction >> var/log/leave-rollover.log 2>&1 +10 2 * * * cd /var/www/sirh && php bin/console app:leave:rollover --no-interaction 2>&1 ``` Explication de la ligne cron: - `10 2 * * *`: planification diff --git a/doc/rtt-rollover.md b/doc/rtt-rollover.md index 5af58db..3c3792f 100644 --- a/doc/rtt-rollover.md +++ b/doc/rtt-rollover.md @@ -133,11 +133,11 @@ Conversion rapide: `1260 minutes = 21h00 = 3.00 jours` (1 jour = 420 min = 7h) Exemple cron (tous les jours a 02:15, juste apres le rollover conges): Dev ```cron -15 2 * * * cd /var/www/html && php bin/console app:rtt:rollover --no-interaction >> var/log/rtt-rollover.log 2>&1 +15 2 * * * cd /var/www/html && php bin/console app:rtt:rollover --no-interaction 2>&1 ``` Prod ```cron -15 2 * * * cd /var/www/sirh && php bin/console app:rtt:rollover --no-interaction >> var/log/rtt-rollover.log 2>&1 +10 2 * * * cd /var/www/sirh && php bin/console app:rtt:rollover --no-interaction 2>&1 ``` Explication de la ligne cron: - `15 2 * * *`: tous les jours a 02:15 diff --git a/frontend/components/hours/HoursDayView.vue b/frontend/components/hours/HoursDayView.vue index a1a9717..bc0e6bf 100644 --- a/frontend/components/hours/HoursDayView.vue +++ b/frontend/components/hours/HoursDayView.vue @@ -1,258 +1,267 @@ diff --git a/src/Command/LeaveRolloverCommand.php b/src/Command/LeaveRolloverCommand.php index 36ec39a..59f5ef7 100644 --- a/src/Command/LeaveRolloverCommand.php +++ b/src/Command/LeaveRolloverCommand.php @@ -13,12 +13,15 @@ use App\Repository\EmployeeRepository; use App\Service\Leave\LeaveBalanceComputationService; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; +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; #[AsCommand( name: 'app:leave:rollover', @@ -31,6 +34,8 @@ final class LeaveRolloverCommand extends Command private readonly EmployeeLeaveBalanceRepository $leaveBalanceRepository, private readonly LeaveBalanceComputationService $leaveBalanceComputationService, private readonly EntityManagerInterface $entityManager, + #[Autowire(service: 'monolog.logger.cron')] + private readonly LoggerInterface $logger, ) { parent::__construct(); } @@ -51,8 +56,12 @@ final class LeaveRolloverCommand extends Command $today = new DateTimeImmutable('today'); $force = (bool) $input->getOption('force'); + $this->logger->info('app:leave:rollover started.', ['date' => $today->format('Y-m-d'), 'force' => $force]); + if (!$force && !$this->isBusinessRolloverDate($today)) { - $io->success('No rollover today: business date is neither 01/01 nor 01/06.'); + $message = 'No rollover today: business date is neither 01/01 nor 01/06.'; + $this->logger->info($message, ['date' => $today->format('Y-m-d')]); + $io->success($message); return Command::SUCCESS; } @@ -67,6 +76,7 @@ final class LeaveRolloverCommand extends Command $ruleCode = $this->resolveRuleCode($employee); if (null === $ruleCode) { + $this->logger->info('Employee skipped: no eligible rule.', ['employeeId' => $employee->getId()]); ++$skipped; continue; @@ -80,13 +90,22 @@ final class LeaveRolloverCommand extends Command $targetYear = $this->resolveTargetYear($ruleCode, $today); $existing = $this->leaveBalanceRepository->findOneByEmployeeRuleAndYear($employee, $ruleCode, $targetYear); if (null !== $existing) { + $this->logger->info('Employee skipped: balance already exists.', ['employeeId' => $employee->getId(), 'year' => $targetYear, 'rule' => $ruleCode->value]); ++$skipped; continue; } - [$carryDays, $carrySaturdays] = $this->resolveCarry($employee, $ruleCode, $targetYear); - $balance = new EmployeeLeaveBalance() + try { + [$carryDays, $carrySaturdays] = $this->resolveCarry($employee, $ruleCode, $targetYear); + } catch (Throwable $e) { + $this->logger->error('Error computing carry for employee.', ['employeeId' => $employee->getId(), 'error' => $e->getMessage()]); + ++$skipped; + + continue; + } + + $balance = new EmployeeLeaveBalance() ->setEmployee($employee) ->setRuleCode($ruleCode) ->setYear($targetYear) @@ -102,16 +121,22 @@ final class LeaveRolloverCommand extends Command ; $this->entityManager->persist($balance); + $this->logger->info('Balance created.', ['employeeId' => $employee->getId(), 'year' => $targetYear, 'rule' => $ruleCode->value, 'carryDays' => $carryDays, 'carrySaturdays' => $carrySaturdays]); ++$created; } - $this->entityManager->flush(); + try { + $this->entityManager->flush(); + } catch (Throwable $e) { + $this->logger->error('Error flushing leave balances.', ['error' => $e->getMessage()]); + $io->error('Leave rollover failed: '.$e->getMessage()); - $io->success(sprintf( - 'Leave rollover done: %d created, %d skipped.', - $created, - $skipped - )); + return Command::FAILURE; + } + + $message = sprintf('Leave rollover done: %d created, %d skipped.', $created, $skipped); + $this->logger->info($message); + $io->success($message); return Command::SUCCESS; } diff --git a/src/Command/RttRolloverCommand.php b/src/Command/RttRolloverCommand.php index 77a6fa9..9efbf17 100644 --- a/src/Command/RttRolloverCommand.php +++ b/src/Command/RttRolloverCommand.php @@ -13,12 +13,15 @@ use App\Repository\EmployeeRttBalanceRepository; use App\Service\Rtt\RttRecoveryComputationService; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; +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; #[AsCommand( name: 'app:rtt:rollover', @@ -31,6 +34,8 @@ final class RttRolloverCommand extends Command private readonly EmployeeRttBalanceRepository $rttBalanceRepository, private readonly RttRecoveryComputationService $rttRecoveryService, private readonly EntityManagerInterface $entityManager, + #[Autowire(service: 'monolog.logger.cron')] + private readonly LoggerInterface $logger, ) { parent::__construct(); } @@ -51,8 +56,12 @@ final class RttRolloverCommand extends Command $today = new DateTimeImmutable('today'); $force = (bool) $input->getOption('force'); + $this->logger->info('app:rtt:rollover started.', ['date' => $today->format('Y-m-d'), 'force' => $force]); + if (!$force && '06-01' !== $today->format('m-d')) { - $io->success('No RTT rollover today: business date is not 01/06.'); + $message = 'No RTT rollover today: business date is not 01/06.'; + $this->logger->info($message, ['date' => $today->format('Y-m-d')]); + $io->success($message); return Command::SUCCESS; } @@ -67,6 +76,7 @@ final class RttRolloverCommand extends Command } if (!$this->isEligible($employee)) { + $this->logger->info('Employee skipped: not eligible.', ['employeeId' => $employee->getId()]); ++$skipped; continue; @@ -74,13 +84,21 @@ final class RttRolloverCommand extends Command $existing = $this->rttBalanceRepository->findOneByEmployeeAndYear($employee, $targetYear); if (null !== $existing) { + $this->logger->info('Employee skipped: balance already exists.', ['employeeId' => $employee->getId(), 'year' => $targetYear]); ++$skipped; continue; } - $previousYear = $targetYear - 1; - $carryMinutes = $this->rttRecoveryService->computeTotalRecoveryForExercise($employee, $previousYear); + try { + $previousYear = $targetYear - 1; + $carryMinutes = $this->rttRecoveryService->computeTotalRecoveryForExercise($employee, $previousYear); + } catch (Throwable $e) { + $this->logger->error('Error computing carry for employee.', ['employeeId' => $employee->getId(), 'error' => $e->getMessage()]); + ++$skipped; + + continue; + } $balance = new EmployeeRttBalance() ->setEmployee($employee) @@ -90,16 +108,22 @@ final class RttRolloverCommand extends Command ; $this->entityManager->persist($balance); + $this->logger->info('Balance created.', ['employeeId' => $employee->getId(), 'year' => $targetYear, 'carryMinutes' => $carryMinutes]); ++$created; } - $this->entityManager->flush(); + try { + $this->entityManager->flush(); + } catch (Throwable $e) { + $this->logger->error('Error flushing RTT balances.', ['error' => $e->getMessage()]); + $io->error('RTT rollover failed: '.$e->getMessage()); - $io->success(sprintf( - 'RTT rollover done: %d created, %d skipped.', - $created, - $skipped - )); + return Command::FAILURE; + } + + $message = sprintf('RTT rollover done: %d created, %d skipped.', $created, $skipped); + $this->logger->info($message); + $io->success($message); return Command::SUCCESS; }