feat : ajout de log pour les cron
This commit is contained in:
@@ -1,14 +1,19 @@
|
|||||||
monolog:
|
monolog:
|
||||||
channels: [deprecation]
|
channels: [deprecation, cron]
|
||||||
|
|
||||||
when@dev:
|
when@dev:
|
||||||
monolog:
|
monolog:
|
||||||
handlers:
|
handlers:
|
||||||
|
cron:
|
||||||
|
type: stream
|
||||||
|
path: "%kernel.logs_dir%/cron.log"
|
||||||
|
level: info
|
||||||
|
channels: [cron]
|
||||||
main:
|
main:
|
||||||
type: stream
|
type: stream
|
||||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||||
level: debug
|
level: debug
|
||||||
channels: ["!event"]
|
channels: ["!event", "!cron"]
|
||||||
console:
|
console:
|
||||||
type: console
|
type: console
|
||||||
process_psr_3_messages: false
|
process_psr_3_messages: false
|
||||||
@@ -17,11 +22,16 @@ when@dev:
|
|||||||
when@prod:
|
when@prod:
|
||||||
monolog:
|
monolog:
|
||||||
handlers:
|
handlers:
|
||||||
|
cron:
|
||||||
|
type: stream
|
||||||
|
path: "%kernel.logs_dir%/cron.log"
|
||||||
|
level: info
|
||||||
|
channels: [cron]
|
||||||
main:
|
main:
|
||||||
type: stream
|
type: stream
|
||||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||||
level: debug
|
level: debug
|
||||||
channels: ["!deprecation"]
|
channels: ["!deprecation", "!cron"]
|
||||||
deprecation:
|
deprecation:
|
||||||
type: stream
|
type: stream
|
||||||
channels: [deprecation]
|
channels: [deprecation]
|
||||||
|
|||||||
@@ -168,11 +168,11 @@ employee_id;rule_code;year;opening_days;opening_saturdays;source_date;comment
|
|||||||
Exemple cron (tous les jours a 02:10):
|
Exemple cron (tous les jours a 02:10):
|
||||||
Dev
|
Dev
|
||||||
```cron
|
```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
|
Prod
|
||||||
```cron
|
```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:
|
Explication de la ligne cron:
|
||||||
- `10 2 * * *`: planification
|
- `10 2 * * *`: planification
|
||||||
|
|||||||
@@ -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):
|
Exemple cron (tous les jours a 02:15, juste apres le rollover conges):
|
||||||
Dev
|
Dev
|
||||||
```cron
|
```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
|
Prod
|
||||||
```cron
|
```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:
|
Explication de la ligne cron:
|
||||||
- `15 2 * * *`: tous les jours a 02:15
|
- `15 2 * * *`: tous les jours a 02:15
|
||||||
|
|||||||
@@ -143,13 +143,22 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="pl-2 text-sm font-semibold text-neutral-700">
|
<div class="pl-2 text-sm font-semibold text-neutral-700">
|
||||||
<div v-if="isTimeTracking(employee)">{{ formatMinutes(getRowMetrics(employee.id).dayMinutes) }}</div>
|
<div v-if="isTimeTracking(employee)">{{
|
||||||
|
formatMinutes(getRowMetrics(employee.id).dayMinutes)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm font-semibold text-neutral-700">
|
<div class="text-sm font-semibold text-neutral-700">
|
||||||
<div v-if="isTimeTracking(employee)">{{ formatMinutes(getRowMetrics(employee.id).nightMinutes) }}</div>
|
<div v-if="isTimeTracking(employee)">{{
|
||||||
|
formatMinutes(getRowMetrics(employee.id).nightMinutes)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm font-semibold text-neutral-700">
|
<div class="text-sm font-semibold text-neutral-700">
|
||||||
<div v-if="isTimeTracking(employee)">{{ formatMinutes(getRowMetrics(employee.id).totalMinutes) }}</div>
|
<div v-if="isTimeTracking(employee)">{{
|
||||||
|
formatMinutes(getRowMetrics(employee.id).totalMinutes)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
<div v-else>{{ getPresenceDayValue(employee.id) }}</div>
|
<div v-else>{{ getPresenceDayValue(employee.id) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isAdmin" class="text-right">
|
<div v-if="isAdmin" class="text-right">
|
||||||
@@ -182,11 +191,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Employee } from '~/services/dto/employee'
|
import type {Employee} from '~/services/dto/employee'
|
||||||
import TimeSelect from '~/components/ui/TimeSelect.vue'
|
import TimeSelect from '~/components/ui/TimeSelect.vue'
|
||||||
import type { HourRow } from './types'
|
import type {HourRow} from './types'
|
||||||
|
|
||||||
const rows = defineModel<Record<number, HourRow>>('rows', { required: true })
|
const rows = defineModel<Record<number, HourRow>>('rows', {required: true})
|
||||||
const bulkValidationInput = ref<HTMLInputElement | null>(null)
|
const bulkValidationInput = ref<HTMLInputElement | null>(null)
|
||||||
const bulkSiteValidationInput = ref<HTMLInputElement | null>(null)
|
const bulkSiteValidationInput = ref<HTMLInputElement | null>(null)
|
||||||
|
|
||||||
@@ -244,7 +253,7 @@ watch(
|
|||||||
if (!bulkValidationInput.value) return
|
if (!bulkValidationInput.value) return
|
||||||
bulkValidationInput.value.indeterminate = isIndeterminate
|
bulkValidationInput.value.indeterminate = isIndeterminate
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{immediate: true}
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -253,6 +262,6 @@ watch(
|
|||||||
if (!bulkSiteValidationInput.value) return
|
if (!bulkSiteValidationInput.value) return
|
||||||
bulkSiteValidationInput.value.indeterminate = isIndeterminate
|
bulkSiteValidationInput.value.indeterminate = isIndeterminate
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{immediate: true}
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -13,12 +13,15 @@ use App\Repository\EmployeeRepository;
|
|||||||
use App\Service\Leave\LeaveBalanceComputationService;
|
use App\Service\Leave\LeaveBalanceComputationService;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
#[AsCommand(
|
#[AsCommand(
|
||||||
name: 'app:leave:rollover',
|
name: 'app:leave:rollover',
|
||||||
@@ -31,6 +34,8 @@ final class LeaveRolloverCommand extends Command
|
|||||||
private readonly EmployeeLeaveBalanceRepository $leaveBalanceRepository,
|
private readonly EmployeeLeaveBalanceRepository $leaveBalanceRepository,
|
||||||
private readonly LeaveBalanceComputationService $leaveBalanceComputationService,
|
private readonly LeaveBalanceComputationService $leaveBalanceComputationService,
|
||||||
private readonly EntityManagerInterface $entityManager,
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
#[Autowire(service: 'monolog.logger.cron')]
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
@@ -51,8 +56,12 @@ final class LeaveRolloverCommand extends Command
|
|||||||
$today = new DateTimeImmutable('today');
|
$today = new DateTimeImmutable('today');
|
||||||
$force = (bool) $input->getOption('force');
|
$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)) {
|
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;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -67,6 +76,7 @@ final class LeaveRolloverCommand extends Command
|
|||||||
|
|
||||||
$ruleCode = $this->resolveRuleCode($employee);
|
$ruleCode = $this->resolveRuleCode($employee);
|
||||||
if (null === $ruleCode) {
|
if (null === $ruleCode) {
|
||||||
|
$this->logger->info('Employee skipped: no eligible rule.', ['employeeId' => $employee->getId()]);
|
||||||
++$skipped;
|
++$skipped;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -80,12 +90,21 @@ final class LeaveRolloverCommand extends Command
|
|||||||
$targetYear = $this->resolveTargetYear($ruleCode, $today);
|
$targetYear = $this->resolveTargetYear($ruleCode, $today);
|
||||||
$existing = $this->leaveBalanceRepository->findOneByEmployeeRuleAndYear($employee, $ruleCode, $targetYear);
|
$existing = $this->leaveBalanceRepository->findOneByEmployeeRuleAndYear($employee, $ruleCode, $targetYear);
|
||||||
if (null !== $existing) {
|
if (null !== $existing) {
|
||||||
|
$this->logger->info('Employee skipped: balance already exists.', ['employeeId' => $employee->getId(), 'year' => $targetYear, 'rule' => $ruleCode->value]);
|
||||||
++$skipped;
|
++$skipped;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
[$carryDays, $carrySaturdays] = $this->resolveCarry($employee, $ruleCode, $targetYear);
|
[$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()
|
$balance = new EmployeeLeaveBalance()
|
||||||
->setEmployee($employee)
|
->setEmployee($employee)
|
||||||
->setRuleCode($ruleCode)
|
->setRuleCode($ruleCode)
|
||||||
@@ -102,16 +121,22 @@ final class LeaveRolloverCommand extends Command
|
|||||||
;
|
;
|
||||||
|
|
||||||
$this->entityManager->persist($balance);
|
$this->entityManager->persist($balance);
|
||||||
|
$this->logger->info('Balance created.', ['employeeId' => $employee->getId(), 'year' => $targetYear, 'rule' => $ruleCode->value, 'carryDays' => $carryDays, 'carrySaturdays' => $carrySaturdays]);
|
||||||
++$created;
|
++$created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$this->entityManager->flush();
|
$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(
|
return Command::FAILURE;
|
||||||
'Leave rollover done: %d created, %d skipped.',
|
}
|
||||||
$created,
|
|
||||||
$skipped
|
$message = sprintf('Leave rollover done: %d created, %d skipped.', $created, $skipped);
|
||||||
));
|
$this->logger->info($message);
|
||||||
|
$io->success($message);
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,15 @@ use App\Repository\EmployeeRttBalanceRepository;
|
|||||||
use App\Service\Rtt\RttRecoveryComputationService;
|
use App\Service\Rtt\RttRecoveryComputationService;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
#[AsCommand(
|
#[AsCommand(
|
||||||
name: 'app:rtt:rollover',
|
name: 'app:rtt:rollover',
|
||||||
@@ -31,6 +34,8 @@ final class RttRolloverCommand extends Command
|
|||||||
private readonly EmployeeRttBalanceRepository $rttBalanceRepository,
|
private readonly EmployeeRttBalanceRepository $rttBalanceRepository,
|
||||||
private readonly RttRecoveryComputationService $rttRecoveryService,
|
private readonly RttRecoveryComputationService $rttRecoveryService,
|
||||||
private readonly EntityManagerInterface $entityManager,
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
#[Autowire(service: 'monolog.logger.cron')]
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
@@ -51,8 +56,12 @@ final class RttRolloverCommand extends Command
|
|||||||
$today = new DateTimeImmutable('today');
|
$today = new DateTimeImmutable('today');
|
||||||
$force = (bool) $input->getOption('force');
|
$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')) {
|
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;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -67,6 +76,7 @@ final class RttRolloverCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->isEligible($employee)) {
|
if (!$this->isEligible($employee)) {
|
||||||
|
$this->logger->info('Employee skipped: not eligible.', ['employeeId' => $employee->getId()]);
|
||||||
++$skipped;
|
++$skipped;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -74,13 +84,21 @@ final class RttRolloverCommand extends Command
|
|||||||
|
|
||||||
$existing = $this->rttBalanceRepository->findOneByEmployeeAndYear($employee, $targetYear);
|
$existing = $this->rttBalanceRepository->findOneByEmployeeAndYear($employee, $targetYear);
|
||||||
if (null !== $existing) {
|
if (null !== $existing) {
|
||||||
|
$this->logger->info('Employee skipped: balance already exists.', ['employeeId' => $employee->getId(), 'year' => $targetYear]);
|
||||||
++$skipped;
|
++$skipped;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$previousYear = $targetYear - 1;
|
$previousYear = $targetYear - 1;
|
||||||
$carryMinutes = $this->rttRecoveryService->computeTotalRecoveryForExercise($employee, $previousYear);
|
$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()
|
$balance = new EmployeeRttBalance()
|
||||||
->setEmployee($employee)
|
->setEmployee($employee)
|
||||||
@@ -90,16 +108,22 @@ final class RttRolloverCommand extends Command
|
|||||||
;
|
;
|
||||||
|
|
||||||
$this->entityManager->persist($balance);
|
$this->entityManager->persist($balance);
|
||||||
|
$this->logger->info('Balance created.', ['employeeId' => $employee->getId(), 'year' => $targetYear, 'carryMinutes' => $carryMinutes]);
|
||||||
++$created;
|
++$created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$this->entityManager->flush();
|
$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(
|
return Command::FAILURE;
|
||||||
'RTT rollover done: %d created, %d skipped.',
|
}
|
||||||
$created,
|
|
||||||
$skipped
|
$message = sprintf('RTT rollover done: %d created, %d skipped.', $created, $skipped);
|
||||||
));
|
$this->logger->info($message);
|
||||||
|
$io->success($message);
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user