Commit 3545357e authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Procédure d'envoi de masse pour les déclarants (avec filtrage par liste)

parent be091829
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -55,6 +55,9 @@ abstract class OscarCommandAbstract extends Command
        $outputStyle = new OutputFormatterStyle('cyan', 'default', ['bold']);
        $output->getFormatter()->setStyle('id', $outputStyle);

        $outputStyle = new OutputFormatterStyle('red', 'default', ['bold']);
        $output->getFormatter()->setStyle('red', $outputStyle);

        $outputStyle = new OutputFormatterStyle('blue', 'default', ['underscore']);
        $output->getFormatter()->setStyle('link', $outputStyle);

+0 −128
Original line number Diff line number Diff line
<?php
/**
 * Created by PhpStorm.
 * User: bouvry
 * Date: 04/10/19
 * Time: 11:49
 */

namespace Oscar\Command;


use Moment\Moment;
use Oscar\Entity\Authentification;
use Oscar\Entity\LogActivity;
use Oscar\Entity\Person;
use Oscar\Entity\Role;
use Oscar\Entity\WorkPackage;
use Oscar\Entity\WorkPackagePerson;
use Oscar\Service\ConnectorService;
use Oscar\Service\OscarConfigurationService;
use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
use Oscar\Service\TimesheetService;
use Oscar\Utils\DateTimeUtils;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
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 Zend\Validator\Date;

class OscarTimesheetDeclarerCommand extends OscarCommandAbstract
{
    protected static $defaultName = 'timesheets:declarer';

    const OPT_FORCE = "force";
    const OPT_DECLARER = "declarer";
    const OPT_PERIOD = "period";

    protected function configure()
    {
        $this
            ->setDescription("Système de relance des déclarants")
            ->addOption(self::OPT_FORCE, 'f', InputOption::VALUE_NONE, "Forcer le mode non-interactif")
            ->addOption(
                self::OPT_DECLARER,
                'd',
                InputOption::VALUE_OPTIONAL,
                "Identifiant du déclarant"
            )
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addOutputStyle($output);

        /// OPTIONS and PARAMETERS
        $declarerId = $input->getOption(self::OPT_DECLARER);
        $declarerPeriod = false; //$input->getOption(self::OPT_PERIOD);

        // Récupération du déclarant
        if ($declarerId) {
            if (!$declarerPeriod) {
                $this->declarer($input, $output, $declarerId);
            } else {
                $this->declarer($input, $output, $declarerId, $declarerPeriod);
            }
        } else {
            $this->declarersList($input, $output);
        }
    }

    /**
     * @return TimesheetService
     */
    protected function getTimesheetService()
    {
        return $this->getServicemanager()->get(TimesheetService::class);
    }

    /**
     * @return PersonService
     */
    protected function getPersonService()
    {
        return $this->getServicemanager()->get(PersonService::class);
    }

    public function declarer(InputInterface $input, OutputInterface $output, $declarerId)
    {
        $io = new SymfonyStyle($input, $output);

        try {
            $declarer = $this->getPersonService()->getPerson($declarerId);

            $io->title("Système de relance pour $declarer");
            $periods = $this->getTimesheetService()->getPersonRecallDeclaration($declarer);

            $io->table(["Période", "Durée", "état"], $periods);
        } catch (\Exception $e) {
            $io->error('Impossible de charger le déclarant : ' . $e->getMessage());
            exit(0);
        }
    }

    public function declarersList(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        $io->title("Lite des déclarants");
        try {
            $declarants = $this->getTimesheetService()->getDeclarers();
            $out = [];
            /** @var Person $declarer */
            foreach ($declarants['persons'] as $personId => $datas) {
                $out[] = [$personId, $datas['displayname'], $datas['affectation'], count($datas['declarations'])];
            }
            $headers = ['ID', 'Déclarant', 'Affectation', 'Déclaration(s)'];
            $io->table($headers, $out);

            $io->comment("Entrez la commande '" . self::getName() . " -d <ID>' pour afficher les détails");
        } catch (\Exception $e) {
            $io->error($e->getMessage());
        }
    }
}
 No newline at end of file
