Merge branch 'exports/apply-person-modifier-on-course' into '111_exports_suite'

Apply persons filters and aggregators on accompanying course

See merge request Chill-Projet/chill-bundles!466
This commit is contained in:
Julien Fastré 2022-11-14 10:22:48 +00:00
commit ec9555ec84
26 changed files with 646 additions and 666 deletions

View File

@ -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;
@ -246,6 +248,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,

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Postgresql GREATEST function.
*
* Borrowed from https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Postgresql/Greatest.php
* (https://github.com/beberlei/DoctrineExtensions/blob/master/LICENSE) and
* https://gist.github.com/olimsaidov/4bbd530b1b645ce75e1bbb781b5dd91f
*/
class Greatest extends FunctionNode
{
/**
* @var array|Node[]
*/
private array $exprs = [];
public function getSql(SqlWalker $sqlWalker)
{
return 'GREATEST(' . implode(', ', array_map(static function (Node $expr) use ($sqlWalker) {
return $expr->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);
}
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Postgresql LEAST function.
*
* Borrowed from https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Postgresql/Least.php
* (https://github.com/beberlei/DoctrineExtensions/blob/master/LICENSE) and
* https://gist.github.com/olimsaidov/4bbd530b1b645ce75e1bbb781b5dd91f
*/
class Least extends FunctionNode
{
/**
* @var array|Node[]
*/
private array $exprs = [];
public function getSql(SqlWalker $sqlWalker)
{
return 'LEAST(' . implode(', ', array_map(static function (Node $expr) use ($sqlWalker) {
return $expr->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);
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Doctrine\DQL;
use Chill\MainBundle\Entity\Address;
use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* @internal
* @coversNothing
*/
final class GreatestTest extends KernelTestCase
{
private EntityManagerInterface $entityManager;
protected function setUp(): void
{
self::bootKernel();
$this->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']);
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Doctrine\DQL;
use Chill\MainBundle\Entity\Address;
use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* @internal
* @coversNothing
*/
final class LeastTest extends KernelTestCase
{
private EntityManagerInterface $entityManager;
protected function setUp(): void
{
self::bootKernel();
$this->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']);
}
}

View File

@ -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' => [

View File

@ -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';
}
}

View File

@ -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()

View File

@ -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,
];
}
}

View File

@ -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,
];
}
}

View File

@ -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,
];
}
}

View File

@ -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)'

View File

@ -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,
];
}
}

View File

@ -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,
];
}
}

View File

@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Filter\PersonFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement;
use Chill\PersonBundle\Export\Declarations;
use DateTime;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface
{
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$this->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';
}
}

View File

@ -1,87 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Filter\PersonFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement;
use Chill\PersonBundle\Export\Declarations;
use DateTime;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface
{
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$this->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';
}
}

View File

@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Filter\PersonFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement;
use Chill\PersonBundle\Export\Declarations;
use DateTime;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface
{
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$this->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';
}
}

View File

@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Filter\PersonFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\Household\HouseholdComposition;
use Chill\PersonBundle\Entity\Household\HouseholdCompositionType;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class ByHouseholdCompositionFilter implements FilterInterface
{
private HouseholdCompositionTypeRepositoryInterface $householdCompositionTypeRepository;
private RollingDateConverterInterface $rollingDateConverter;
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
HouseholdCompositionTypeRepositoryInterface $householdCompositionTypeRepository,
RollingDateConverterInterface $rollingDateConverter,
TranslatableStringHelperInterface $translatableStringHelper
) {
$this->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';
}
}

View File

@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Filter\PersonFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\PersonBundle\Entity\Household\HouseholdComposition;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class WithoutHouseholdComposition implements FilterInterface
{
private RollingDateConverterInterface $rollingDateConverter;
public function __construct(
RollingDateConverterInterface $rollingDateConverter
) {
$this->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';
}
}

View File

@ -1,90 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Tests\Export\Filter\PersonFilters;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodClosingFilter;
use DateTime;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
/**
* @internal
* @coversNothing
*/
final class AccompanyingPeriodClosingFilterTest extends AbstractFilterTest
{
private AccompanyingPeriodClosingFilter $filter;
protected function setUp(): void
{
self::bootKernel();
try {
$this->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'),
];
}
}

View File

@ -1,90 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Tests\Export\Filter\PersonFilters;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodFilter;
use DateTime;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
/**
* @internal
* @coversNothing
*/
final class AccompanyingPeriodFilterTest extends AbstractFilterTest
{
private AccompanyingPeriodFilter $filter;
protected function setUp(): void
{
self::bootKernel();
try {
$this->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'),
];
}
}

View File

@ -1,90 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Tests\Export\Filter\PersonFilters;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodOpeningFilter;
use DateTime;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
/**
* @internal
* @coversNothing
*/
final class AccompanyingPeriodOpeningFilterTest extends AbstractFilterTest
{
private AccompanyingPeriodOpeningFilter $filter;
protected function setUp(): void
{
self::bootKernel();
try {
$this->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'),
];
}
}

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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