Commit 650f4dd8 authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Travaux en cours sur les notifications / optimisation des requêtes

parent c8e65a6d
Loading
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
<?php


namespace Oscar\Command;


use Oscar\Service\NotificationService;
use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
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;

class OscarNotificationsPurgeCommand extends OscarCommandAbstract
{
    protected static $defaultName = 'notifications:purge';

    protected function configure()
    {
        $this
            ->setDescription("Purge les notifications obsolétes")
        ;
    }

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

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


        /** @var NotificationService $notificationService */
        $notificationService = $this->getServicemanager()->get(NotificationService::class);
        try {
            $notificationService->purgeNotificationsObsoletes($io);
            $notificationService->purgeNotificationsPersonsInactive($io);
            $notificationService->purgeNotificationsNoPersons($io);
        } catch (\Exception $e) {
            $io->error($e->getMessage());
            return self::FAILURE;
        }
        return self::SUCCESS;
    }
}
 No newline at end of file
+27 −0
Original line number Diff line number Diff line
@@ -29,6 +29,19 @@ class Activity implements ResourceInterface
{
    use TraitTrackable;

    public static function getStatusInactive() :array {
        return [
            self::STATUS_ABORDED,
            self::STATUS_CLOSED,
            self::STATUS_FENCED,
            self::STATUS_REFUSED,
            self::STATUS_REFUSED_2,
            self::STATUS_REORIENTED,
            self::STATUS_TERMINATED,
            self::STATUS_TRANSFERED,
        ];
    }

    public static function getStatusSelect()
    {
        static $statusSelect;
@@ -1994,6 +2007,18 @@ class Activity implements ResourceInterface
        return $json;
    }

    public function getPersonsDeeper( bool $active = true)
    {
        $affectations = $this->getPersonsDeep();
        /** @var ActivityOrganization $activityOrganization */
        foreach ($this->getOrganizationsDeep() as $activityOrganization) {
            foreach ($activityOrganization->getOrganization()->getPersons() as $person) {
                $affectations[] = $person;
            }
        }
        return $affectations;
    }

    public function getPersonsDeep($ignoreMain = false)
    {
        $persons = [];
@@ -2027,6 +2052,8 @@ class Activity implements ResourceInterface
        return $partners;
    }



    protected function deepParent(Organization $organization, &$out = []): array
    {
        if ($organization->getParent()) {
+41 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
namespace Oscar\Entity;

use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;

class NotificationRepository extends EntityRepository
{
@@ -135,6 +136,46 @@ class NotificationRepository extends EntityRepository
        $this->getEntityManager()->createQuery($dql)->getResult();
    }

    public function getNotificationsObsoletes(array $params)
    {
        $qb = $this->createQueryBuilder("n")
            ->leftJoin(Activity::class, 'a', Join::WITH, "n.objectId = a.id")
            ->where("n.object = :object")
            ->andWhere("a.status IN(:status)")
            ->orderBy('n.dateEffective', 'ASC');

        $parameters = [
            'object' => 'activity',
            'status' => $params['status']
        ];

        $qb->setParameters($parameters);

        return $qb->getQuery()->getResult();
    }

    public function getNotificationsPersonsInactive(string $date)
    {
        $qb = $this->getEntityManager()->getRepository(NotificationPerson::class, 'np')
            ->createQueryBuilder('np')
            ->innerJoin('np.person', 'p')
            ->where('p.ldapFinInscription < :date')
            ->setParameters(
                [
                    'date' => $date,
                ]
            );
        return $qb->getQuery()->execute();
    }

    public function getNotificationsEmpty()
    {
        $qb = $this->createQueryBuilder("n")
            ->where("n.persons IS EMPTY");

        return $qb->getQuery()->getResult();
    }

    protected function getQueryBuilderDeleteBase()
    {
        return $this->getBaseQueryBuilder()
+68 −1
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
            )
            ->innerJoin(NotificationPerson::class, 'n', Join::WITH, $qb->expr()->eq('p.id', 'n.person'))
            ->innerJoin('n.notification', 'nt')
            ->where('n.read IS NULL AND nt.dateEffective <= :now')
            ->where('n.read IS NULL AND nt.dateEffective <= :now AND p.ldapFinInscription < :now')
            ->orderBy('p.lastname', 'ASC')
            ->setParameter('now', date('Y-m-d'))
            ->getQuery()
@@ -672,4 +672,71 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
        ;
        return $qb->getQuery()->getResult();
    }

    public function getPersonsWithPaymentsLate():array
    {
        $sql = <<<SQL
with 
	-- IDS des activités ayant des versement prévisionnel en retard
	activity_ids as (	
		select 
			distinct ap.activity_id as id
			from activitypayment ap 
			join activity a on ap.activity_id = a.id
			where 
				ap.datepredicted < now() and ap.status = 1
				and a.status not in(200,201)
	), 
	-- IDs des rôles ayant le privilège de gérer les versements
	role_payment as (
		select 
			distinct ur.id as id 
			from user_role ur 
			join role_privilege rp on ur.id = rp.role_id 
			join privilege p2 on p2.id = rp.privilege_id
			where p2.code = 'PAYMENT_MANAGE'
	)
SELECT DISTINCT p.*
FROM person p
WHERE 
	-- Le compte de la personne est active
	(p.ldapfininscription is null or p.ldapfininscription <> '' or p.ldapfininscription::date > now()::date )
	
	-- La personne est impliquée dans le versement
	and p.id IN (
    SELECT ap.person_id
    FROM activityperson ap
    WHERE ap.activity_id IN(select id from activity_ids) and ap.roleobj_id IN(select id from role_payment)

    UNION

    SELECT pp.person_id
    FROM projectmember pp
    JOIN activity a ON a.project_id = pp.project_id
    WHERE a.id IN(select id from activity_ids) and pp.roleobj_id IN(select id from role_payment)
    
    UNION

    -- 3️⃣ Person via une organization liée à l’activité
    SELECT po.person_id
    FROM organizationperson po
    JOIN activityorganization ao ON ao.organization_id = po.organization_id
    WHERE ao.activity_id IN(select id from activity_ids) and po.roleobj_id IN(select id from role_payment)

    UNION

    -- 4️⃣ Person via une organization liée au projet de l’activité
    SELECT po.person_id
    FROM organizationperson po
    JOIN projectpartner oproj ON oproj.organization_id = po.organization_id
    JOIN activity a ON a.project_id = oproj.project_id
    WHERE a.id IN(select id from activity_ids) and po.roleobj_id IN(select id from role_payment)
)
	;
SQL;
        return $this->getEntityManager()
            ->getConnection()
            ->executeQuery($sql)
            ->fetchAllAssociative();
    }
}
+37 −0
Original line number Diff line number Diff line
@@ -988,4 +988,41 @@ class NotificationService implements UseServiceContainer
//
//        die("Calcule");
    }

    public function purgeNotificationsObsoletes(\Symfony\Component\Console\Style\SymfonyStyle $io)
    {
        $params = [
            'status' => Activity::getStatusInactive()
        ];
        $notifications = $this->getNotificationRepository()->getNotificationsObsoletes($params);
        $total = count($notifications);
        foreach ($notifications as $notification) {
            $this->getEntityManager()->remove($notification);
        }
        $this->getEntityManager()->flush();
        $this->getLoggerService()->info("$total notification(s) purgées - Activités terminées");
    }

    public function purgeNotificationsPersonsInactive(\Symfony\Component\Console\Style\SymfonyStyle $io)
    {
        $date = new \DateTime('-6 month');
        $notifications = $this->getNotificationRepository()->getNotificationsPersonsInactive($date->format('Y-m-d'));
        $total = count($notifications);
        foreach ($notifications as $notificationPerson) {
            $this->getEntityManager()->remove($notificationPerson);
        }
        $this->getEntityManager()->flush();
        $this->getLoggerService()->info("$total notification(s) purgées - Personnes désactivées depuis plus de 6 mois");
    }

    public function purgeNotificationsNoPersons(\Symfony\Component\Console\Style\SymfonyStyle $io)
    {
        $notifications = $this->getNotificationRepository()->getNotificationsEmpty();
        $total = count($notifications);
        foreach ($notifications as $notification) {
            $this->getEntityManager()->remove($notification);
        }
        $this->getEntityManager()->flush();
        $this->getLoggerService()->info("$total notification(s) purgées - Aucune personnes associées");
    }
}
Loading