+0 −148
Original line number Diff line number Diff line
<?php
/**
 * Created by PhpStorm.
 * User: bouvry
 * Date: 04/10/19
 * Time: 11:49
 */

namespace Oscar\Command;


use Moment\Moment;
use Oscar\Entity\Authentification;
use Oscar\Entity\LogActivity;
use Oscar\Entity\Person;
use Oscar\Entity\Role;
use Oscar\Entity\WorkPackage;
use Oscar\Entity\WorkPackagePerson;
use Oscar\Service\ConnectorService;
use Oscar\Service\OscarConfigurationService;
use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
use Oscar\Service\TimesheetService;
use Oscar\Utils\DateTimeUtils;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
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 Zend\Validator\Date;

class OscarTimesheetDeclarersListCommand extends OscarCommandAbstract
{
    protected static $defaultName = 'timesheets:declarers';
    const ARG_DECLARANT = "declarant";

    protected function configure()
    {
        $this
            ->setDescription("Affiche la liste des déclarants")
            ->addArgument(self::ARG_DECLARANT, InputArgument::OPTIONAL, "Identifiant du déclarant", null)
    //        ->addOption('period', 'p', InputOption::VALUE_OPTIONAL, "Période sous la forme ANNEE-MOIS")
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addOutputStyle($output);

        /** @var OscarUserContext $oscaruserContext */
        $oscaruserContext = $this->getServicemanager()->get(OscarUserContext::class);

        /** @var PersonService $personService */
        $personService = $this->getServicemanager()->get(PersonService::class);

        /** @var TimesheetService $timesheetService */
        $timesheetService = $this->getServicemanager()->get(TimesheetService::class);

        $io = new SymfonyStyle($input, $output);

        // détails
        $declarantId = $input->getArgument(self::ARG_DECLARANT);

        if( $declarantId ){
            try {
                /** @var Person $person */
                $person = $personService->getPerson($declarantId);
            } catch (\Exception $e) {
                $io->error($e->getMessage());
                exit(1);
            }

            $io->title("Déclarant <bold>$person</bold>");
            $headers = ['Projet', 'Lot', 'Début', 'Fin', 'Intitulé'];
            $lines = [];
            $start = null;
            $end = null;

            $io->section("Lots identifiés");

            /** @var WorkPackagePerson $workPackagePerson */
            foreach ($person->getWorkPackages() as $workPackagePerson) {
                $workPackage = $workPackagePerson->getWorkPackage();
                $lines[] = [
                  $workPackage->getActivity()->getAcronym(),
                  $workPackage->getCode(),
                  $workPackage->getActivity()->getDateStart()->format('D j F Y'),
                  $workPackage->getActivity()->getDateEnd()->format('D j F Y'),
                  $workPackage->getLabel(),
                ];

                $s = $workPackage->getActivity()->getDateStart()->getTimestamp();
                $e = $workPackage->getActivity()->getDateEnd()->getTimestamp();

                if($start == null || $start > $s)$start = $s;
                if( $end == null || $end < $e ) $end = $e;
            }
            $io->table($headers, $lines);

            $debut = (new \DateTime())->setTimestamp($start);
            $fin = (new \DateTime())->setTimestamp($end);

            $periodsOpen = DateTimeUtils::allperiodsBetweenTwo($debut, $fin);

            $io->section("Périodes");
            $io->writeln("Du ".$debut->format('c'). " au " . $fin->format('c'));
            $headers = ["Période", "Conflict", "Total", "Nbr Lot", 'Jours'];
            $rows = [];
            foreach ($periodsOpen as $period) {
                $periodDatas = $timesheetService->getTimesheetDatasPersonPeriod($person, $period);
                $rows[] = [
                    $period,
                    $periodDatas['hasConflict']?'Oui':'Non',
                    number_format($periodDatas['total'], 2),
                    count($periodDatas['workpackages']),
                    $periodDatas['dayNbr'],
                ];
            }
            $io->table($headers, $rows);

        }
        else {
            $io->title("Déclarants");


            /** @var OscarConfigurationService $oscarConfig */
            $oscarConfig = $this->getServicemanager()->get(OscarConfigurationService::class);

            /** @var TimesheetService $timesheetService */
            $timesheetService = $this->getServicemanager()->get(TimesheetService::class);

            try {
                $declarants = $timesheetService->getDeclarers();
                $out = [];
                /** @var Person $declarer */
                foreach ($declarants['persons'] as $personId=>$datas) {
                    $out[] = [$personId, $datas['displayname'], $datas['affectation'], count($datas['declarations'])];
                }
                $headers = ['ID', 'Déclarant', 'Affectation', 'Déclaration(s)'];
                $io->table($headers, $out);
            } catch (\Exception $e) {
                $io->error($e->getMessage());
            }
        }
    }
}
 No newline at end of file
