Browse Source

fix merge conflicts

Olivier Massot 1 year ago
parent
commit
cc513da228

+ 0 - 86
config/packages/docker/monolog.yaml

@@ -1,86 +0,0 @@
-# Voir doc/logging.md
-monolog:
-    channels: ['cron']
-    handlers:
-        # sorties standards (stdout, stderr, console)
-        stderr:
-            type: stream
-            path: php://stderr
-            level: error
-            channels: ["!event", "!doctrine"]
-        console:
-            type: console
-            process_psr_3_messages: false
-            level: debug
-            channels: ["!event", "!doctrine", "!console"]
-
-        # email en cas d'erreurs critiques, sauf erreurs 404 / 405
-#        critical:
-#            type: fingers_crossed
-#            action_level: critical
-#            excluded_http_codes: [ 404, 405 ]
-#            handler: deduplicated
-#        deduplicated:
-#            type: deduplication
-#            handler: mailer
-#        mailer:
-#            type: symfony_mailer
-#            from_email: "process@opentalent.fr"
-#            to_email: "exploitation@opentalent.fr"
-#            subject: AP2I - Critical Error Occurred
-#            level: critical
-#            formatter: monolog.formatter.html
-#            content_type: text/html
-
-        # logging fichier
-        file_main:
-            type: rotating_file
-            path: "%kernel.logs_dir%/%env(LOG_FILE_NAME)%.main.log"
-            level: debug
-            max_files: 3
-            channels: [php, doctrine, http_client, elastica]
-        file_auth:
-            type: rotating_file
-            path: "%kernel.logs_dir%/%kernel.environment%.auth.log"
-            level: debug
-            max_files: 3
-            channels: security
-
-        # logs dédiés à l'exécution des cron-jobs
-        cron:
-            type: group
-            members: [cron_file]
-            channels: cron
-        cron_file:
-            type: rotating_file
-            path: "%kernel.logs_dir%/%kernel.environment%.cron.log"
-            level: debug
-            max_files: 7
-            formatter: monolog.formatter.message
-#        cron_critical:
-#            type:           fingers_crossed
-#            action_level:   critical
-#            handler:        cron_deduplicated
-#        cron_deduplicated:
-#            type: deduplication
-#            # the time in seconds during which duplicate entries are discarded (default: 60)
-#            time: 10
-#            handler: cron_mailer
-#        cron_mailer:
-#            type:           symfony_mailer
-#            from_email:     "process@opentalent.fr"
-#            to_email:       "exploitation@opentalent.fr"
-#            subject:        "Cron - Critical Error"
-#            level:          error
-#            formatter:      monolog.formatter.html
-#            content_type:   text/html
-
-
-        # uncomment to get logging in your browser
-        # you may have to allow bigger header sizes in your Web server configuration
-        #firephp:
-        #    type: firephp
-        #    level: info
-        #chromephp:
-        #    type: chromephp
-        #    level: info

+ 103 - 0
config/packages/monolog.yaml

@@ -1,3 +1,106 @@
 monolog:
     channels:
         - deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
