Loading front/src/TimesheetHigDelay.vue +39 −22 Original line number Diff line number Diff line Loading @@ -8,6 +8,12 @@ </pre> </div> </div> <nav> <select v-model="includeNonActive" @change="updateActive"> <option value="on">Affiche les activités non-active</option> <option value="off">Activités "Active" uniquement</option> </select> </nav> <article class="card" v-for="entry in entries"> <h2 class="card-title"> <span class="profile"> Loading @@ -33,24 +39,25 @@ <i class="icon-user"></i> Validateur(s) impliqué(s) : </h4> <div class="alert alert-danger" v-if="entry.np1.length == 0"><i class="icon-attention-1"></i> Aucun <em>N+1</em> (validateur hors-lot) n'est assigné à ce déclarant, vous pouvez lui en assigner un (ou plusieurs) depuis la fiche personne. <div class="danger-area" v-if="entry.np1.length == 0"><i class="icon-attention-1"></i> Aucun <em>N+1</em> (validateur hors-lot) n'est assigné à ce déclarant. <span v-if="entry.url_show"> <a :href="entry.url_show"> Corriger depuis la fiche </a> </span> </div> <div v-if="entry.send == true && entry.validators.length == 0" class="alert alert-danger"> <div v-if="entry.send == true && entry.validators.length == 0" class="danger-area"> <i class="icon-attention-1"></i> Aucun validateur n'est désigné pour valider ces déclarations, rendez-vous dans la fiche activité afin de vérifier que des validateurs sont bien désignés. </div> <div v-else> <p class="info-area"> Les validateurs ci-dessous sont ceux qui sont impliqués personnellement dans les validations en cours. </p> <ul> <li v-for="v in entry.validators"><i class="icon-cube"></i> {{ v }}</li> <li v-for="(v, i) in entry.validators"><i class="icon-cube"></i> {{ v.fullname }}</li> <li v-for="v in entry.np1"> <i class="icon-tag"></i> <strong>{{ v }}</strong> <strong>{{ v.fullname }}</strong> <small> (Validateur Hors-Lot)</small> </li> </ul> Loading @@ -60,20 +67,25 @@ <i class="icon-cubes"></i> Activités </h4> <p class="info-area"> Liste des activités où <strong>{{ entry.fullname }}</strong> a été identifié comme déclarant. Vous pouvez voir les validateurs désignés pour valider les futurs déclarations envoyées. </p> <article v-for="activity in entry.activities" class="card xs"> <!-- <p class="info-area">--> <!-- Liste des activités où <strong>{{ entry.fullname }}</strong> a été identifié comme déclarant.--> <!-- Vous pouvez voir les validateurs désignés pour valider les futurs déclarations envoyées.--> <!-- </p>--> <article v-for="activity in entry.activities" class="card xs activity"> <h5> <span> <i class="icon-cubes"></i> <strong>[{{ activity.acronym }}]</strong> <em>{{ activity.label }}</em> </span> <a :href="activity.url_timesheet" v-if="activity.url_timesheet"> Configurer </a> </h5> <div v-if="activity.validators.prj.length != 0"> <i class="icon-cube"></i> <strong v-for="p in activity.validators.prj" class="cartouche">{{ p }}</strong> <strong v-for="p in activity.validators.prj" class="cartouche">{{ p.fullname }}</strong> </div> <div v-else class="bg-danger"> <i class="icon-attention-1"></i> Loading @@ -82,7 +94,7 @@ <div v-if="activity.validators.sci.length != 0"> <i class="icon-beaker"></i> <strong v-for="p in activity.validators.sci" class="cartouche">{{ p }}</strong> <strong v-for="p in activity.validators.sci" class="cartouche">{{ p.fullname }}</strong> </div> <div v-else class="bg-danger"> <i class="icon-attention-1"></i> Loading @@ -91,7 +103,7 @@ <div v-if="activity.validators.adm.length != 0"> <i class="icon-book"></i> <strong v-for="p in activity.validators.adm" class="cartouche">{{ p }}</strong> <strong v-for="p in activity.validators.adm" class="cartouche">{{ p.fullname }}</strong> </div> <div v-else class="bg-danger"> <i class="icon-attention-1"></i> Loading Loading @@ -209,7 +221,8 @@ export default { return { /** Liste des données (Personne,periode) **/ entries: [], debug: null debug: null, includeNonActive: 'off' } }, Loading @@ -224,7 +237,7 @@ export default { methods: { fetch() { this.$http.get(this.url).then( this.$http.get(this.url +'?a=' +this.includeNonActive).then( ok => { this.entries = ok.data.highdelays; }, Loading @@ -232,6 +245,10 @@ export default { console.log(ko); } ) }, updateActive() { this.fetch(); } }, Loading module/Oscar/src/Oscar/Command/OscarTimesheetHighDelayCommand.php +58 −28 Original line number Diff line number Diff line Loading @@ -40,9 +40,9 @@ class OscarTimesheetHighDelayCommand extends OscarAdvancedCommandAbstract protected function configure() { $this ->setDescription("Relance automatique des feuilles de temps") ->addOption("purge", null, InputOption::VALUE_OPTIONAL, "Suppression des données (dev)", false) ->addOption("preview", null, InputOption::VALUE_OPTIONAL, "Aperçu (affiche les personnes concernées)", false) ->setDescription("Relance automatique des retards importants") ->addOption("include-nonactive", null, InputOption::VALUE_NONE, "Inclus les activités non-active") ->addOption("send", null, InputOption::VALUE_NONE, "Effectue l'envoi réél des mails") ->addOption("processdate", null, InputOption::VALUE_OPTIONAL, "Date d'execution", false) ; } Loading @@ -53,22 +53,9 @@ class OscarTimesheetHighDelayCommand extends OscarAdvancedCommandAbstract $processArg = $input->getOption('processdate'); $purge = $input->getOption('purge'); $preview = $input->getOption('preview') !== false; $includeNonActive = $input->getOption('include-nonactive') != false; $send = $input->getOption('send') !== false; if( $purge === null ){ // $recalls = $this->getOrganizationService()->getEntityManager()->getRepository(RecallDeclaration::class)->findAll(); // if($this->ask("Reset complet des procédures de rappel ? (y)")){ // foreach ($recalls as $r) { // $this->getOrganizationService()->getEntityManager()->remove($r); // } // $this->getOrganizationService()->getEntityManager()->flush(); // die(); // } else { // $this->getIO()->writeln("Annulé"); // } } if( !$processArg ){ $period = PeriodInfos::getPeriodInfosObj(date('Y-m'))->prevMonth(); Loading @@ -80,32 +67,75 @@ class OscarTimesheetHighDelayCommand extends OscarAdvancedCommandAbstract $force = false; $this->getIO()->title("Relance dans retards importants pour les déclarants (avant " . $period->getPeriodLabel() . ")"); $this->getIO()->writeln("OPTION send : " . ($send ? 'on' : 'off')); $this->getIO()->writeln("OPTION include-nonactive : " . ($includeNonActive ? 'on' : 'off')); // Liste des personnes avec des retards anciens (Personne => Période) $datas = $this->getPersonService()->getPersonsHighDelay($period->getPeriodCode()); $datas = $this->getPersonService()->getPersonsHighDelay($period->getPeriodCode(), null, $includeNonActive == 'on'); $subject = '[OSCAR] Déclaration en retard'; $body = $this->getOscarConfigurationService()->getHighDelayRelance(); $validatorsStack = []; foreach ($datas as $personDt) { $this->getIO()->title("Traitement pour " . $personDt['fullname']); if( $personDt['require_alert_declarer'] == true ){ $this->getIO()->writeln("<green> > Envoi : Déclarant</green>"); $result = $this->getTimesheetService()->recallHighDelayDeclarer($personDt['person_id']); $email = $personDt['email']; $fullname = $personDt['fullname']; $this->getIO()->writeln("<green> \u{2714} Envoi au Déclarant $fullname ($email)</green>"); if( $send ) { try { $message = $this->getPersonService()->getMailingService()->newMessage($subject); $message->setBody($body); $message->addTo($email); $this->getPersonService()->getMailingService()->send($message); } catch (\Exception $e) { $this->getIO()->error($e->getMessage()); } } } else { $this->getIO()->writeln("<info> - pas d'envoi pour le déclarant</info>"); // $this->getIO()->writeln("<info> x pas d'envoi pour le déclarant</info>"); } if( count($personDt['np1']) == 0 ){ $this->getIO()->error("\u{26A0} Le déclarant '$fullname' n'a pas de validateur administratif pour ces créneaux Hors-Lot"); } // Il y'a des validateurs à soliciter pour ce déclarant if( $personDt['require_alert_validator'] == true ){ if( count($personDt['validators']) ){ foreach ($personDt['validators'] as $i=>$name) { $this->getIO()->writeln("<green> > Envoi validateur : $name</green>"); foreach ($personDt['validators'] as $i=>$infosValidator) { $validatorsStack[$i] = $infosValidator; } } else { $this->getIO()->error("Pas de validateur pour ce déclarant"); $this->getIO()->error("\u{26A0} Pas de validateur pour les déclarations de $fullname, vérifier que ces activités ont des validateurs désignés"); } } else { $this->getIO()->writeln("<info> - pas d'envoi pour le validateur</info>"); // $this->getIO()->writeln("<comment> \u{2716} pas d'envoi pour le validateur (aucune déclaration à valider)</comment>"); } } $this->getIO()->title("Envois groupé aux validateurs"); foreach ($validatorsStack as $i=>$infosValidator) { $validatorName = $infosValidator['fullname']; $validatorEmail = $infosValidator['email']; $this->getIO()->writeln("<green> \u{2714} Envoi validateur : $validatorName ($validatorEmail)</green>"); if( $send ) { $message = $this->getPersonService()->getMailingService()->newMessage($subject); $message->setBody($body); $message->addTo($validatorEmail); $this->getPersonService()->getMailingService()->send($message); } } if( $send == false ){ $this->getIO()->warning("AUCUN ENVOI EFFECTUE, UTILISEZ --send POUR l'ENVOI EFFECTIF"); } return 0; } Loading module/Oscar/src/Oscar/Controller/ProjectGrantController.php +37 −9 Original line number Diff line number Diff line Loading @@ -669,7 +669,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif $formatter = new ActivityToJsonFormatter(); $json = $formatter->format($activity); return $this->jsonOutput($json); die("TODO : $activity"); } /** Loading Loading @@ -935,20 +934,49 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif public function deleteAction() { try { $projectGrant = $this->getActivityFromRoute(); $activity = $this->getActivityFromRoute(); $this->getOscarUserContextService()->check( Privileges::ACTIVITY_DELETE, $projectGrant $activity ); $project = $projectGrant->getProject(); $this->getLoggerService()->info(sprintf('Suppression de %s - %s', $projectGrant, $projectGrant->getId())); $activity_id = $projectGrant->getId(); $this->getLoggerService()->info(sprintf('Suppression de %s - %s', $activity, $activity->getId())); $project = $activity->getProject(); //////////////////////////////////////////////////////////////////////////////////////////////////////////// // Récupération des informations annexes // On supprime les créneaux $this->getTimesheetService()->removeTimesheetActivity($activity); // Suppression des documents $documents = $activity->getDocuments(); if( count($documents) ){ $documentPathRoot = $this->getOscarConfigurationService()->getDocumentDropLocation(); /** @var ContractDocument $d */ foreach ($documents as $d) { $path = $documentPathRoot.'/'.$d->getPath(); if( file_exists($path) ){ unlink($path); } $this->getLoggerService()->info("Suppression du document '$d'"); $this->getLoggerService()->info("Fichier '$path'"); $this->getEntityManager()->remove($d); } $this->getEntityManager()->flush(); } try { $this->getActivityService()->searchDelete($activity_id); $this->getActivityService()->searchDelete($activity->getId()); } catch (\Exception $e) { } $this->getEntityManager()->remove($projectGrant); $this->getEntityManager()->remove($activity); $this->getEntityManager()->flush(); if (!$project) { Loading @@ -958,7 +986,7 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif $this->redirect()->toRoute( 'project/show', ['id' => $projectGrant->getProject()->getId()] ['id' => $activity->getProject()->getId()] ); } } catch (\Exception $e) { Loading module/Oscar/src/Oscar/Controller/TimesheetController.php +12 −1 Original line number Diff line number Diff line Loading @@ -664,11 +664,20 @@ class TimesheetController extends AbstractOscarController ]; } /** * url(/feuille-de-temps/highdelay) * @return array|JsonModel * @throws OscarException * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ public function highDelayAction() { $this->getOscarUserContextService()->check(Privileges::MAINTENANCE_VALIDATION_MANAGE); $format = $this->params()->fromQuery('f', OscarFormatterConst::FORMAT_IO_HTML); $includeNonActive = $this->params()->fromQuery('a', 'off'); if ($this->isAjax() || $format == OscarFormatterConst::FORMAT_IO_JSON) { // Critères $period = $this->params()->fromQuery('period', date('Y-m')); Loading @@ -676,9 +685,11 @@ class TimesheetController extends AbstractOscarController $datas = $this->baseJsonResponse(); // Liste des personnes avec des retards anciens (Personne => Période) $datas['include_nonactive'] = $includeNonActive == 'on'; $datas['highdelays'] = $this->getPersonService()->getPersonsHighDelay( $period->getPeriodCode(), $this->url() $this->url(), $includeNonActive == 'on' ); return $this->jsonOutput($datas); } Loading module/Oscar/src/Oscar/Entity/PersonRepository.php +16 −6 Original line number Diff line number Diff line Loading @@ -500,7 +500,7 @@ class PersonRepository extends EntityRepository implements IConnectedRepository * (ATTENTION : Si aucune déclaration n'a été envoyée, il n'y a pas de résultats) * @param int $personId */ public function getRepportDeclarationPerson( int $personId ) public function getRepportDeclarationPerson( int $personId, bool $includenonActive = false ) { $sql = "SELECT declarer_id AS declarer_id, Loading @@ -519,6 +519,7 @@ class PersonRepository extends EntityRepository implements IConnectedRepository GROUP BY declarer_id, period ORDER BY period"; $query = $this->getEntityManager()->getConnection()->prepare($sql); $result = $query->executeQuery([ Loading @@ -530,7 +531,13 @@ class PersonRepository extends EntityRepository implements IConnectedRepository return $datas; } public function getIdsDeclarersBeforePeriod( string $period ): array /** * Retourne les ID des déclarants avant la période donnée. * * @param string $period * @return array */ public function getIdsDeclarersBeforePeriod( string $period, bool $includeNonActive = false ): array { $qb = $this->getEntityManager()->createQueryBuilder() ->select('DISTINCT(p.id) id') Loading @@ -538,19 +545,22 @@ class PersonRepository extends EntityRepository implements IConnectedRepository ->innerJoin('p.workPackages', 'wpp') ->groupBy('p.id'); $parametersQuery = []; $extract = DateTimeUtils::periodBounds($period); $end = $extract['end']; $qb->innerJoin('wpp.workPackage', 'wp') ->innerJoin('wp.activity', 'a') ->where('a.dateStart < :periodEnd'); $parametersQuery = [ 'periodEnd' => $end ]; if( $includeNonActive == false ){ $qb->andWhere('a.status = :status'); $parametersQuery['status'] = Activity::STATUS_ACTIVE; } $qb->setParameters($parametersQuery); $results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY); Loading Loading
front/src/TimesheetHigDelay.vue +39 −22 Original line number Diff line number Diff line Loading @@ -8,6 +8,12 @@ </pre> </div> </div> <nav> <select v-model="includeNonActive" @change="updateActive"> <option value="on">Affiche les activités non-active</option> <option value="off">Activités "Active" uniquement</option> </select> </nav> <article class="card" v-for="entry in entries"> <h2 class="card-title"> <span class="profile"> Loading @@ -33,24 +39,25 @@ <i class="icon-user"></i> Validateur(s) impliqué(s) : </h4> <div class="alert alert-danger" v-if="entry.np1.length == 0"><i class="icon-attention-1"></i> Aucun <em>N+1</em> (validateur hors-lot) n'est assigné à ce déclarant, vous pouvez lui en assigner un (ou plusieurs) depuis la fiche personne. <div class="danger-area" v-if="entry.np1.length == 0"><i class="icon-attention-1"></i> Aucun <em>N+1</em> (validateur hors-lot) n'est assigné à ce déclarant. <span v-if="entry.url_show"> <a :href="entry.url_show"> Corriger depuis la fiche </a> </span> </div> <div v-if="entry.send == true && entry.validators.length == 0" class="alert alert-danger"> <div v-if="entry.send == true && entry.validators.length == 0" class="danger-area"> <i class="icon-attention-1"></i> Aucun validateur n'est désigné pour valider ces déclarations, rendez-vous dans la fiche activité afin de vérifier que des validateurs sont bien désignés. </div> <div v-else> <p class="info-area"> Les validateurs ci-dessous sont ceux qui sont impliqués personnellement dans les validations en cours. </p> <ul> <li v-for="v in entry.validators"><i class="icon-cube"></i> {{ v }}</li> <li v-for="(v, i) in entry.validators"><i class="icon-cube"></i> {{ v.fullname }}</li> <li v-for="v in entry.np1"> <i class="icon-tag"></i> <strong>{{ v }}</strong> <strong>{{ v.fullname }}</strong> <small> (Validateur Hors-Lot)</small> </li> </ul> Loading @@ -60,20 +67,25 @@ <i class="icon-cubes"></i> Activités </h4> <p class="info-area"> Liste des activités où <strong>{{ entry.fullname }}</strong> a été identifié comme déclarant. Vous pouvez voir les validateurs désignés pour valider les futurs déclarations envoyées. </p> <article v-for="activity in entry.activities" class="card xs"> <!-- <p class="info-area">--> <!-- Liste des activités où <strong>{{ entry.fullname }}</strong> a été identifié comme déclarant.--> <!-- Vous pouvez voir les validateurs désignés pour valider les futurs déclarations envoyées.--> <!-- </p>--> <article v-for="activity in entry.activities" class="card xs activity"> <h5> <span> <i class="icon-cubes"></i> <strong>[{{ activity.acronym }}]</strong> <em>{{ activity.label }}</em> </span> <a :href="activity.url_timesheet" v-if="activity.url_timesheet"> Configurer </a> </h5> <div v-if="activity.validators.prj.length != 0"> <i class="icon-cube"></i> <strong v-for="p in activity.validators.prj" class="cartouche">{{ p }}</strong> <strong v-for="p in activity.validators.prj" class="cartouche">{{ p.fullname }}</strong> </div> <div v-else class="bg-danger"> <i class="icon-attention-1"></i> Loading @@ -82,7 +94,7 @@ <div v-if="activity.validators.sci.length != 0"> <i class="icon-beaker"></i> <strong v-for="p in activity.validators.sci" class="cartouche">{{ p }}</strong> <strong v-for="p in activity.validators.sci" class="cartouche">{{ p.fullname }}</strong> </div> <div v-else class="bg-danger"> <i class="icon-attention-1"></i> Loading @@ -91,7 +103,7 @@ <div v-if="activity.validators.adm.length != 0"> <i class="icon-book"></i> <strong v-for="p in activity.validators.adm" class="cartouche">{{ p }}</strong> <strong v-for="p in activity.validators.adm" class="cartouche">{{ p.fullname }}</strong> </div> <div v-else class="bg-danger"> <i class="icon-attention-1"></i> Loading Loading @@ -209,7 +221,8 @@ export default { return { /** Liste des données (Personne,periode) **/ entries: [], debug: null debug: null, includeNonActive: 'off' } }, Loading @@ -224,7 +237,7 @@ export default { methods: { fetch() { this.$http.get(this.url).then( this.$http.get(this.url +'?a=' +this.includeNonActive).then( ok => { this.entries = ok.data.highdelays; }, Loading @@ -232,6 +245,10 @@ export default { console.log(ko); } ) }, updateActive() { this.fetch(); } }, Loading
module/Oscar/src/Oscar/Command/OscarTimesheetHighDelayCommand.php +58 −28 Original line number Diff line number Diff line Loading @@ -40,9 +40,9 @@ class OscarTimesheetHighDelayCommand extends OscarAdvancedCommandAbstract protected function configure() { $this ->setDescription("Relance automatique des feuilles de temps") ->addOption("purge", null, InputOption::VALUE_OPTIONAL, "Suppression des données (dev)", false) ->addOption("preview", null, InputOption::VALUE_OPTIONAL, "Aperçu (affiche les personnes concernées)", false) ->setDescription("Relance automatique des retards importants") ->addOption("include-nonactive", null, InputOption::VALUE_NONE, "Inclus les activités non-active") ->addOption("send", null, InputOption::VALUE_NONE, "Effectue l'envoi réél des mails") ->addOption("processdate", null, InputOption::VALUE_OPTIONAL, "Date d'execution", false) ; } Loading @@ -53,22 +53,9 @@ class OscarTimesheetHighDelayCommand extends OscarAdvancedCommandAbstract $processArg = $input->getOption('processdate'); $purge = $input->getOption('purge'); $preview = $input->getOption('preview') !== false; $includeNonActive = $input->getOption('include-nonactive') != false; $send = $input->getOption('send') !== false; if( $purge === null ){ // $recalls = $this->getOrganizationService()->getEntityManager()->getRepository(RecallDeclaration::class)->findAll(); // if($this->ask("Reset complet des procédures de rappel ? (y)")){ // foreach ($recalls as $r) { // $this->getOrganizationService()->getEntityManager()->remove($r); // } // $this->getOrganizationService()->getEntityManager()->flush(); // die(); // } else { // $this->getIO()->writeln("Annulé"); // } } if( !$processArg ){ $period = PeriodInfos::getPeriodInfosObj(date('Y-m'))->prevMonth(); Loading @@ -80,32 +67,75 @@ class OscarTimesheetHighDelayCommand extends OscarAdvancedCommandAbstract $force = false; $this->getIO()->title("Relance dans retards importants pour les déclarants (avant " . $period->getPeriodLabel() . ")"); $this->getIO()->writeln("OPTION send : " . ($send ? 'on' : 'off')); $this->getIO()->writeln("OPTION include-nonactive : " . ($includeNonActive ? 'on' : 'off')); // Liste des personnes avec des retards anciens (Personne => Période) $datas = $this->getPersonService()->getPersonsHighDelay($period->getPeriodCode()); $datas = $this->getPersonService()->getPersonsHighDelay($period->getPeriodCode(), null, $includeNonActive == 'on'); $subject = '[OSCAR] Déclaration en retard'; $body = $this->getOscarConfigurationService()->getHighDelayRelance(); $validatorsStack = []; foreach ($datas as $personDt) { $this->getIO()->title("Traitement pour " . $personDt['fullname']); if( $personDt['require_alert_declarer'] == true ){ $this->getIO()->writeln("<green> > Envoi : Déclarant</green>"); $result = $this->getTimesheetService()->recallHighDelayDeclarer($personDt['person_id']); $email = $personDt['email']; $fullname = $personDt['fullname']; $this->getIO()->writeln("<green> \u{2714} Envoi au Déclarant $fullname ($email)</green>"); if( $send ) { try { $message = $this->getPersonService()->getMailingService()->newMessage($subject); $message->setBody($body); $message->addTo($email); $this->getPersonService()->getMailingService()->send($message); } catch (\Exception $e) { $this->getIO()->error($e->getMessage()); } } } else { $this->getIO()->writeln("<info> - pas d'envoi pour le déclarant</info>"); // $this->getIO()->writeln("<info> x pas d'envoi pour le déclarant</info>"); } if( count($personDt['np1']) == 0 ){ $this->getIO()->error("\u{26A0} Le déclarant '$fullname' n'a pas de validateur administratif pour ces créneaux Hors-Lot"); } // Il y'a des validateurs à soliciter pour ce déclarant if( $personDt['require_alert_validator'] == true ){ if( count($personDt['validators']) ){ foreach ($personDt['validators'] as $i=>$name) { $this->getIO()->writeln("<green> > Envoi validateur : $name</green>"); foreach ($personDt['validators'] as $i=>$infosValidator) { $validatorsStack[$i] = $infosValidator; } } else { $this->getIO()->error("Pas de validateur pour ce déclarant"); $this->getIO()->error("\u{26A0} Pas de validateur pour les déclarations de $fullname, vérifier que ces activités ont des validateurs désignés"); } } else { $this->getIO()->writeln("<info> - pas d'envoi pour le validateur</info>"); // $this->getIO()->writeln("<comment> \u{2716} pas d'envoi pour le validateur (aucune déclaration à valider)</comment>"); } } $this->getIO()->title("Envois groupé aux validateurs"); foreach ($validatorsStack as $i=>$infosValidator) { $validatorName = $infosValidator['fullname']; $validatorEmail = $infosValidator['email']; $this->getIO()->writeln("<green> \u{2714} Envoi validateur : $validatorName ($validatorEmail)</green>"); if( $send ) { $message = $this->getPersonService()->getMailingService()->newMessage($subject); $message->setBody($body); $message->addTo($validatorEmail); $this->getPersonService()->getMailingService()->send($message); } } if( $send == false ){ $this->getIO()->warning("AUCUN ENVOI EFFECTUE, UTILISEZ --send POUR l'ENVOI EFFECTIF"); } return 0; } Loading
module/Oscar/src/Oscar/Controller/ProjectGrantController.php +37 −9 Original line number Diff line number Diff line Loading @@ -669,7 +669,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif $formatter = new ActivityToJsonFormatter(); $json = $formatter->format($activity); return $this->jsonOutput($json); die("TODO : $activity"); } /** Loading Loading @@ -935,20 +934,49 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif public function deleteAction() { try { $projectGrant = $this->getActivityFromRoute(); $activity = $this->getActivityFromRoute(); $this->getOscarUserContextService()->check( Privileges::ACTIVITY_DELETE, $projectGrant $activity ); $project = $projectGrant->getProject(); $this->getLoggerService()->info(sprintf('Suppression de %s - %s', $projectGrant, $projectGrant->getId())); $activity_id = $projectGrant->getId(); $this->getLoggerService()->info(sprintf('Suppression de %s - %s', $activity, $activity->getId())); $project = $activity->getProject(); //////////////////////////////////////////////////////////////////////////////////////////////////////////// // Récupération des informations annexes // On supprime les créneaux $this->getTimesheetService()->removeTimesheetActivity($activity); // Suppression des documents $documents = $activity->getDocuments(); if( count($documents) ){ $documentPathRoot = $this->getOscarConfigurationService()->getDocumentDropLocation(); /** @var ContractDocument $d */ foreach ($documents as $d) { $path = $documentPathRoot.'/'.$d->getPath(); if( file_exists($path) ){ unlink($path); } $this->getLoggerService()->info("Suppression du document '$d'"); $this->getLoggerService()->info("Fichier '$path'"); $this->getEntityManager()->remove($d); } $this->getEntityManager()->flush(); } try { $this->getActivityService()->searchDelete($activity_id); $this->getActivityService()->searchDelete($activity->getId()); } catch (\Exception $e) { } $this->getEntityManager()->remove($projectGrant); $this->getEntityManager()->remove($activity); $this->getEntityManager()->flush(); if (!$project) { Loading @@ -958,7 +986,7 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif $this->redirect()->toRoute( 'project/show', ['id' => $projectGrant->getProject()->getId()] ['id' => $activity->getProject()->getId()] ); } } catch (\Exception $e) { Loading
module/Oscar/src/Oscar/Controller/TimesheetController.php +12 −1 Original line number Diff line number Diff line Loading @@ -664,11 +664,20 @@ class TimesheetController extends AbstractOscarController ]; } /** * url(/feuille-de-temps/highdelay) * @return array|JsonModel * @throws OscarException * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ public function highDelayAction() { $this->getOscarUserContextService()->check(Privileges::MAINTENANCE_VALIDATION_MANAGE); $format = $this->params()->fromQuery('f', OscarFormatterConst::FORMAT_IO_HTML); $includeNonActive = $this->params()->fromQuery('a', 'off'); if ($this->isAjax() || $format == OscarFormatterConst::FORMAT_IO_JSON) { // Critères $period = $this->params()->fromQuery('period', date('Y-m')); Loading @@ -676,9 +685,11 @@ class TimesheetController extends AbstractOscarController $datas = $this->baseJsonResponse(); // Liste des personnes avec des retards anciens (Personne => Période) $datas['include_nonactive'] = $includeNonActive == 'on'; $datas['highdelays'] = $this->getPersonService()->getPersonsHighDelay( $period->getPeriodCode(), $this->url() $this->url(), $includeNonActive == 'on' ); return $this->jsonOutput($datas); } Loading
module/Oscar/src/Oscar/Entity/PersonRepository.php +16 −6 Original line number Diff line number Diff line Loading @@ -500,7 +500,7 @@ class PersonRepository extends EntityRepository implements IConnectedRepository * (ATTENTION : Si aucune déclaration n'a été envoyée, il n'y a pas de résultats) * @param int $personId */ public function getRepportDeclarationPerson( int $personId ) public function getRepportDeclarationPerson( int $personId, bool $includenonActive = false ) { $sql = "SELECT declarer_id AS declarer_id, Loading @@ -519,6 +519,7 @@ class PersonRepository extends EntityRepository implements IConnectedRepository GROUP BY declarer_id, period ORDER BY period"; $query = $this->getEntityManager()->getConnection()->prepare($sql); $result = $query->executeQuery([ Loading @@ -530,7 +531,13 @@ class PersonRepository extends EntityRepository implements IConnectedRepository return $datas; } public function getIdsDeclarersBeforePeriod( string $period ): array /** * Retourne les ID des déclarants avant la période donnée. * * @param string $period * @return array */ public function getIdsDeclarersBeforePeriod( string $period, bool $includeNonActive = false ): array { $qb = $this->getEntityManager()->createQueryBuilder() ->select('DISTINCT(p.id) id') Loading @@ -538,19 +545,22 @@ class PersonRepository extends EntityRepository implements IConnectedRepository ->innerJoin('p.workPackages', 'wpp') ->groupBy('p.id'); $parametersQuery = []; $extract = DateTimeUtils::periodBounds($period); $end = $extract['end']; $qb->innerJoin('wpp.workPackage', 'wp') ->innerJoin('wp.activity', 'a') ->where('a.dateStart < :periodEnd'); $parametersQuery = [ 'periodEnd' => $end ]; if( $includeNonActive == false ){ $qb->andWhere('a.status = :status'); $parametersQuery['status'] = Activity::STATUS_ACTIVE; } $qb->setParameters($parametersQuery); $results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY); Loading