+0 −237
Original line number Diff line number Diff line
<?php
/**
 * Created by PhpStorm.
 * User: bouvry
 * Date: 04/10/19
 * Time: 11:49
 */

namespace Oscar\Command;


use Doctrine\ORM\NoResultException;
use Moment\Moment;
use Oscar\Entity\Authentification;
use Oscar\Entity\LogActivity;
use Oscar\Entity\Person;
use Oscar\Entity\Role;
use Oscar\Entity\WorkPackage;
use Oscar\Entity\WorkPackagePerson;
use Oscar\Service\ConnectorService;
use Oscar\Service\MailingService;
use Oscar\Service\OscarConfigurationService;
use Oscar\Service\OscarMailerService;
use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
use Oscar\Service\TimesheetService;
use Oscar\Utils\DateTimeUtils;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
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 UnicaenApp\Service\Mailer\MailerService;
use Zend\Validator\Date;

class
OscarTimesheetDeclarersRecallCommand extends OscarCommandAbstract
{
    protected static $defaultName = 'timesheets:declarers-recall';

    const OPT_FORCE         = "force";
    const OPT_DECLARER      = "declarer";
    const OPT_PERIOD        = "period";
    const OPT_PROCESSDATE        = "processdate";

    const ARG_ALL        = "all";

    protected function configure()
    {
        $this
            ->setDescription("Système de relance des déclarants")
            ->addOption(self::OPT_FORCE, 'f', InputOption::VALUE_NONE, "Forcer le mode non-interactif")
            ->addOption(self::OPT_DECLARER, 'd', InputOption::VALUE_REQUIRED, "Identifiant du déclarant")
            ->addOption(self::OPT_PERIOD, 'p', InputOption::VALUE_OPTIONAL, "Période")
            ->addOption(self::OPT_PROCESSDATE, 'c', InputOption::VALUE_OPTIONAL, "Date de relance (par défaut date actuelle)")
            ->addArgument(self::ARG_ALL, InputArgument::OPTIONAL, "Déclencher pour tous les déclarants", false);
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addOutputStyle($output);

        $io = new SymfonyStyle($input, $output);

        // Argument ALL
        $all = $input->getArgument(self::ARG_ALL);

        /// OPTIONS and PARAMETERS
        $declarerLogin = $input->getOption(self::OPT_DECLARER);
        $processDate = $input->getOption(self::OPT_PROCESSDATE);

        if( $processDate ){
            $processDate = new \DateTime($processDate);
        } else {
            $processDate = new \DateTime();
        }

        $io->writeln("Date effective de la relance : <bold>". $processDate->format('D d M Y') ."</bold>");
        //die();

        if( $all == false && $declarerLogin == null ){
            $io->writeln("Utiliser l'option --declarant=ID");
            $this->declarersList($input, $output);
            return;
        }

        if( $all != 'all' ){
            try {
                $person = $this->getPersonService()->getPersonByLdapLogin($declarerLogin);
                if( !$person ){
                    throw new \Exception("Nop !");
                }
                $personId = $person->getId();

            } catch (NoResultException $e){
                $io->error("Impossible de charger la personne à partir de son identifiant de connexion : $declarerLogin");
                return;
            }
            $declarerId = $personId;
            $all = false;
        }

        $declarerPeriod = $input->getOption(self::OPT_PERIOD);
        if( !$declarerPeriod ){
            $today = date('Y-m-d');
            $time = strtotime($today);
            $final = date("Y-m-d", strtotime("-1 month", $time));
            $declarerPeriod = DateTimeUtils::getPeriodStrFromDateStr($final);
        }

        $io->writeln("Pour la période : <bold>". $declarerPeriod ."</bold>.");


        $do = false;

        if( $all == true ){
            $declarants = $this->getTimesheetService()->getDeclarers();
            $io->writeln(sprintf("Nombre de déclarants pour cette période : <bold>%s</bold>", count($declarants['persons'])));
            $out = [];

            /** @var Person $declarer */
            foreach ($declarants['persons'] as $personId=>$datas) {
                $io->text("Traitement pour " . $personId);
                try {
                    $result = $this->recallDeclarer($personId, $declarerPeriod, $io, $processDate);
                } catch (\Exception $e) {
                    $io->warning($e->getMessage());
                }
            }
        } else {
            try {
                $result = $this->recallDeclarer($personId, $declarerPeriod, $io, $processDate);
            } catch (\Exception $e) {
                $io->warning($e->getMessage());
            }
        }
        $io->comment("Opération terminée");
        return;
    }

    protected function recallDeclarer($declarerId, $declarerPeriod, SymfonyStyle $io, $processDate = null)
    {
        /** @var Person $declarer */
        $declarer = $this->getPersonService()->getPersonById($declarerId);

        $result = $this->declarerPeriod($declarerId, $declarerPeriod, $processDate);

        if( $result ) {
            $io->title($result['person']);
            $io->writeln(sprintf("Message : <options=bold>%s</>", $result['message']));
            $io->writeln(sprintf("Mail ? <options=bold>%s</>", $result['needSend'] ? 'Oui' : 'Non'));
            $io->writeln(sprintf("Déclaration (heures) : <options=bold>%s/%s</>", $result['total'], $result['needed']));
            $io->writeln(sprintf("Max : <options=bold>%s</>", $result['max']));
            $io->writeln(sprintf("Min : <options=bold>%s</>", $result['min']));
            $io->writeln(sprintf("Mail requis : <options=bold>%s</>", $result['mailRequired'] ? "Oui" : "Non"));
            $io->writeln(sprintf("Mail envoyé : <options=bold>%s</>", $result['mailSend'] ? "Oui" : "Non"));
            $io->writeln(sprintf("Dernier envoi : <options=bold>%s</>", $result['lastSend']));
            $io->writeln(sprintf("Prochain envoi : <options=bold>%s</>", $result['nextSend']));
            $io->writeln(sprintf("Status : <options=bold>%s</>", $result['status']));
        }
        else {
            $io->warning("Pas de données pour $declarer à la période $declarerPeriod");
        }
        return;
    }

    /**
     * @return MailingService
     */
    protected function getMailer()
    {
        return $this->getServicemanager()->get(MailingService::class);
    }

    /**
     * @return TimesheetService
     */
    protected function getTimesheetService(){
        return $this->getServicemanager()->get(TimesheetService::class);
    }

    /**
     * @return PersonService
     */
    protected function getPersonService(){
        return $this->getServicemanager()->get(PersonService::class);
    }

    //public function declarerRecall

    public function declarerPeriod( $declarerId, $period, $processDate = null ){
        if( $processDate == null ){
            $processDate = new \DateTime();
        }
        return $this->getTimesheetService()->recallProcess($declarerId, $period, $processDate);
    }

    public function declarer( InputInterface $input, OutputInterface $output, $declarerId ){

        $io = new SymfonyStyle($input, $output);

        try {
            $declarer = $this->getPersonService()->getPerson($declarerId);

            $io->title("Système de relance pour $declarer");
            $periods = $this->getTimesheetService()->getPersonRecallDeclaration($declarer);

            $io->table(["Période", "Durée", "état"], $periods);

        } catch (\Exception $e) {
            $io->error('Impossible de charger le déclarant : ' . $e->getMessage());
            exit(0);
        }
    }

    public function declarersList( InputInterface $input, OutputInterface $output ){
        $io = new SymfonyStyle($input, $output);
        $io->title("Lite des déclarants");
        try {
            $declarants = $this->getTimesheetService()->getDeclarers();
            $out = [];
            /** @var Person $declarer */
            foreach ($declarants['persons'] as $personId=>$datas) {
                $out[] = [$personId, $datas['displayname'], $datas['login'], $datas['affectation'], count($datas['declarations'])];
            }
            $headers = ['ID', 'login', 'Déclarant', 'Affectation', 'Déclaration(s)'];
            $io->table($headers, $out);

            $io->comment("Entrez la commande '".self::getName()." --". self::OPT_DECLARER . "=<ID>' pour afficher les détails");
        } catch (\Exception $e) {
            $io->error($e->getMessage());
        }
    }
}
 No newline at end of file