+        - cron
+
+    handlers:
+        # sorties standards (stdout, stderr, console)
+        stderr:
+            type: stream
+            path: php://stderr
+            level: error
+            channels: [ "!event", "!doctrine", "!cron" ]
+        console:
+            type: console
+            process_psr_3_messages: false
+            level: debug
+            channels: [ "!event", "!doctrine", "!console" ]
+
+        # logging fichier
+        file_main:
+            type: rotating_file
+            path: "%kernel.logs_dir%/%env(LOG_FILE_NAME)%.main.log"
+            level: debug
+            max_files: 3
+            channels: [php, doctrine, http_client, elastica]
+        file_auth:
+            type: rotating_file
+            path: "%kernel.logs_dir%/%kernel.environment%.auth.log"
+            level: debug
+            max_files: 3
+            channels: security
+
+        # email en cas d'erreurs critiques, sauf erreurs 404 / 405
+        #        critical:
+        #            type: fingers_crossed
+        #            action_level: critical
+        #            excluded_http_codes: [ 404, 405 ]
+        #            handler: deduplicated
+        #        deduplicated:
+        #            type: deduplication
+        #            handler: mailer
+        #        mailer:
+        #            type: symfony_mailer
+        #            from_email: "process@opentalent.fr"
+        #            to_email: "exploitation@opentalent.fr"
+        #            subject: AP2I - Critical Error Occurred
+        #            level: critical
+        #            formatter: monolog.formatter.html
+        #            content_type: text/html
+
+        ### --- Cron-Jobs ---
+        # Log fichier (niveau debug)
+        cron_file:
+            type: rotating_file
+            path: "%kernel.logs_dir%/%kernel.environment%.cron.log"
+            level: debug
+            max_files: 7
+            formatter: monolog.formatter.message
+            channels: [cron]
+
+        # Rapport par mail
+        cron_info:
+            type:           fingers_crossed
+            action_level:   info
+            handler:        cron_info_deduplicated
+            channels: ['cron']
+        cron_info_deduplicated:
+            type: deduplication
+            # the time in seconds during which duplicate entries are discarded (default: 60)
+            time: 10
+            handler: cron_info_mailer
+        cron_info_mailer:
+            type:           symfony_mailer
+            from_email:     "mail.report@opentalent.fr"
+            to_email:       "exploitation@opentalent.fr"
+            subject:        "Cron - Execution Report"
+            level:          info
+            content_type:   text/html
+
+        # Log par mail en cas d'erreur critique
+        cron_critical:
+            type:           fingers_crossed
+            action_level:   critical
+            handler:        cron_critical_deduplicated
+        cron_critical_deduplicated:
+            type: deduplication
+            # the time in seconds during which duplicate entries are discarded (default: 60)
+            time: 10
+            handler: cron_critical_mailer
+        cron_critical_mailer:
+            type:           symfony_mailer
+            from_email:     "mail.report@opentalent.fr"
+            to_email:       "exploitation@opentalent.fr"
+            subject:        "Cron - Critical Error"
+            level:          critical
+            formatter:      monolog.formatter.html
+            content_type:   text/html
+
+        # uncomment to get logging in your browser
+        # you may have to allow bigger header sizes in your Web server configuration
+        #firephp:
+        #    type: firephp
+        #    level: info
+        #chromephp:
+        #    type: chromephp
+        #    level: info

+ 0 - 86
config/packages/prod/monolog.yaml

@@ -1,86 +0,0 @@
-# Voir doc/logging.md
-monolog:
-    channels: ['cron']
-    handlers:
-        # sorties standards (stdout, stderr, console)
-        stderr:
-            type: stream
-            path: php://stderr
-            level: error
-            channels: ["!event", "!doctrine"]
-        console:
-            type: console
-            process_psr_3_messages: false
-            level: debug
-            channels: ["!event", "!doctrine", "!console"]
-
-        # email en cas d'erreurs critiques, sauf erreurs 404 / 405
-        #        critical:
-        #            type: fingers_crossed
-        #            action_level: critical
-        #            excluded_http_codes: [ 404, 405 ]
-        #            handler: deduplicated
-        #        deduplicated:
-        #            type: deduplication
-        #            handler: mailer
-        #        mailer:
-        #            type: symfony_mailer
-        #            from_email: "process@opentalent.fr"
-        #            to_email: "exploitation@opentalent.fr"
-        #            subject: AP2I - Critical Error Occurred
-        #            level: critical
-        #            formatter: monolog.formatter.html
-        #            content_type: text/html
-
-        # logging fichier
-        file_main:
-            type: rotating_file
-            path: "%kernel.logs_dir%/%env(LOG_FILE_NAME)%.main.log"
-            level: debug
-            max_files: 3
-            channels: [php, doctrine, http_client, elastica]
-        file_auth:
-            type: rotating_file
-            path: "%kernel.logs_dir%/%kernel.environment%.auth.log"
-            level: debug
-            max_files: 3
-            channels: security
-
-        # logs dédiés à l'exécution des cron-jobs
-        cron:
-            type: group
-            members: [cron_file]
-            channels: cron
-        cron_file:
-            type: rotating_file
-            path: "%kernel.logs_dir%/%kernel.environment%.cron.log"
-            level: debug
-            max_files: 7
-            formatter: monolog.formatter.message
-#        cron_critical:
-#            type:           fingers_crossed
-#            action_level:   critical
-#            handler:        cron_deduplicated
-#        cron_deduplicated:
-#            type: deduplication
-#            # the time in seconds during which duplicate entries are discarded (default: 60)
-#            time: 10
-#            handler: cron_mailer
-#        cron_mailer:
-#            type:           symfony_mailer
-#            from_email:     "process@opentalent.fr"
-#            to_email:       "exploitation@opentalent.fr"
-#            subject:        "Cron - Critical Error"
-#            level:          error
-#            formatter:      monolog.formatter.html
-#            content_type:   text/html
-
-
-        # uncomment to get logging in your browser
-        # you may have to allow bigger header sizes in your Web server configuration
-        #firephp:
-        #    type: firephp
-        #    level: info
-        #chromephp:
-        #    type: chromephp
-        #    level: info

