diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index dc50846fb..2a785af42 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -25,10 +25,12 @@ use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; use Chill\MainBundle\Doctrine\DQL\Age; use Chill\MainBundle\Doctrine\DQL\Extract; use Chill\MainBundle\Doctrine\DQL\GetJsonFieldByKey; +use Chill\MainBundle\Doctrine\DQL\Greatest; use Chill\MainBundle\Doctrine\DQL\JsonAggregate; use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength; use Chill\MainBundle\Doctrine\DQL\JsonbExistsInArray; use Chill\MainBundle\Doctrine\DQL\JsonExtract; +use Chill\MainBundle\Doctrine\DQL\Least; use Chill\MainBundle\Doctrine\DQL\OverlapsI; use Chill\MainBundle\Doctrine\DQL\Replace; use Chill\MainBundle\Doctrine\DQL\Similarity; @@ -249,6 +251,8 @@ class ChillMainExtension extends Extension implements 'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class, 'ST_X' => STX::class, 'ST_Y' => STY::class, + 'GREATEST' => Greatest::class, + 'LEAST' => LEAST::class, ], 'datetime_functions' => [ 'EXTRACT' => Extract::class, diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php new file mode 100644 index 000000000..b9ca9c4b6 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php @@ -0,0 +1,57 @@ +dispatch($sqlWalker); + }, $this->exprs)) . ')'; + } + + public function parse(Parser $parser) + { + $this->exprs = []; + + $lexer = $parser->getLexer(); + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $this->exprs[] = $parser->ArithmeticPrimary(); + + while (Lexer::T_COMMA === $lexer->lookahead['type']) { + $parser->match(Lexer::T_COMMA); + $this->exprs[] = $parser->ArithmeticPrimary(); + } + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php new file mode 100644 index 000000000..0c8a1b17d --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php @@ -0,0 +1,57 @@ +dispatch($sqlWalker); + }, $this->exprs)) . ')'; + } + + public function parse(Parser $parser) + { + $this->exprs = []; + + $lexer = $parser->getLexer(); + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $this->exprs[] = $parser->ArithmeticPrimary(); + + while (Lexer::T_COMMA === $lexer->lookahead['type']) { + $parser->match(Lexer::T_COMMA); + $this->exprs[] = $parser->ArithmeticPrimary(); + } + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php new file mode 100644 index 000000000..c11061287 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php @@ -0,0 +1,48 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function testGreatestInDQL() + { + $dql = 'SELECT GREATEST(a.validFrom, a.validTo, :now) AS g FROM ' . Address::class . ' a WHERE a.validTo < :now and a.validFrom < :now'; + + $actual = $this->entityManager + ->createQuery($dql) + ->setParameter('now', $now = new DateTimeImmutable('now'), Types::DATE_IMMUTABLE) + ->setMaxResults(3) + ->getResult(); + + $this->assertIsArray($actual); + $this->assertEquals($now->format('Y-m-d'), $actual[0]['g']); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php new file mode 100644 index 000000000..1e5be8e24 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php @@ -0,0 +1,48 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function testGreatestInDQL() + { + $dql = 'SELECT LEAST(a.validFrom, a.validTo, :now) AS g FROM ' . Address::class . ' a WHERE a.validTo < :now and a.validFrom < :now'; + + $actual = $this->entityManager + ->createQuery($dql) + ->setParameter('now', $now = new DateTimeImmutable('now'), Types::DATE_IMMUTABLE) + ->setMaxResults(3) + ->getResult(); + + $this->assertIsArray($actual); + $this->assertNotEquals($now->format('Y-m-d'), $actual[0]['g']); + } +} diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 932f5b9f9..d60e15e41 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -97,11 +97,11 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $loader->load('services/exports_person.yaml'); if ($container->getParameter('chill_person.accompanying_period') !== 'hidden') { - $loader->load('services/exports_accompanying_period.yaml'); + $loader->load('services/exports_accompanying_course.yaml'); + $loader->load('services/exports_social_actions.yaml'); + $loader->load('services/exports_evaluation.yaml'); } - $loader->load('services/exports_accompanying_course.yaml'); - $loader->load('services/exports_social_actions.yaml'); - $loader->load('services/exports_evaluation.yaml'); + $loader->load('services/exports_household.yaml'); } @@ -944,10 +944,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac /** * Add a widget "add a person" on the homepage, automatically. - * - * @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container */ - protected function prependHomepageWidget(containerBuilder $container) + protected function prependHomepageWidget(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ 'widgets' => [ diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php similarity index 75% rename from src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php rename to src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php index f299762e6..7a1aaaa49 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php @@ -9,20 +9,18 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; +namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\HouseholdComposition; -use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface; use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; class ByHouseholdCompositionAggregator implements AggregatorInterface { @@ -47,30 +45,20 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface { $p = self::PREFIX; - if (!in_array('acppart', $qb->getAllAliases(), true)) { - $qb->leftJoin('acp.participations', 'acppart'); - } - $qb ->leftJoin( - HouseholdMember::class, - "{$p}_hm", - Join::WITH, - $qb->expr()->orX( - $qb->expr()->isNull("{$p}_hm"), - $qb->expr()->andX( - $qb->expr()->lte("{$p}_hm.startDate", ":{$p}_date"), - $qb->expr()->orX( - $qb->expr()->isNull("{$p}_hm.endDate"), - $qb->expr()->gt("{$p}_hm.endDate", ":{$p}_date") - ) - ) - ) + 'person.householdParticipations', + "{$p}_hm" ) ->leftJoin( HouseholdComposition::class, "{$p}_compo", Join::WITH, + $qb->expr()->eq("{$p}_hm.household", "{$p}_compo.household"), + ) + ->andWhere("{$p}_hm.startDate <= :{$p}_date AND ({$p}_hm.endDate IS NULL OR {$p}_hm.endDate > :{$p}_date)") + ->andWhere("{$p}_hm.shareHousehold = 'TRUE'") + ->andWhere( $qb->expr()->orX( $qb->expr()->isNull("{$p}_compo"), $qb->expr()->andX( @@ -89,13 +77,13 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface public function applyOn() { - return Declarations::ACP_TYPE; + return Declarations::PERSON_TYPE; } public function buildForm(FormBuilderInterface $builder) { $builder->add('date_calc', ChillDateType::class, [ - 'label' => 'export.aggregator.course.by_household_composition.Calc date', + 'label' => 'export.aggregator.person.by_household_composition.Calc date', 'input_format' => 'datetime_immutable', 'data' => new DateTimeImmutable('now'), ]); @@ -105,7 +93,7 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface { return function ($value) { if ('_header' === $value) { - return 'export.aggregator.course.by_household_composition.Household composition'; + return 'export.aggregator.person.by_household_composition.Household composition'; } if (null === $value) { @@ -127,6 +115,6 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface public function getTitle() { - return 'export.aggregator.course.by_household_composition.Group course by household composition'; + return 'export.aggregator.person.by_household_composition.Group course by household composition'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php index fbdac5d40..0a42fd928 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php @@ -14,8 +14,11 @@ namespace Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository; +use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; use Chill\PersonBundle\Templating\Entity\SocialActionRender; +use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; use function in_array; @@ -25,12 +28,20 @@ final class ActionTypeAggregator implements AggregatorInterface private SocialActionRepository $socialActionRepository; + private SocialIssueRender $socialIssueRender; + + private SocialIssueRepository $socialIssueRepository; + public function __construct( SocialActionRepository $socialActionRepository, - SocialActionRender $actionRender + SocialActionRender $actionRender, + SocialIssueRender $socialIssueRender, + SocialIssueRepository $socialIssueRepository ) { $this->socialActionRepository = $socialActionRepository; $this->actionRender = $actionRender; + $this->socialIssueRender = $socialIssueRender; + $this->socialIssueRepository = $socialIssueRepository; } public function addRole(): ?string @@ -44,8 +55,15 @@ final class ActionTypeAggregator implements AggregatorInterface $qb->leftJoin('acpw.socialAction', 'acpwsocialaction'); } - $qb->addSelect('acpwsocialaction.id as action_type_aggregator'); - $qb->addGroupBy('action_type_aggregator'); + if (!in_array('acpwsocialissue', $qb->getAllAliases(), true)) { + $qb->leftJoin('acpwsocialaction.issue', 'acpwsocialissue'); + } + + $qb + ->addSelect('acpwsocialissue.id as social_action_type_aggregator') + ->addSelect('acpwsocialaction.id as action_type_aggregator') + ->addGroupBy('action_type_aggregator') + ->addGroupBy('social_action_type_aggregator'); } public function applyOn() @@ -60,24 +78,41 @@ final class ActionTypeAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { - if ('_header' === $value) { - return 'Social Action Type'; - } + switch ($key) { + case 'action_type_aggregator': + return function ($value): string { + if ('_header' === $value) { + return 'Social Action Type'; + } - if (null === $value) { - return ''; - } + if (null === $value || null === $sa = $this->socialActionRepository->find($value)) { + return ''; + } - $sa = $this->socialActionRepository->find($value); + return $this->actionRender->renderString($sa, []); + }; - return $this->actionRender->renderString($sa, []); - }; + case 'social_action_type_aggregator': + return function ($value): string { + if ('_header' === $value) { + return 'Social Issue'; + } + + if (null === $value || null === $si = $this->socialIssueRepository->find($value)) { + return ''; + } + + return $this->socialIssueRender->renderString($si, []); + }; + + default: + throw new LogicException('this key is not supported: ' . $key); + } } public function getQueryKeys($data) { - return ['action_type_aggregator']; + return ['social_action_type_aggregator', 'action_type_aggregator']; } public function getTitle() diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php index d07ee3639..a9f794888 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php @@ -15,7 +15,6 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; @@ -100,11 +99,13 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface $qb ->andWhere('acp.step != :count_acp_step') + ->leftJoin('acp.participations', 'acppart') + ->leftJoin('acppart.person', 'person') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) @@ -125,6 +126,7 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface { return [ Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php index e62752d13..578cc1452 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php @@ -15,25 +15,22 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use LogicException; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; class CountEvaluation implements ExportInterface, GroupedExportInterface { - private EntityRepository $repository; + private EntityManagerInterface $entityManager; public function __construct( EntityManagerInterface $em ) { - $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->entityManager = $em; } public function buildForm(FormBuilderInterface $builder) @@ -96,22 +93,19 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface return $el['center']; }, $acl); - $qb = $this->repository->createQueryBuilder('acp'); - - if (!in_array('acpw', $qb->getAllAliases(), true)) { - $qb->join('acp.works', 'acpw'); - } - - if (!in_array('workeval', $qb->getAllAliases(), true)) { - $qb->join('acpw.accompanyingPeriodWorkEvaluations', 'workeval'); - } + $qb = $this->entityManager->createQueryBuilder(); $qb + ->from(AccompanyingPeriod\AccompanyingPeriodWorkEvaluation::class, 'workeval') + ->join('workeval.accompanyingPeriodWork', 'acpw') + ->join('acpw.accompanyingPeriod', 'acp') + ->join('acp.participations', 'acppart') + ->join('acppart.person', 'person') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) @@ -133,6 +127,7 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface Declarations::EVAL_TYPE, Declarations::SOCIAL_WORK_ACTION_TYPE, Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php index 0c838beff..f1eaeb4cb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php @@ -14,31 +14,42 @@ namespace Chill\PersonBundle\Export\Export; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; -use Chill\PersonBundle\Entity\Household\HouseholdMember; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; +use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\HouseholdVoter; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use LogicException; use Symfony\Component\Form\FormBuilderInterface; class CountHousehold implements ExportInterface, GroupedExportInterface { - private EntityRepository $repository; + private const TR_PREFIX = 'export.export.nb_household_with_course.'; + + private EntityManagerInterface $entityManager; + + private RollingDateConverterInterface $rollingDateConverter; public function __construct( - EntityManagerInterface $em + EntityManagerInterface $em, + RollingDateConverterInterface $rollingDateConverter ) { - $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->entityManager = $em; + $this->rollingDateConverter = $rollingDateConverter; } public function buildForm(FormBuilderInterface $builder) { - // TODO: Implement buildForm() method. + $builder + ->add('calc_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), + 'label' => self::TR_PREFIX . 'Date of calculation of household members', + 'required' => false, + ]); } public function getAllowedFormattersTypes(): array @@ -48,7 +59,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface public function getDescription(): string { - return 'Count household by various parameters.'; + return self::TR_PREFIX . 'Count household with accompanying course by various parameters.'; } public function getGroup(): string @@ -58,21 +69,31 @@ class CountHousehold implements ExportInterface, GroupedExportInterface public function getLabels($key, array $values, $data) { - if ('export_result' !== $key) { - throw new LogicException("the key {$key} is not used by this export"); - } + return static function ($value) use ($key) { + if ('_header' === $value) { + switch ($key) { + case 'household_export_result': + return self::TR_PREFIX . 'Count households'; - $labels = array_combine($values, $values); - $labels['_header'] = $this->getTitle(); + case 'acp_export_result': + return self::TR_PREFIX . 'Count accompanying periods'; - return static function ($value) use ($labels) { - return $labels[$value]; + default: + throw new LogicException('Key not supported: ' . $key); + } + } + + if (null === $value) { + return ''; + } + + return $value; }; } public function getQueryKeys($data): array { - return ['export_result']; + return ['household_export_result', 'acp_export_result']; } public function getResult($query, $data) @@ -82,7 +103,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface public function getTitle(): string { - return 'Count households'; + return self::TR_PREFIX . 'Count households with accompanying course'; } public function getType(): string @@ -96,25 +117,29 @@ class CountHousehold implements ExportInterface, GroupedExportInterface return $el['center']; }, $acl); - $qb = $this->repository - ->createQueryBuilder('acp') - ->join('acp.participations', 'acppart') - // little optimization: we remove joins and make a direct join between participations and household members - ->join(HouseholdMember::class, 'member', Query\Expr\Join::WITH, 'IDENTITY(acppart.person) = IDENTITY(member.person)') - ->join('member.household', 'household'); + $qb = $this->entityManager->createQueryBuilder(); $qb + ->from(Household::class, 'household') + ->join('household.members', 'hmember') + ->join('hmember.person', 'person') + ->join('person.accompanyingPeriodParticipations', 'acppart') + ->join('acppart.accompanyingPeriod', 'acp') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) - ->setParameter('authorized_centers', $centers); + ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') + ->setParameter('authorized_centers', $centers) + ->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date'])); - $qb->select('COUNT(DISTINCT household.id) AS export_result'); + $qb + ->select('COUNT(DISTINCT household.id) AS household_export_result') + ->addSelect('COUNT(DISTINCT acp.id) AS acp_export_result'); return $qb; } @@ -129,6 +154,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface return [ Declarations::HOUSEHOLD_TYPE, Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index 98708149a..07a307563 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -100,7 +100,7 @@ class CountPerson implements ExportInterface, GroupedExportInterface $qb = $this->personRepository->createQueryBuilder('person'); - $qb->select('COUNT(person.id) AS export_result') + $qb->select('COUNT(DISTINCT person.id) AS export_result') ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php b/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php index 9333312fd..0aaf526cc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php @@ -15,12 +15,10 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use LogicException; @@ -28,12 +26,12 @@ use Symfony\Component\Form\FormBuilderInterface; class CountSocialWorkActions implements ExportInterface, GroupedExportInterface { - protected EntityRepository $repository; + protected EntityManagerInterface $em; public function __construct( EntityManagerInterface $em ) { - $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->em = $em; } public function buildForm(FormBuilderInterface $builder): void @@ -96,15 +94,18 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface return $el['center']; }, $acl); - $qb = $this->repository->createQueryBuilder('acp') - ->join('acp.works', 'acpw'); + $qb = $this->em->createQueryBuilder(); $qb + ->from(AccompanyingPeriod\AccompanyingPeriodWork::class, 'acpw') + ->join('acpw.accompanyingPeriod', 'acp') + ->join('acp.participations', 'acppart') + ->join('acppart.person', 'person') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) @@ -125,6 +126,7 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface return [ Declarations::SOCIAL_WORK_ACTION_TYPE, Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php index a0e68beea..c124f0227 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php @@ -16,7 +16,6 @@ use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; @@ -53,7 +52,7 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn public function getDescription(): string { - return 'Create an average of accompanying courses duration according to various filters'; + return 'Create an average of accompanying courses duration of each person participation to accompanying course, according to filters on persons, accompanying course'; } public function getGroup(): string @@ -63,21 +62,37 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn public function getLabels($key, array $values, $data) { - if ('export_result' !== $key) { - throw new LogicException("the key {$key} is not used by this export"); - } + return static function ($value) use ($key) { + if ('_header' === $value) { + switch ($key) { + case 'avg_export_result': + return 'export.export.acp_stats.avg_duration'; - $labels = array_combine($values, $values); - $labels['_header'] = $this->getTitle(); + case 'count_acppart_export_result': + return 'export.export.acp_stats.count_participations'; - return static function ($value) use ($labels) { - return $labels[$value]; + case 'count_acp_export_result': + return 'export.export.acp_stats.count_acps'; + + case 'count_pers_export_result': + return 'export.export.acp_stats.count_persons'; + + default: + throw new LogicException('key not supported: ' . $key); + } + } + + if (null === $value) { + return ''; + } + + return $value; }; } public function getQueryKeys($data): array { - return ['export_result']; + return ['avg_export_result', 'count_acp_export_result', 'count_acppart_export_result', 'count_pers_export_result']; } public function getResult($query, $data) @@ -87,7 +102,7 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn public function getTitle(): string { - return 'Accompanying courses duration'; + return 'Accompanying courses participation duration and number of participations'; } public function getType(): string @@ -104,22 +119,28 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn $qb = $this->repository->createQueryBuilder('acp'); $qb + ->select('AVG( + LEAST(acppart.endDate, COALESCE(acp.closingDate, :force_closingDate)) + - GREATEST(acppart.startDate, COALESCE(acp.openingDate, :force_closingDate)) + ) AS avg_export_result') + ->addSelect('COUNT(DISTINCT acppart.id) AS count_acppart_export_result') + ->addSelect('COUNT(DISTINCT person.id) AS count_pers_export_result') + ->addSelect('COUNT(DISTINCT acp.id) AS count_acp_export_result') + ->setParameter('force_closingDate', $data['closingdate']) + ->leftJoin('acp.participations', 'acppart') + ->leftJoin('acppart.person', 'person') + ->andWhere('acp.step != :count_acp_step') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) + ->setParameter('count_acp_step', AccompanyingPeriod::STEP_DRAFT) ->setParameter('authorized_centers', $centers); - $qb - ->select('AVG( - COALESCE(acp.closingDate, :force_closingDate) - acp.openingDate - ) AS export_result') - ->setParameter('force_closingDate', $data['closingdate']); - return $qb; } @@ -132,6 +153,7 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn { return [ Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php deleted file mode 100644 index 8c6c132b7..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php +++ /dev/null @@ -1,78 +0,0 @@ -addJoinAccompanyingPeriod($qb); - - $clause = $qb->expr()->andX( - $qb->expr()->lte('acp.closingDate', ':date_to'), - $qb->expr()->gte('acp.closingDate', ':date_from') - ); - - $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); - } - - public function applyOn(): string - { - return Declarations::PERSON_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('date_from', ChillDateType::class, [ - 'label' => 'Having an accompanying period closed after this date', - 'data' => new DateTime('-1 month'), - ]); - - $builder->add('date_to', ChillDateType::class, [ - 'label' => 'Having an accompanying period closed before this date', - 'data' => new DateTime(), - ]); - } - - public function describeAction($data, $format = 'string') - { - return [ - 'Filtered by accompanying period: persons having an accompanying period' - . ' closed between the %date_from% and %date_to%', - [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - ], - ]; - } - - public function getTitle(): string - { - return 'Filter by accompanying period: closed between two dates'; - } -} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php deleted file mode 100644 index 05cf7fd1e..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php +++ /dev/null @@ -1,87 +0,0 @@ -addJoinAccompanyingPeriod($qb); - - $clause = $qb->expr()->andX(); - - $clause->add( - $qb->expr()->lte('acp.openingDate', ':date_to') - ); - $clause->add( - $qb->expr()->orX( - $qb->expr()->gte('acp.closingDate', ':date_from'), - $qb->expr()->isNull('acp.closingDate') - ) - ); - - $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); - } - - public function applyOn(): string - { - return Declarations::PERSON_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('date_from', ChillDateType::class, [ - 'label' => 'Having an accompanying period opened after this date', - 'data' => new DateTime('-1 month'), - ]); - - $builder->add('date_to', ChillDateType::class, [ - 'label' => 'Having an accompanying period ending before this date, or ' - . 'still opened at this date', - 'data' => new DateTime(), - ]); - } - - public function describeAction($data, $format = 'string') - { - return [ - 'Filtered by accompanying period: persons having an accompanying period' - . ' opened after the %date_from% and closed before the %date_to% (or still opened ' - . 'at the %date_to%)', - [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - ], - ]; - } - - public function getTitle(): string - { - return 'Filter by accompanying period: active period'; - } -} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php deleted file mode 100644 index b6d895233..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php +++ /dev/null @@ -1,78 +0,0 @@ -addJoinAccompanyingPeriod($qb); - - $clause = $qb->expr()->andX( - $qb->expr()->lte('acp.openingDate', ':date_to'), - $qb->expr()->gte('acp.openingDate', ':date_from') - ); - - $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); - } - - public function applyOn(): string - { - return Declarations::PERSON_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('date_from', ChillDateType::class, [ - 'label' => 'Having an accompanying period opened after this date', - 'data' => new DateTime('-1 month'), - ]); - - $builder->add('date_to', ChillDateType::class, [ - 'label' => 'Having an accompanying period opened before this date', - 'data' => new DateTime(), - ]); - } - - public function describeAction($data, $format = 'string') - { - return [ - 'Filtered by accompanying period: persons having an accompanying period' - . ' opened between the %date_from% and %date_to%', - [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - ], - ]; - } - - public function getTitle(): string - { - return 'Filter by accompanying period: starting between two dates'; - } -} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php new file mode 100644 index 000000000..9b59549f1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php @@ -0,0 +1,110 @@ +householdCompositionTypeRepository = $householdCompositionTypeRepository; + $this->rollingDateConverter = $rollingDateConverter; + $this->translatableStringHelper = $translatableStringHelper; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = 'person_by_household_compo_filter'; + + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM ' . HouseholdMember::class . " {$p}_hm " . + 'JOIN ' . HouseholdComposition::class . " {$p}_compo WITH {$p}_hm.household = {$p}_compo.household " . + "WHERE {$p}_hm.person = person AND {$p}_hm.shareHousehold = 'TRUE' " . + "AND ({$p}_hm.startDate <= :{$p}_date AND ({$p}_hm.endDate IS NULL OR {$p}_hm.endDate > :{$p}_date)) " . + "AND ({$p}_compo.startDate <= :{$p}_date AND ({$p}_compo.endDate IS NULL OR {$p}_compo.endDate > :{$p}_date)) " . + "AND {$p}_compo.householdCompositionType IN (:{$p}_accepted)" + ) + ) + ->setParameter("{$p}_accepted", $data['compositions']) + ->setParameter("{$p}_date", $this->rollingDateConverter->convert($data['calc_date']), Types::DATE_IMMUTABLE); + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('compositions', EntityType::class, [ + 'class' => HouseholdCompositionType::class, + 'choices' => $this->householdCompositionTypeRepository->findAllActive(), + 'choice_label' => fn (HouseholdCompositionType $compositionType) => $this->translatableStringHelper->localize($compositionType->getLabel()), + 'label' => 'export.filter.person.by_composition.Accepted compositions', + 'multiple' => true, + 'expanded' => true, + ]) + ->add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.filter.person.by_composition.Date calc', + 'data' => new RollingDate(RollingDate::T_TODAY), + ]); + } + + public function describeAction($data, $format = 'string') + { + $compos = array_map( + fn (HouseholdCompositionType $compositionType) => $this->translatableStringHelper->localize($compositionType->getLabel()), + $data['compositions']->toArray() + ); + + return ['export.filter.person.by_composition.Filtered by composition at %date%: only %compositions%', [ + '%compositions%' => implode(', ', $compos), + '%date%' => $this->rollingDateConverter->convert($data['calc_date'])->format('d-m-Y'), + ]]; + } + + public function getTitle() + { + return 'export.filter.person.by_composition.Filter by household composition'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php new file mode 100644 index 000000000..c4644fc11 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php @@ -0,0 +1,84 @@ +rollingDateConverter = $rollingDateConverter; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = 'person_by_household_no_compo_filter'; + + $qb + ->andWhere( + $qb->expr()->not( + $qb->expr()->exists( + 'SELECT 1 FROM ' . HouseholdMember::class . " {$p}_hm " . + 'JOIN ' . HouseholdComposition::class . " {$p}_compo WITH {$p}_hm.household = {$p}_compo.household " . + "WHERE {$p}_hm.person = person AND {$p}_hm.shareHousehold = 'TRUE' " . + "AND ({$p}_hm.startDate <= :{$p}_date AND ({$p}_hm.endDate IS NULL OR {$p}_hm.endDate > :{$p}_date)) " . + "AND ({$p}_compo.startDate <= :{$p}_date AND ({$p}_compo.endDate IS NULL OR {$p}_compo.endDate > :{$p}_date)) " + ) + ) + ) + ->setParameter("{$p}_date", $this->rollingDateConverter->convert($data['calc_date']), Types::DATE_IMMUTABLE); + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.filter.person.by_no_composition.Date calc', + 'data' => new RollingDate(RollingDate::T_TODAY), + ]); + } + + public function describeAction($data, $format = 'string') + { + return ['export.filter.person.by_no_composition.Persons filtered by no composition at %date%', [ + '%date%' => $this->rollingDateConverter->convert($data['calc_date'])->format('d-m-Y'), + ]]; + } + + public function getTitle() + { + return 'export.filter.person.by_no_composition.Filter persons without household composition'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php deleted file mode 100644 index 76c3b40b5..000000000 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php +++ /dev/null @@ -1,90 +0,0 @@ -filter = self::$container->get('chill.person.export.filter_accompanying_period_closing'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped('The current configuration does not use accompanying_periods'); - } - } - - public function getFilter() - { - return $this->filter; - } - - public function getFormData(): array - { - return [ - [ - 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), - ], - ]; - } - - public function getQueryBuilders(): array - { - if (null === self::$kernel) { - self::bootKernel(); - } - - $em = self::$container - ->get('doctrine.orm.entity_manager'); - - return [ - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person'), - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.accompanyingPeriods', 'accompanying_period') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('activity.date AS date') - ->select('activity.attendee as attendee') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center'), - ]; - } -} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php deleted file mode 100644 index 582d090e8..000000000 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php +++ /dev/null @@ -1,90 +0,0 @@ -filter = self::$container->get('chill.person.export.filter_accompanying_period'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped('The current configuration does not use accompanying_periods'); - } - } - - public function getFilter() - { - return $this->filter; - } - - public function getFormData() - { - return [ - [ - 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), - ], - ]; - } - - public function getQueryBuilders() - { - if (null === self::$kernel) { - self::bootKernel(); - } - - $em = self::$container - ->get('doctrine.orm.entity_manager'); - - return [ - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person'), - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.accompanyingPeriods', 'accompanying_period') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('activity.date AS date') - ->select('activity.attendee as attendee') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center'), - ]; - } -} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php deleted file mode 100644 index 9262d0757..000000000 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php +++ /dev/null @@ -1,90 +0,0 @@ -filter = self::$container->get('chill.person.export.filter_accompanying_period_opening'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped('The current configuration does not use accompanying_periods'); - } - } - - public function getFilter() - { - return $this->filter; - } - - public function getFormData() - { - return [ - [ - 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), - ], - ]; - } - - public function getQueryBuilders() - { - if (null === self::$kernel) { - self::bootKernel(); - } - - $em = self::$container - ->get('doctrine.orm.entity_manager'); - - return [ - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person'), - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.accompanyingPeriods', 'accompanying_period') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('activity.date AS date') - ->select('activity.attendee as attendee') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center'), - ]; - } -} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml index 71eecf4ff..6d0e160fd 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml @@ -214,10 +214,6 @@ services: tags: - { name: chill.export_aggregator, alias: accompanyingcourse_ref_scope_aggregator } - Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ByHouseholdCompositionAggregator: - tags: - - { name: chill.export_aggregator, alias: accompanyingcourse_by_household_compo_aggregator } - Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ByActionNumberAggregator: tags: - { name: chill.export_aggregator, alias: accompanyingcourse_by_action_number_aggregator } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml deleted file mode 100644 index 42ddd2181..000000000 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml +++ /dev/null @@ -1,16 +0,0 @@ -services: - - chill.person.export.filter_accompanying_period: - class: Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodFilter - tags: - - { name: chill.export_filter, alias: person_accc_period_filter } - - chill.person.export.filter_accompanying_period_opening: - class: Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodOpeningFilter - tags: - - { name: chill.export_filter, alias: person_acc_pe_op_filter } - - chill.person.export.filter_accompanying_period_closing: - class: Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodClosingFilter - tags: - - { name: chill.export_filter, alias: person_acc_pe_cl_filter } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml index b2b182c5b..a8563e5ca 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml @@ -1,4 +1,7 @@ services: + _defaults: + autoconfigure: true + autowire: true ## Indicators chill.person.export.count_person: @@ -107,6 +110,14 @@ services: tags: - { name: chill.export_filter, alias: person_geog_filter } + Chill\PersonBundle\Export\Filter\PersonFilters\ByHouseholdCompositionFilter: + tags: + - { name: chill.export_filter, alias: person_by_household_composition_filter } + + Chill\PersonBundle\Export\Filter\PersonFilters\WithoutHouseholdComposition: + tags: + - { name: chill.export_filter, alias: person_without_household_composition_filter } + ## Aggregators chill.person.export.aggregator_nationality: class: Chill\PersonBundle\Export\Aggregator\PersonAggregators\NationalityAggregator @@ -156,3 +167,7 @@ services: tags: - { name: chill.export_aggregator, alias: person_geog_aggregator } + Chill\PersonBundle\Export\Aggregator\PersonAggregators\ByHouseholdCompositionAggregator: + tags: + - { name: chill.export_aggregator, alias: person_household_compo_aggregator } + diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index bdedea895..0b53bd7a5 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -359,8 +359,8 @@ Count people participating in an accompanying course by various parameters.: Com Exports of accompanying courses: Exports des parcours d'accompagnement Count accompanying courses: Nombre de parcours Count accompanying courses by various parameters: Compte le nombre de parcours en fonction de différents filtres. -Accompanying courses duration: Durée moyenne des parcours -Create an average of accompanying courses duration according to various filters: Moyenne de la durée des parcours en jours, selon différents filtres. +Accompanying courses participation duration and number of participations: Durée moyenne et nombre des participation des usagers aux parcours +Create an average of accompanying courses duration of each person participation to accompanying course, according to filters on persons, accompanying course: Crée un rapport qui comptabilise la moyenne de la durée de participation de chaque usager concerné aux parcours, avec différents filtres, notamment sur les usagers concernés. Closingdate to apply: Date de fin à prendre en compte lorsque le parcours n'est pas clotûré Exports of social work actions: Exports des actions d'accompagnement @@ -373,8 +373,6 @@ Count evaluations: Nombre d'évaluations Count evaluation by various parameters.: Compte le nombre d'évaluations selon différents filtres. Exports of households: Exports des ménages -Count households: Nombre de ménages -Count household by various parameters.: Compte le nombre de ménages impliqués dans un parcours selon différents filtres. ## persons filters Filter by person gender: Filtrer les personnes par genre @@ -989,7 +987,24 @@ notification: Notify any: Notifier d'autres utilisateurs export: + export: + acp_stats: + avg_duration: Moyenne de la durée de participation de chaque usager concerné + count_participations: Nombre de participations distinctes + count_persons: Nombre d'usagers concernés distincts + count_acps: Nombre de parcours distincts + nb_household_with_course: + Count households with accompanying course: Nombre de ménages impliqués dans un parcours + Count households: Nombre de ménages + Count accompanying periods: Nombre de parcours + Count household with accompanying course by various parameters.: Compte le nombre de ménages impliqués dans un parcours selon différents filtres. + Date of calculation of household members: Date à laquelle les membres du ménages sont comptabilisés aggregator: + person: + by_household_composition: + Household composition: Composition du ménage + Group course by household composition: Grouper les personnes par composition familiale + Calc date: Date de calcul de la composition du ménage course: by_referrer: Computation date for referrer: Date à laquelle le référent était actif @@ -1002,10 +1017,6 @@ export: week: Durée du parcours en semaines month: Durée du parcours en mois Precision: Unité de la durée - by_household_composition: - Household composition: Composition du ménage - Group course by household composition: Grouper les parcours par composition familiale des ménages des usagers concernés - Calc date: Date de calcul de la composition du ménage by_number_of_action: Number of actions: Nombre d'actions by_creator_job: @@ -1032,6 +1043,17 @@ export: Max date: Date d'échéance filter: + person: + by_composition: + Filter by household composition: Filtrer les personnes par composition du ménage + Accepted compositions: Composition de ménages + Date calc: Date de calcul + 'Filtered by composition at %date%: only %compositions%': 'Filtré par composition du ménage, le %date%, seulement %compositions%' + by_no_composition: + Filter persons without household composition: Filtrer les personnes sans composition de ménage (ni ménage) + Persons filtered by no composition at %date%: Uniquement les personnes sans composition de ménage à la date du %date% + Date calc: Date de calcul + course: by_user_scope: Computation date for referrer: Date à laquelle le référent était actif