+29 −25
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
use Oscar\Service\TimesheetService;
use Oscar\Utils\DateTimeUtils;
use Oscar\Utils\PeriodInfos;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
@@ -32,49 +33,52 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Zend\Validator\Date;

class OscarTimesheetRecallsCommand extends OscarCommandAbstract
class OscarTimesheetRecallsCommand extends OscarAdvancedCommandAbstract
{
    protected static $defaultName = 'timesheets:recalls';

    const OPT_DECLARER      = "declarer";
    const OPT_PERIOD        = "period";

    protected function configure()
    {
        $this
            ->setDescription("Afficher les relances")
            ->setDescription("Relance automatique des feuilles de temps")
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->addOutputStyle($output);
        $io = new SymfonyStyle($input, $output);
        parent::execute($input, $output);

        $period = PeriodInfos::getPeriodInfosObj(date('Y-m'))->prevMonth();
        $force = false;

        $recalls = $this->getTimesheetService()->getRecalls();
        // Date de déclenchement de la procédure
        $processDate = new \DateTime();

        $headers = ["ID", "Date", "Depuis", "Déclarants", "Période"];
        $rows = [];
        $this->getIO()->title("Relance pour " . $period->getPeriodLabel());

        $moment = new Moment();
        $declarers = $this->getPersonService()->getPersonsByIds(
                $this->getPersonService()->getDeclarersIdsPeriod($period->getPeriodCode())
        );

        /** @var RecallDeclaration $recall */
        foreach ($recalls as $recall) {
            $moment = new Moment($recall->getLastSend()->getTimestamp());
            $row = [
                $recall->getId(),
                $recall->getLastSend()->format('Y-m-d H:i:s'),
                $moment->fromNow()->getRelative(),
                $recall->getPerson()->__toString(),
                sprintf("%s %s", $recall->getPeriodMonth(), $recall->getPeriodYear())
            ];
            $rows[] = $row;
        foreach ($declarers as $declarer) {
            $result = $this->getTimesheetService()->recallProcess($declarer->getId(), $period->getPeriodCode(), $processDate, $force);
            if( $result['mailSend'] ){
                $snd = "<green>Mail envoyé</green>";
            } else {
                if( $result['blocked'] ){
                    $snd = "<red>Bloqué</red>";
                } else {
                    $snd = "<none>Pas d'envoi</none>";
                }
            }
            $snd = $snd ." ". $result['recall_info'];
            $this->getIO()->writeln(" - <bold>$declarer</bold> : $snd");
        }
        $io->table($headers, $rows);
        /// OPTIONS and PARAMETERS

        return 0;
    }


    /**
     * @return TimesheetService
     */
Loading