+ 0 - 2
config/services.yaml

@@ -87,8 +87,6 @@ services:
         - !tagged_iterator app.encoder
     App\Service\ServiceIterator\Mailer\BuilderIterator:
         - !tagged_iterator app.mailer.builder
-    App\Service\ServiceIterator\CronjobIterator:
-        - !tagged_iterator app.cronjob
     App\Service\ServiceIterator\StorageIterator:
         - !tagged_iterator app.storage
 

+ 37 - 0
doc/cron.md

@@ -0,0 +1,37 @@
+# Crons
+
+## La commande `ot:cron`
+
+Les taches planifiées (crons) sont exécutées au moyen de la commande suivante, où jobs est le nom du job 
+à effectuer (ou une liste de noms de séparés par des virgules): 
+
+    bin/console ot:cron run <jobs>
+
+Pour lister les jobs disponibles : 
+
+    bin/console ot:cron list
+
+Pour plus d'informations : 
+
+    bin/console ot:cron --help
+
+> À noter : tous les jobs implémentent une méthode preview qui peut être exécutée en passant l'option -p, --preview 
+> à la commande.
+
+## Créer un nouveau job
+
+Pour ajouter une nouvelle tâche exécutable, créer simplement une nouvelle classe dans le répertoire src/Service/Cron/Job. 
+Cette classe doit hériter de \App\Service\Cron\BaseCronJob.
+
+Le nom du job sera déduit du nom de ce nouvel objet (`MyCron` deviendra `my-cron`)
+
+Cette classe devra implémenter les méthodes `preview` et `execute` telles que définies dans 
+l'interface \App\Service\Cron\CronjobInterface.
+
+La commande `ot:cron` s'occupera pour vous de :
+
+* locker le process pour interdire l'exécution simultanée de deux jobs du même nom
+* mesurer les temps d'exécution
+* assurer la gestion d'erreur du job
+* le logging et l'envoi d'un mail en cas d'erreur critique
+* le retour d'une valeur de succès ou d'erreur selon le résultat du job

+ 56 - 21
src/Commands/CronCommand.php

@@ -5,6 +5,8 @@ namespace App\Commands;
 use App\Service\Cron\CronjobInterface;
 use App\Service\Cron\UI\ConsoleUI;
 use App\Service\ServiceIterator\CronjobIterator;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Handler\RotatingFileHandler;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\Console\Attribute\AsCommand;
 use Symfony\Component\Console\Command\Command;
@@ -15,6 +17,7 @@ use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Contracts\Service\Attribute\Required;
+use Throwable;
 
 /**
  * CLI Command to run the cron-jobs.
@@ -25,7 +28,7 @@ use Symfony\Contracts\Service\Attribute\Required;
  *     bin/console ot:cron run clean-db --preview
  *     bin/console ot:cron run clean-db
  *
- * @see ~/src/Service/Cron/Readme.md
+ * @see doc/cron.md
  */
 #[AsCommand(
     name: 'ot:cron',
