Loading module/Oscar/src/Oscar/Entity/ActivityDate.php +98 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,12 @@ class ActivityDate implements ITrackable const PROGRESSION_REFUSED = 'refused'; const PROGRESSION_INPROGRESS = 'inprogress'; const STATE_TODO = 'todo'; const STATE_DONE = 'done'; const STATE_LATE = 'late'; const STATE_PAST = 'past'; const STATE_COMING = 'coming'; const STATE_NOW = 'now'; // Jalon terminé const VALUE_TODO = 0; Loading @@ -50,6 +56,21 @@ class ActivityDate implements ITrackable ]; } /** * @return string[] */ public static function statesLabels(): array { return [ self::STATE_DONE => "Fait", self::STATE_COMING => "A venir", self::STATE_PAST => "Passé", self::STATE_TODO => "A Faire", self::STATE_LATE => "En retard", self::STATE_NOW => "Aujourd'hui" ]; } /** * @return string[] */ Loading Loading @@ -189,7 +210,6 @@ class ActivityDate implements ITrackable } public function getProgressInfo(): string { if ($this->isFinishable()) { Loading Loading @@ -225,7 +245,12 @@ class ActivityDate implements ITrackable */ public function isLate(DateTime $now = new DateTime()): bool { return $this->isFinishable() && !$this->isFinished() && ($now > $this->getDateStart()); return $this->isFinishable() && !$this->isFinished() && $this->isPast($now); } public function isPast(DateTime $now = new DateTime()) { return $now > $this->getDateStart(); } /** Loading Loading @@ -376,10 +401,56 @@ class ActivityDate implements ITrackable return $this; } public function generateSubject(?array $options = null): string { if ($options === null) { $options = []; } } /** * Retourne le tag d'état du jalon. * * @param DateTime|null $now * @return string */ public function getTagTime(?DateTime $now = new DateTime()): string { if ($this->isFinishable()) { $tag = "todo"; if ($this->isFinished()) { $tag = "done"; } elseif ($this->isLate()) { $tag = "late"; } } else { if ($this->isNow($now)) { $tag = "now"; } elseif ($this->isPast($now)) { $tag = "past"; } else { $tag = "coming"; } } return $tag; } public function getTagTimeStr(?DateTime $now = new DateTime()): string { $tag = $this->getTagTime($now); if (array_key_exists($tag, $this::statesLabels())) { return $this::statesLabels()[$tag]; } else { return $tag; } } function __toString() { return $this->getDateStart()->format('d M Y') . ( $this->isFinishable() && $this->isLate() ? ' [En retard]' : '') . ' [' . $this->getTagTime() . ']' . ' (' . $this->getType() . ')'; } Loading Loading @@ -428,4 +499,27 @@ class ActivityDate implements ITrackable 'dateStart' => $this->getDateStartStr(), ]; } /** * @param DateTime|null $now * @return bool */ private function isNow(?DateTime $now): bool { return $this->getDateStartStr() == $now->format('Y-m-d'); } public function getEmailSubject(DateTime $dateReference): string { $state = $this->getTagTimeStr($dateReference); return $this->getType()->getLabel() . ' (' . $this->getDateStart()->format('d M Y') . ')' . ' [' . $state . '] ' . $this->getActivity(); } public function getEmailBody(array $variables = []) :string { return "EMAIL BODY\n"; } } No newline at end of file module/Oscar/src/Oscar/Entity/DateTypeRepository.php +43 −25 Original line number Diff line number Diff line Loading @@ -14,9 +14,37 @@ use Oscar\Exception\OscarException; class DateTypeRepository extends EntityRepository { public function allArray() public function allArray($clause = '') { try { $query = $this->getQueryWithRoleArray($clause); $results = $query->getResult(); foreach ($results as &$row) { if ($row['roles'] == '[null]') { $row['roles'] = []; } else { $rolesStr = $row['roles']; $row['roles'] = json_decode($rolesStr, false); } if ($row['roles_ids'] == '[null]') { $row['roles_ids'] = []; } else { $roles_idsStr = $row['roles_ids']; $row['roles_ids'] = json_decode($roles_idsStr, false); } } return $results; } catch (\Exception $e) { throw new OscarException($e->getMessage()); } } /** * @return \Doctrine\ORM\NativeQuery */ protected function getQueryWithRoleArray($where = ""){ $rsm = new ResultSetMapping(); $rsm->addScalarResult('id', 'id'); $rsm->addScalarResult('label', 'label'); Loading @@ -27,37 +55,27 @@ class DateTypeRepository extends EntityRepository $rsm->addScalarResult('finishable', 'finishable'); $rsm->addScalarResult('facet', 'facet'); $rsm->addScalarResult('roles', 'roles'); $rsm->addScalarResult('roles_ids', 'roles_ids'); $rsm->addScalarResult('used', 'used'); $sql = 'select d.id, d.label, d.description, d.emailenable, d.emailmessage, d.finishable , d.recursivity, d.facet, count(a.id) as used, json_agg(distinct ur.role_id) as roles from datetype d count(a.id) as used, json_agg(distinct ur.role_id) as roles, json_agg(distinct ur.id) as roles_ids from datetype d left join activitydate a ON a.type_id = d.id left join role_datetype rd on rd.datetype_id = d.id left join user_role ur on ur.id = rd.role_id ' . $where . ' group by d.id order by facet;'; $query = $this->getEntityManager()->createNativeQuery($sql, $rsm); $results = $query->getResult(); foreach ($results as &$row) { if ($row['roles'] == '[null]') { $row['roles'] = []; } else { $rolesStr = $row['roles']; $row['roles'] = json_decode($rolesStr, false); } } return $results; } catch (\Exception $e) { throw new OscarException($e->getMessage()); } return $query; } public function getMailablesMilestones() { $queryBuilder = $this->createQueryBuilder('d') ->select('d') ->where('d.emailEnable = true'); return $queryBuilder->getQuery()->getArrayResult(); return $this->allArray('WHERE d.emailenable = true'); } } module/Oscar/src/Oscar/Service/MilestoneService.php +37 −8 Original line number Diff line number Diff line Loading @@ -276,13 +276,18 @@ class MilestoneService implements UseLoggerService, UseEntityManager, UseOscarUs return $milestone; } public function mailMiltonesMailables( ?string $dateRef = null, SymfonyStyle $io ) :void { public function mailMiltonesMailables( ?string $dateRef = null, ?SymfonyStyle $io = null ) :void { // Date de référence $dateReference = new \DateTime($dateRef); // $io->section("Mails pour " . $dateReference->format('Y-m-d')); $ioMsg = function($str) use ($io) { if ($io !== null) { $io->writeln($str); } }; $ioMsg("Mails pour " . $dateReference->format('Y-m-d')); // Récupérer la liste des types de jalons $datetypes = $this->getDateTypeRepository()->getMailablesMilestones(); Loading @@ -294,12 +299,12 @@ class MilestoneService implements UseLoggerService, UseEntityManager, UseOscarUs $milestoneQueryFinishable = $this->getEntityManager()->getRepository(ActivityDate::class) ->createQueryBuilder('ad') ->where('ad.type = :datetype_id AND ad.dateStart IN(:dates)') ->orWhere('ad.dateStart < :dateref AND (ad.finished < 100 OR ad.finished IS NULL)'); ->orWhere('ad.type = :datetype_id AND ad.dateStart < :dateref AND (ad.finished < 100 OR ad.finished IS NULL)'); $dateRef = $dateReference->format('Y-m-d'); foreach ($datetypes as $datetype) { $io->info($datetype['label']); $ioMsg("\n#################################### " . $datetype['label'] . " ####################################"); $queryBuilder = $milestoneQueryStandard; Loading @@ -325,12 +330,36 @@ class MilestoneService implements UseLoggerService, UseEntityManager, UseOscarUs $parameters['dateref'][] = $dateRef; } $io->writeln($queryBuilder->getDQL()); // Obtention des jalons concernés pour la date de référence $milestones = $queryBuilder->setParameters($parameters)->getQuery()->getResult(); /** @var ActivityDate $milestone */ foreach ($milestones as $milestone) { echo "$milestone\n"; echo "\n# " . $milestone->getEmailSubject($dateReference)."\n"; echo "-------------------------------------------------\n"; echo $milestone->getEmailBody()."\n"; // Construction du sujet du mail // Construction du corps du mail // On récupère les personnes concernées $persons = $this->getProjectGrantService()->getPersonsActivity( $milestone->getActivity()->getId(), $datetype['roles_ids'], null ); // TODO A voir, récupérer les personnes de l'oganisation centrale ? /** @var Person $person */ foreach ($persons as $person) { $email = $person->getEmail(); $fullname = $person->getFullname(); echo " - $fullname ($email)\n"; } } } Loading module/Oscar/src/Oscar/Service/ProjectGrantService.php +2 −2 Original line number Diff line number Diff line Loading @@ -251,7 +251,7 @@ class ProjectGrantService implements UseGearmanJobLauncherService, UseOscarConfi } } if (count($filterRoleOrganization)) { //if ($filterRoleOrganization !== null && count($filterRoleOrganization)) { /** @var ActivityOrganization $organizationActivity */ foreach ($activity->getOrganizationsDeep() as $organizationActivity) { if ($filterRoleOrganization == null || in_array( Loading @@ -273,7 +273,7 @@ class ProjectGrantService implements UseGearmanJobLauncherService, UseOscarConfi } } } } //} usort($out, function ($a, $b) { return $a->getLastName() <=> $b->getLastName(); Loading Loading
module/Oscar/src/Oscar/Entity/ActivityDate.php +98 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,12 @@ class ActivityDate implements ITrackable const PROGRESSION_REFUSED = 'refused'; const PROGRESSION_INPROGRESS = 'inprogress'; const STATE_TODO = 'todo'; const STATE_DONE = 'done'; const STATE_LATE = 'late'; const STATE_PAST = 'past'; const STATE_COMING = 'coming'; const STATE_NOW = 'now'; // Jalon terminé const VALUE_TODO = 0; Loading @@ -50,6 +56,21 @@ class ActivityDate implements ITrackable ]; } /** * @return string[] */ public static function statesLabels(): array { return [ self::STATE_DONE => "Fait", self::STATE_COMING => "A venir", self::STATE_PAST => "Passé", self::STATE_TODO => "A Faire", self::STATE_LATE => "En retard", self::STATE_NOW => "Aujourd'hui" ]; } /** * @return string[] */ Loading Loading @@ -189,7 +210,6 @@ class ActivityDate implements ITrackable } public function getProgressInfo(): string { if ($this->isFinishable()) { Loading Loading @@ -225,7 +245,12 @@ class ActivityDate implements ITrackable */ public function isLate(DateTime $now = new DateTime()): bool { return $this->isFinishable() && !$this->isFinished() && ($now > $this->getDateStart()); return $this->isFinishable() && !$this->isFinished() && $this->isPast($now); } public function isPast(DateTime $now = new DateTime()) { return $now > $this->getDateStart(); } /** Loading Loading @@ -376,10 +401,56 @@ class ActivityDate implements ITrackable return $this; } public function generateSubject(?array $options = null): string { if ($options === null) { $options = []; } } /** * Retourne le tag d'état du jalon. * * @param DateTime|null $now * @return string */ public function getTagTime(?DateTime $now = new DateTime()): string { if ($this->isFinishable()) { $tag = "todo"; if ($this->isFinished()) { $tag = "done"; } elseif ($this->isLate()) { $tag = "late"; } } else { if ($this->isNow($now)) { $tag = "now"; } elseif ($this->isPast($now)) { $tag = "past"; } else { $tag = "coming"; } } return $tag; } public function getTagTimeStr(?DateTime $now = new DateTime()): string { $tag = $this->getTagTime($now); if (array_key_exists($tag, $this::statesLabels())) { return $this::statesLabels()[$tag]; } else { return $tag; } } function __toString() { return $this->getDateStart()->format('d M Y') . ( $this->isFinishable() && $this->isLate() ? ' [En retard]' : '') . ' [' . $this->getTagTime() . ']' . ' (' . $this->getType() . ')'; } Loading Loading @@ -428,4 +499,27 @@ class ActivityDate implements ITrackable 'dateStart' => $this->getDateStartStr(), ]; } /** * @param DateTime|null $now * @return bool */ private function isNow(?DateTime $now): bool { return $this->getDateStartStr() == $now->format('Y-m-d'); } public function getEmailSubject(DateTime $dateReference): string { $state = $this->getTagTimeStr($dateReference); return $this->getType()->getLabel() . ' (' . $this->getDateStart()->format('d M Y') . ')' . ' [' . $state . '] ' . $this->getActivity(); } public function getEmailBody(array $variables = []) :string { return "EMAIL BODY\n"; } } No newline at end of file
module/Oscar/src/Oscar/Entity/DateTypeRepository.php +43 −25 Original line number Diff line number Diff line Loading @@ -14,9 +14,37 @@ use Oscar\Exception\OscarException; class DateTypeRepository extends EntityRepository { public function allArray() public function allArray($clause = '') { try { $query = $this->getQueryWithRoleArray($clause); $results = $query->getResult(); foreach ($results as &$row) { if ($row['roles'] == '[null]') { $row['roles'] = []; } else { $rolesStr = $row['roles']; $row['roles'] = json_decode($rolesStr, false); } if ($row['roles_ids'] == '[null]') { $row['roles_ids'] = []; } else { $roles_idsStr = $row['roles_ids']; $row['roles_ids'] = json_decode($roles_idsStr, false); } } return $results; } catch (\Exception $e) { throw new OscarException($e->getMessage()); } } /** * @return \Doctrine\ORM\NativeQuery */ protected function getQueryWithRoleArray($where = ""){ $rsm = new ResultSetMapping(); $rsm->addScalarResult('id', 'id'); $rsm->addScalarResult('label', 'label'); Loading @@ -27,37 +55,27 @@ class DateTypeRepository extends EntityRepository $rsm->addScalarResult('finishable', 'finishable'); $rsm->addScalarResult('facet', 'facet'); $rsm->addScalarResult('roles', 'roles'); $rsm->addScalarResult('roles_ids', 'roles_ids'); $rsm->addScalarResult('used', 'used'); $sql = 'select d.id, d.label, d.description, d.emailenable, d.emailmessage, d.finishable , d.recursivity, d.facet, count(a.id) as used, json_agg(distinct ur.role_id) as roles from datetype d count(a.id) as used, json_agg(distinct ur.role_id) as roles, json_agg(distinct ur.id) as roles_ids from datetype d left join activitydate a ON a.type_id = d.id left join role_datetype rd on rd.datetype_id = d.id left join user_role ur on ur.id = rd.role_id ' . $where . ' group by d.id order by facet;'; $query = $this->getEntityManager()->createNativeQuery($sql, $rsm); $results = $query->getResult(); foreach ($results as &$row) { if ($row['roles'] == '[null]') { $row['roles'] = []; } else { $rolesStr = $row['roles']; $row['roles'] = json_decode($rolesStr, false); } } return $results; } catch (\Exception $e) { throw new OscarException($e->getMessage()); } return $query; } public function getMailablesMilestones() { $queryBuilder = $this->createQueryBuilder('d') ->select('d') ->where('d.emailEnable = true'); return $queryBuilder->getQuery()->getArrayResult(); return $this->allArray('WHERE d.emailenable = true'); } }
module/Oscar/src/Oscar/Service/MilestoneService.php +37 −8 Original line number Diff line number Diff line Loading @@ -276,13 +276,18 @@ class MilestoneService implements UseLoggerService, UseEntityManager, UseOscarUs return $milestone; } public function mailMiltonesMailables( ?string $dateRef = null, SymfonyStyle $io ) :void { public function mailMiltonesMailables( ?string $dateRef = null, ?SymfonyStyle $io = null ) :void { // Date de référence $dateReference = new \DateTime($dateRef); // $io->section("Mails pour " . $dateReference->format('Y-m-d')); $ioMsg = function($str) use ($io) { if ($io !== null) { $io->writeln($str); } }; $ioMsg("Mails pour " . $dateReference->format('Y-m-d')); // Récupérer la liste des types de jalons $datetypes = $this->getDateTypeRepository()->getMailablesMilestones(); Loading @@ -294,12 +299,12 @@ class MilestoneService implements UseLoggerService, UseEntityManager, UseOscarUs $milestoneQueryFinishable = $this->getEntityManager()->getRepository(ActivityDate::class) ->createQueryBuilder('ad') ->where('ad.type = :datetype_id AND ad.dateStart IN(:dates)') ->orWhere('ad.dateStart < :dateref AND (ad.finished < 100 OR ad.finished IS NULL)'); ->orWhere('ad.type = :datetype_id AND ad.dateStart < :dateref AND (ad.finished < 100 OR ad.finished IS NULL)'); $dateRef = $dateReference->format('Y-m-d'); foreach ($datetypes as $datetype) { $io->info($datetype['label']); $ioMsg("\n#################################### " . $datetype['label'] . " ####################################"); $queryBuilder = $milestoneQueryStandard; Loading @@ -325,12 +330,36 @@ class MilestoneService implements UseLoggerService, UseEntityManager, UseOscarUs $parameters['dateref'][] = $dateRef; } $io->writeln($queryBuilder->getDQL()); // Obtention des jalons concernés pour la date de référence $milestones = $queryBuilder->setParameters($parameters)->getQuery()->getResult(); /** @var ActivityDate $milestone */ foreach ($milestones as $milestone) { echo "$milestone\n"; echo "\n# " . $milestone->getEmailSubject($dateReference)."\n"; echo "-------------------------------------------------\n"; echo $milestone->getEmailBody()."\n"; // Construction du sujet du mail // Construction du corps du mail // On récupère les personnes concernées $persons = $this->getProjectGrantService()->getPersonsActivity( $milestone->getActivity()->getId(), $datetype['roles_ids'], null ); // TODO A voir, récupérer les personnes de l'oganisation centrale ? /** @var Person $person */ foreach ($persons as $person) { $email = $person->getEmail(); $fullname = $person->getFullname(); echo " - $fullname ($email)\n"; } } } Loading
module/Oscar/src/Oscar/Service/ProjectGrantService.php +2 −2 Original line number Diff line number Diff line Loading @@ -251,7 +251,7 @@ class ProjectGrantService implements UseGearmanJobLauncherService, UseOscarConfi } } if (count($filterRoleOrganization)) { //if ($filterRoleOrganization !== null && count($filterRoleOrganization)) { /** @var ActivityOrganization $organizationActivity */ foreach ($activity->getOrganizationsDeep() as $organizationActivity) { if ($filterRoleOrganization == null || in_array( Loading @@ -273,7 +273,7 @@ class ProjectGrantService implements UseGearmanJobLauncherService, UseOscarConfi } } } } //} usort($out, function ($a, $b) { return $a->getLastName() <=> $b->getLastName(); Loading