@@ -49,13 +52,11 @@ class CronCommand extends Command
     private LoggerInterface $logger;
     private CronjobIterator $cronjobIterator;
 
+    /** @noinspection PhpUnused */
     #[Required]
     /** @see https://symfony.com/doc/current/logging/channels_handlers.html#how-to-autowire-logger-channels */
-    public function setLoggerInterface(LoggerInterface $cronLogger): void
-    {
-        $this->logger = $cronLogger;
-    }
-
+    public function setLoggerInterface(LoggerInterface $cronLogger): void { $this->logger = $cronLogger; }
+    /** @noinspection PhpUnused */
     #[Required]
     public function setCronjobIterator(CronjobIterator $cronjobIterator): void
     {
@@ -100,6 +101,8 @@ class CronCommand extends Command
     {
         $this->output = $output;
 
+        $this->configureLoggerFormatter();
+
         /** @var FormatterHelper $formatter */
         $formatter = $this->getHelper('formatter');
 
@@ -128,7 +131,7 @@ class CronCommand extends Command
             foreach (explode(',', $jobNames) as $name) {
                 try {
                     $jobs[] = $this->cronjobIterator->getByName($name);
-                } catch (\RuntimeException $e) {
+                } catch (RuntimeException $e) {
                     $this->output->writeln($e->getMessage());
                     $this->listJobs();
 
@@ -137,15 +140,13 @@ class CronCommand extends Command
             }
         }
 
-        $this->logger->info(
-            'CronCommand will '.
-            ($preview ? 'preview' : 'execute').' '.
-            implode(', ', array_map(static function ($job) { return $job->name(); }, $jobs))
-        );
-
         $results = [];
 
         foreach ($jobs as $job) {
+            $this->logger->info(
+                'CronCommand will execute `' . $job->name() . '`' . ($preview ? ' [PREVIEW MODE]' : '')
+            );
+
             $results[] = $this->runJob($job, $preview);
         }
 
@@ -197,25 +198,59 @@ class CronCommand extends Command
         $ui = new ConsoleUI($this->output);
         $job->setUI($ui);
 
+        $this->configureLoggerFormatter($job->name());
+
         try {
             if ($preview) {
                 $job->preview();
             } else {
                 $job->execute();
             }
-        } catch (\RuntimeException $e) {
-            $this->logger->critical($e);
-            $this->output->write('An error happened while running the process : '.$e);
 
+            $t1 = microtime(true);
+
+            $msg = "Job has been successfully executed (" . round($t1 - $t0, 2) . " sec.)" . ($preview ? ' [PREVIEW MODE]' : '');
+            $this->output->writeln($formatter->formatSection($job->name(), $msg));
+            $this->logger->info($job->name() . ' - ' . $msg);
+
+        } catch (Throwable $e) {
+            $this->logger->critical($e);
+            $this->output->write("An error happened while running the process : " . $e);
             return Command::FAILURE;
+
+        } finally {
+            $this->resetLoggerFormatter();
         }
 
-        $t1 = microtime(true);
+        return Command::SUCCESS;
+    }
 
-        $msg = 'Job has been successfully executed ('.round($t1 - $t0, 2).' sec.)'.($preview ? ' [PREVIEW MODE]' : '');
-        $this->output->writeln($formatter->formatSection($job->name(), $msg));
-        $this->logger->info($job->name().' - '.$msg);
+    /**
+     * Modify the RotatingFile logger line format to match the display the current job's name (if any)
+     *
+     * @param string|null $jobName
+     * @return void
+     */
+    protected function configureLoggerFormatter(string | null $jobName = null): void {
+        /** @noinspection PhpPossiblePolymorphicInvocationInspection @phpstan-ignore-next-line */
+        foreach ($this->logger->getHandlers() as $handler) {
+            if ($handler instanceof RotatingFileHandler) {
 
-        return Command::SUCCESS;
+                $format = "[%datetime%] " .
+                          ($jobName !== null ? "[" . $jobName . "] " : "") .
+                          "%channel%.%level_name%: %message% %context% %extra%\n";
+
+                $handler->setFormatter(new LineFormatter($format, 'Y-m-d H:i:s.v'));
+            }
+        }
+    }
+
+    /**
+     * Alias for `$this->configureLoggerFormatter(null)`
+     * @return void
+     */
+    protected function resetLoggerFormatter(): void
+    {
+        $this->configureLoggerFormatter();
     }
 }

+ 0 - 95
src/Commands/DolibarrSyncCommand.php

@@ -1,95 +0,0 @@
-<?php
-
-namespace App\Commands;
-
-use App\Service\Dolibarr\DolibarrSyncService;
-use Symfony\Component\Console\Attribute\AsCommand;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Command\LockableTrait;
-use Symfony\Component\Console\Helper\ProgressBar;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Output\OutputInterface;
-
-#[AsCommand(
-    name: 'ot:dolibarr-sync',
-    description: 'Push the latest data from the Opentalent DB to dolibarr'
-)]
-class DolibarrSyncCommand extends Command
-{
-    use LockableTrait;
-
-    /**
-     * How many operations are shown each time the preview choice is made.
-     */
-    public const PREVIEW_CHUNK = 20;
-
-    public function __construct(
-        private DolibarrSyncService $dolibarrSyncService
-    ) {
-        parent::__construct();
-    }
-
-    protected function configure(): void
-    {
-        $this->addOption(
-            'preview',
-            'p',
-            InputOption::VALUE_NONE,
-            'Only preview the sync operations instead of executing it'
-        );
-    }
-
-    protected function execute(InputInterface $input, OutputInterface $output): int
-    {
-        if (!$this->lock()) {
-            $output->writeln('The command is already running in another process.');
-
-            return Command::SUCCESS;
-        }
-
-        $output->writeln('Start the synchronization');
-        $t0 = microtime(true);
-        $output->writeln('Scanning...');
-
-        $progressBar = new ProgressBar($output, 0);
-        $progressCallback = function ($i, $total) use ($progressBar) {
-            if (!$progressBar->getMaxSteps() !== $total) {
-                $progressBar->setMaxSteps($total);
-            }
-            $progressBar->setProgress($i);
-        };
-
-        $operations = $this->dolibarrSyncService->scan($progressCallback);
-
-        $t1 = microtime(true);
-        $output->writeln('Scan lasted '.($t1 - $t0).' sec.');
-
-        $output->writeln(count($operations).' operations to be executed');
-
-        if ($input->getOption('preview')) {
-            $output->writeln('-- Preview --');
-            foreach ($operations as $i => $iValue) {
-                $output->writeln($i.'. '.$iValue->getLabel());
-                foreach ($iValue->getChangeLog() as $message) {
-                    $output->writeln('   '.$message);
-                }
-            }
-        } else {
-            $t0 = microtime(true);
-            $output->writeln('Executing...');
-
-            $operations = $this->dolibarrSyncService->execute($operations, $progressCallback);
-
-            $successes = count(array_filter($operations, function ($o) { return $o->getStatus() === $o::STATUS_DONE; }));
-            $errors = count(array_filter($operations, function ($o) { return $o->getStatus() === $o::STATUS_ERROR; }));
-            $output->writeln($successes.' operations successfully executed');
-            $output->writeln($errors.' errors');
-
-            $t1 = microtime(true);
-            $output->writeln('Execution lasted '.($t1 - $t0).' sec.');
-        }
-
-        return Command::SUCCESS;
-    }
-}

+ 1 - 0
src/Enum/Access/FunctionEnum.php

@@ -34,6 +34,7 @@ enum FunctionEnum: string
     case COORDINATOR = 'COORDINATOR';
     case TECHNICAL_STAFF = 'TECHNICAL_STAFF';
     case ACCOUNTANT = 'ACCOUNTANT';
+    case COM_STAFF = 'COM_STAFF';
     case ACTIVE_MEMBER_OF_THE_CA = 'ACTIVE_MEMBER_OF_THE_CA';
     case HONORARY_PRESIDENT = 'HONORARY_PRESIDENT';
     case PRESIDENT = 'PRESIDENT';

+ 5 - 3
src/Service/Cron/BaseCronJob.php

@@ -14,8 +14,10 @@ use Symfony\Contracts\Service\Attribute\Required;
  *
  * This class shouldn't implement directly the CronjobInterface because it shall not be injected itself into the
  * CronjobIterator, but all its subclasses should.
+ *
+ * @see doc/cron.md
  */
-abstract class BaseCronJob
+abstract class BaseCronJob implements CronjobInterface
 {
     protected CronUIInterface $ui;
     protected LoggerInterface $logger;
@@ -41,8 +43,8 @@ abstract class BaseCronJob
         );
     }
 
-    public function setUI(CronUIInterface $ui): void
+    public function setUI(CronUIInterface $io): void
     {
-        $this->ui = $ui;
+        $this->ui = $io;
     }
 }

+ 1 - 1
src/Service/Cron/CronjobInterface.php

@@ -8,7 +8,7 @@ use Psr\Log\LoggerInterface;
 /**
  * A cron-job.
  *
- * @see ~/src/Service/Cron/Readme.md
+ * @see doc/cron.md
  */
 interface CronjobInterface
 {

+ 1 - 1
src/Service/Cron/Job/CleanDb.php

@@ -15,7 +15,7 @@ use JetBrains\PhpStorm\Pure;
  * >>> ot:cron run clean-db --preview
  * >>> ot:cron run clean-db
  */
-class CleanDb extends BaseCronJob implements CronjobInterface
+class CleanDb extends BaseCronJob
 {
     /**
      * Delay before deleting the record from the DB.

+ 1 - 1
src/Service/Cron/Job/CleanTempFiles.php

@@ -21,7 +21,7 @@ use JetBrains\PhpStorm\Pure;
  * >>> ot:cron run clean-temp-files --preview
  * >>> ot:cron run clean-temp-files
  */
-class CleanTempFiles extends BaseCronJob implements CronjobInterface
+class CleanTempFiles extends BaseCronJob
 {
     /**
      * Delay before removing a temporary file (in days).

+ 2 - 7
src/Service/Cron/Job/DolibarrSync.php

@@ -13,16 +13,11 @@ use JetBrains\PhpStorm\Pure;
  * >>> ot:cron run dolibarr-sync --preview
  * >>> ot:cron run dolibarr-sync
  */
-class DolibarrSync extends BaseCronJob implements CronjobInterface
+class DolibarrSync extends BaseCronJob
 {
-    /**
-     * How many operations are shown each time the preview choice is made.
-     */
-    public const PREVIEW_CHUNK = 20;
-
     #[Pure]
     public function __construct(
-        private DolibarrSyncService $dolibarrSyncService
+        private readonly DolibarrSyncService $dolibarrSyncService
     ) {
         parent::__construct();
     }

+ 0 - 11
src/Service/Cron/Readme.md

@@ -1,11 +0,0 @@
-## Cronjobs
-
-This namespace group the cronjobs that can be executed with 
-
-    ot:cron [options] <action> [<jobs>]
-
-Each of the cronjobs are in `App\Service\Cron\Job` and shall implement the CronjobInterface.
-
-The job name is the class name, formatted in SnakeCase with hyphen `-`
-
-Ex: `MySuperJob` job's name will be `my-super-job`

+ 3 - 2
src/Service/Dolibarr/DolibarrSyncService.php

@@ -690,8 +690,9 @@ class DolibarrSyncService
     /**
      * Returns the number of accesses possessing at least one of the missions.
      *
-     * @param array<mixed> $missions A list of missions
-     * @param array<mixed> $members  An organization members as returned by getActiveMembersIndex: [$accessID => [$missions...]]
+     * @param array<string> $missions A list of missions
+     * @param array<string, array<string>> $members An organization members as returned by getActiveMembersIndex: [$accessID => [$missions...]]
+     * @return int
      */
     protected function countWithMission(array $missions, array $members): int
     {

+ 2 - 0
src/Service/ServiceIterator/CronjobIterator.php

@@ -3,6 +3,7 @@
 namespace App\Service\ServiceIterator;
 
 use App\Service\Cron\CronjobInterface;
+use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
 
 /**
  * Permet d'itérer sur les cronjobs.
@@ -15,6 +16,7 @@ class CronjobIterator
      * @param iterable<CronjobInterface> $cronjobServices
      */
     public function __construct(
+        #[TaggedIterator('app.cronjob')]
         readonly private iterable $cronjobServices,
     ) {
     }

+ 5 - 11
tests/Unit/Service/Cron/BaseCronJobTest.php

@@ -9,17 +9,11 @@ use App\Service\Cron\UI\SilentUI;
 use PHPUnit\Framework\TestCase;
 use Psr\Log\LoggerInterface;
 
-class TestableBaseCronJob extends BaseCronJob
-{
-    public function getUI(): CronUIInterface
-    {
-        return $this->ui;
-    }
-
-    public function getLogger(): LoggerInterface
-    {
-        return $this->logger;
-    }
+class TestableBaseCronJob extends BaseCronJob {
+    public function getUI(): CronUIInterface { return $this->ui; }
+    public function getLogger(): LoggerInterface { return $this->logger; }
+    public function preview(): void {}
+    public function execute(): void {}
 }
 
 class BaseCronJobTest extends TestCase

+ 8 - 8
tests/Unit/Service/Dolibarr/DolibarrApiServiceTest.php

@@ -45,8 +45,7 @@ class DolibarrApiServiceTest extends TestCase
     /**
      * @see DolibarrApiService::getSociety()
      */
-    public function testGetSocietyMissing(): void
-    {
+    public function testGetSocietyNotExisting(): void {
         $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
             ->setConstructorArgs([$this->client])
             ->setMethodsExcept(['getSociety'])
@@ -57,7 +56,7 @@ class DolibarrApiServiceTest extends TestCase
         $dolibarrApiService
             ->expects(self::once())
             ->method('getJsonContent')
-            ->with('thirdparties', ['limit' => '1', 'sqlfilters' => '(ef.2iopen_organization_id:=:'.$organizationId.')'])
+            ->with("thirdparties", [ "limit" => "1", "sqlfilters" => "ref_int=" . $organizationId])
             ->willThrowException(new HttpException(404));
 
         $society = $dolibarrApiService->getSociety($organizationId);
@@ -68,8 +67,7 @@ class DolibarrApiServiceTest extends TestCase
     /**
      * @see DolibarrApiService::getSociety()
      */
-    public function testGetSocietyError(): void
-    {
+    public function testGetSocietyWithError(): void {
         $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
             ->setConstructorArgs([$this->client])
             ->setMethodsExcept(['getSociety'])
@@ -77,13 +75,15 @@ class DolibarrApiServiceTest extends TestCase
 
         $organizationId = 123;
 
+        $e = new HttpException(500);
+
         $dolibarrApiService
             ->expects(self::once())
             ->method('getJsonContent')
-            ->with('thirdparties', ['limit' => '1', 'sqlfilters' => '(ef.2iopen_organization_id:=:'.$organizationId.')'])
-            ->willThrowException(new HttpException(500));
+            ->with("thirdparties", [ "limit" => "1", "sqlfilters" => "ref_int=" . $organizationId])
+            ->willThrowException($e);
 
-        $this->expectException(HttpException::class);
+        $this->expectException($e::class);
 
         $dolibarrApiService->getSociety($organizationId);
     }

+ 1 - 1
tests/Unit/Service/Dolibarr/DolibarrSyncServiceTest.php

@@ -803,7 +803,7 @@ class DolibarrSyncServiceTest extends TestCase
 
         $this->assertEqualsCanonicalizing([
             1 => [1 => [FunctionEnum::PRESIDENT->value], 2 => [FunctionEnum::STUDENT->value]],
-            2 => [3 => [FunctionEnum::PRESIDENT->value, FunctionEnum::TEACHER->value]],
+            2 => [3 => [FunctionEnum::PRESIDENT->value, FunctionEnum::TEACHER->value]]
         ], $index);
     }