Compare commits

...

70 Commits

Author SHA1 Message Date
26a5de9958 Merge branch 'issue178_169_export_calendars' of gitlab.com:Chill-Projet/chill-bundles into issue178_169_export_calendars 2023-11-16 12:03:43 +01:00
4e35bcbd93 Format yaml file back to they way it was before 2023-11-16 12:03:35 +01:00
7587472785 fix export.yaml file: remove quotes 2023-11-16 12:03:35 +01:00
9ba33f3df4 style fixes for tests 2023-11-16 12:03:35 +01:00
e0de10b7a8 Add tests for new exports calendar 2023-11-16 12:03:35 +01:00
33235d3541 php cs fixes 2023-11-16 12:03:35 +01:00
817ca7e148 add missing variables to two exports 2023-11-16 12:03:35 +01:00
382f275719 add translations 2023-11-16 12:03:35 +01:00
f78c1c0512 adjust logic for calendar exports linked to person 2023-11-16 12:03:35 +01:00
c3ced7fb6e add center filter to calendar exports linked to acp 2023-11-16 12:03:35 +01:00
96a9be39c3 reorganize exports calendar/ refactor config yaml 2023-11-16 12:03:35 +01:00
792ad394c8 Format yaml file back to they way it was before 2023-11-16 11:14:38 +01:00
ff344dbb0c Release 2.12.1 2023-11-16 11:07:34 +01:00
8719b4dedd Merge branch '208-export-fix-loading-by-type-goal-result' into 'master'
Resolve "Export: le chargement de l'app vue de "filtrer les actions par type, objectif et résultat" ne se charge pas sur certains exports"

Closes #208

See merge request Chill-Projet/chill-bundles!615
2023-11-16 10:05:56 +00:00
d8fa743bc9 Export: fix loading of form for "filter action by type, goal and result" 2023-11-16 10:57:59 +01:00
eaa40d6725 DX: remove some unnecessary console.log 2023-11-16 10:57:32 +01:00
a7141ef771 fix export.yaml file: remove quotes 2023-11-16 10:43:47 +01:00
bc638e5eb9 style fixes for tests 2023-11-15 16:38:57 +01:00
b0171e3093 Add tests for new exports calendar 2023-11-15 16:34:08 +01:00
b317daf779 php cs fixes 2023-11-15 16:20:10 +01:00
27bf2893d0 add missing variables to two exports 2023-11-15 16:19:43 +01:00
e2a12968ce add translations 2023-11-15 16:15:24 +01:00
fe9ce1a356 adjust logic for calendar exports linked to person 2023-11-15 15:58:41 +01:00
9c04212c45 add center filter to calendar exports linked to acp 2023-11-15 15:40:36 +01:00
85504d72c2 reorganize exports calendar/ refactor config yaml 2023-11-15 15:31:18 +01:00
1f47f157ea Release v2.12.0 2023-11-15 14:03:46 +01:00
5ab0d3f8da add units on the headers for avg duration of accompanying period work 2023-11-15 13:57:48 +01:00
98fd5cae78 Merge branch '204-export-action-creator' into 'master'
[export] add filters/aggregators for creator works action

Closes #204

See merge request Chill-Projet/chill-bundles!610
2023-11-15 12:49:08 +00:00
2bb29242e4 Merge branch '206-add-exports' into 'master'
"Ajouter un export "usagers concernées par un échange" et "usagers concernés par une action""

Closes #203 and #206

See merge request Chill-Projet/chill-bundles!613
2023-11-15 12:45:29 +00:00
e6cab938c8 DX: increase max connection in postgres service 2023-11-15 13:41:35 +01:00
f5f4d8fcdd remove blank line in changie 2023-11-15 13:30:48 +01:00
e9df26c2f7 Export: add clauses on the social work start date and end date within the filter "Filter accompanying period by accompanying period work"' 2023-11-15 13:25:08 +01:00
af6bee2497 Export: add an export which count persons on activity 2023-11-15 13:25:08 +01:00
af585bada3 Export: add a export which count persons on accompanying period work 2023-11-15 13:24:59 +01:00
f9763b866d add 6 new tests for filters/aggrs 2023-11-15 13:00:45 +01:00
7f18a2fb7d [export] better translation since filters are sorted 2023-11-15 13:00:45 +01:00
3cdad6caff Revert "test cs-fixer"
This reverts commit 9aa1d22d69e0f67333a8c39574fa2efed71c2bc8.
2023-11-15 13:00:45 +01:00
200ab836c7 test cs-fixer 2023-11-15 13:00:45 +01:00
3e39c0ced7 rector and cs-fixer 2023-11-15 13:00:45 +01:00
83c3621c26 declare service 2023-11-15 13:00:45 +01:00
b790e2fcf1 complete aggregators 2023-11-15 13:00:45 +01:00
fde6000d0b filters alterQuery 2023-11-15 13:00:45 +01:00
3892d1e877 remove date field 2023-11-15 13:00:45 +01:00
6944773868 create 6 new filters/aggr files 2023-11-15 13:00:45 +01:00
d5bc9d10d5 Merge branch 'issue202_export_duration_actions' into 'master'
Export: create an export which add the average  duration of accompanying period work

Closes #202

See merge request Chill-Projet/chill-bundles!611
2023-11-15 11:42:35 +00:00
3743b336a6 Export: create an export which add the average duration of accompanying period work 2023-11-15 11:42:34 +00:00
3332413fe0 Merge branch '199-missing-exports' into 'master'
Add missing filters and grouping

Closes #189, #200, and #199

See merge request Chill-Projet/chill-bundles!609
2023-11-14 20:24:21 +00:00
86e659edd4 DX: replace some string by constants 2023-11-14 21:17:09 +01:00
2e60ba3137 Export: fix infinite loop in HouseholdVoter 2023-11-14 21:17:08 +01:00
1663c6f7c7 DX: rename CountHousehold => CountHouseholdInPeriod.php + add test 2023-11-14 21:17:08 +01:00
d01b6db5dc DX: remove unused property 2023-11-14 21:17:08 +01:00
847c8238e8 Export: fix typo in filter "filter accompanying period work on end date 2023-11-14 21:17:08 +01:00
2cc5fa06ae Export: split export about person on accompanying period work: one with the
people associated with the work, another one with the people associated with the
  accompanying period
2023-11-14 21:17:07 +01:00
0d741ab886 Export: add grouping "group peoples by postal code" 2023-11-14 21:17:07 +01:00
9cb794fef2 Merge branch 'documentation-configure-absence-sync' into 'master'
Update the description and screenshots for the configuration of calendar

See merge request Chill-Projet/chill-bundles!608
2023-11-14 19:41:04 +00:00
fd03855ee6 Merge branch '205-fix-acpwork-referrers-as-a-list' into 'master'
Fix normalization of accompanying period work

Closes #205

See merge request Chill-Projet/chill-bundles!612
2023-11-14 19:40:42 +00:00
ac9897d9e7 DX: add a test to ensure that accompanyingPeriodWork::getReferrers is a list 2023-11-14 20:33:18 +01:00
88469dbe8e Fix serialization of accompangying period work referrers 2023-11-14 18:34:28 +01:00
cbc83c0e63 Export: add grouping "group activity by person" (activites saved in person context) 2023-11-13 15:29:01 +01:00
27012d842d Export: add an ActivityPresenceFilter 2023-11-13 15:29:01 +01:00
4112e59af4 Export: add an ActivityPresenceAggregator 2023-11-09 17:35:34 +01:00
1b0a30baf8 Merge branch '188-fix-ci' into 'master'
debug ci

Closes #188

See merge request Chill-Projet/chill-bundles!606
2023-11-09 15:20:55 +00:00
9673b369ef DX: restore the requirements of phpunit's tests
The problem with timezone is now fixed
2023-11-09 16:13:58 +01:00
43966c4d5a remove the change of timezone in test's setUp 2023-11-09 16:01:34 +01:00
c9f438319c update the description and screenshots for the configuration of calendar
and absence synchronization
2023-11-08 10:21:03 +01:00
58b45c6f1b Prepare for v2.11.0 2023-11-07 16:18:33 +01:00
f756c0d71e Merge branch '185-fix-inconsistencies-person-geog-unit-aggregator' into 'master'
Fix geographical unit stat aggregator by course: show also the course if they...

Closes #194 and #185

See merge request Chill-Projet/chill-bundles!607
2023-11-07 15:15:12 +00:00
bb1602934c Fix "group activity by creator job" aggregator 2023-11-07 16:07:24 +01:00
83fe3ec3fc Export: add a "filter activity by creator job" filter 2023-11-07 16:06:22 +01:00
abebb79e8b Fix geographical unit stat aggregator by course: show also the course if they are not located within a location 2023-11-07 14:41:56 +01:00
84 changed files with 4450 additions and 291 deletions

6
.changes/v2.11.0.md Normal file
View File

@@ -0,0 +1,6 @@
## v2.11.0 - 2023-11-07
### Feature
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
### Fixed
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
* Fix "group activity by creator job" aggregator

26
.changes/v2.12.0.md Normal file
View File

@@ -0,0 +1,26 @@
## v2.12.0 - 2023-11-15
### Feature
* ([#199](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/199)) Export: add an aggregator "group activities by presence"
* ([#199](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/199)) Export: add a filter "filter activity by activity presence"
* ([#199](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/199)) Export: add an aggregator "group activities by person" (only for the activities saved in a person context)
* ([#199](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/199)) Export: add a new aggregator "group peoples by postal code"
* ([#200](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/200)) Export: split export about person on accompanying period work: one with the people associated with the work, another one with the people associated with the accompanying period
* ([#204](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/204)) Add 3 new filters and 3 new aggregators for work action creator (with jobs and scopes)
* ([#202](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/202)) Create export for the average duration of social work actions
* ([#206](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/206)) Export: add a export which count persons on accompanying period work
* ([#206](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/206)) Export: add an export which count persons on activity
* ([#203](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/203)) Export: add clauses on the social work start date and end date within the filter "Filter accompanying period by accompanying period work"
### Fixed
* Export: fix typo in filter "filter accompanying period work on end date"
* ([#189](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/189)) Export: Fix failure in export linked to household
* ([#205](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/205)) Fix loading of accompanying period work referrers
### Traduction francophone des principaux changements
* export: ajout d'un regroupement "grouper les échanges par présence de l'usager";
* export: ajout d'un filtre "filtre les échanges par présence de l'usager";
* export: ajout d'un regroupement "regrouper les échanges par personne" (seulement pour les échanges enregistrés dans le contexte de l'usager);
* export: ajout d'un regroupement "grouper les usagers par codes postaux"
* export: séparation des exports sur les actions: dans l'un, les filtres des usagers portent sur les usagers concernés par l'action, dans l'autre, les filtres portent sur les usagers concernés par le parcours de l'action;
* export: ajout de 3 nouveaux filtres et regroupements sur le créateur de l'action, son métier et son service;
* export: correction de l'export sur les ménages liés aux parcours;
* correction du chargement des actions d'accompagnement

3
.changes/v2.12.1.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.12.1 - 2023-11-16
### Fixed
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"

View File

@@ -11,6 +11,10 @@ cache:
services:
- name: postgis/postgis:14-3.3-alpine
alias: db
command:
- postgres
- "-c"
- max_connections=1000
- name: redis
alias: redis
@@ -108,8 +112,6 @@ rector_tests:
# - tests/app/vendor/
unit_tests:
# temporarily allow failure due to problem with timezone
allow_failure: true
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
script:

View File

@@ -6,6 +6,13 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.11.0 - 2023-11-07
### Feature
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
### Fixed
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
* Fix "group activity by creator job" aggregator
## v2.10.6 - 2023-11-07
### Fixed
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement

View File

@@ -1,13 +1,15 @@
Configure Chill for calendar sync and SSO with Microsoft Graph (Outlook)
========================================================================
Configure Chill for calendar and absence synchronisation and SSO with Microsoft Graph (Outlook)
===============================================================================================
Chill offers the possibility to:
* authenticate users using Microsoft Graph, with relatively small adaptations;
* synchronize calendar in both ways (`see the user manual for a large description of the feature <https://gitea.champs-libres.be/Chill-project/manuals>`_).
Both can be configured separately (synchronising calendars without SSO, or SSO without calendar). When calendar sync is configured without SSL, the user's email address is the key to associate Chill's users with Microsoft's ones.
Both can be configured separately (synchronising calendars without SSO, or SSO without calendar).
Please note that the user's email address is the key to associate Chill's users with Microsoft's ones.
Configure SSO
-------------
@@ -46,7 +48,7 @@ Do not forget to provider user's accesses to your app, using the "Utilisateurs e
You must know have gathered all the required variables for SSO:
.. code-block::
.. code-block::
SAML_BASE_URL=https://test.chill.be # must be
SAML_ENTITY_ID=https://test.chill.be # must match the one entered
@@ -186,20 +188,27 @@ Configure chill app
Configure sync
--------------
Configure sync and calendar access
----------------------------------
The sync processe might be configured in the same app, or into a different app.
The purpose of this configuration is the following:
The synchronization processes use Oauth2.0 for authentication and authorization.
- let user read their calendar and shared calendar within Chill (with the same permissions as the one configured in Outlook / Azure);
- allow chill instance to write appointment ("Rendez-vous") into their calendar, and invite other users to their appointment;
- allow chill instance to be notified if an appoint is added or removed by the user within another interface than Chill: if the appointment match another one created in the Chill interface, the date and time are updated in Chill;
- allow chill instance to read the absence of the user and, if set, mark the user as absent in Chill;
The sync processe might be configured in the same app, or into a different app on the Azure side.
The synchronization processes use Oauth 2.0 / OpenID Connect for authentication and authorization.
.. note::
Two flows are in use:
* we authenticate "on behalf of a user", to allow users to see their own calendar or other user's calendar into the web interface.
* we authenticate "on behalf of a user", to allow users to see their own calendar or other user's calendar into the web interface.
Typically, when the page is loaded, Chill first check that an authorization token exists. If not, the user is redirected to Microsoft Azure for authentification and a new token is grabbed (most of the times, this is transparent for users).
Typically, when the page is loaded, Chill first check that an authorization token exists. If not, the user is redirected to Microsoft Azure for authentification and a new token is grabbed (most of the times, this is transparent for users).
* Chill also acts "as a machine", to synchronize calendars with a daemon background.
@@ -229,8 +238,9 @@ Some explanation:
The sync daemon must have write access:
* the daemon must be allowed to read all users and their profile, to establish a link between them and the Chill's users: (:code:`Users.Read.All`);
* it must also be allowed to read and write into the calendars (:code:`Calendars.ReadWrite.All`)
* for sending invitation to other users, the permission (:code:`Mail.Send`) must be granted.
* it must also be allowed to read and write into the calendars (:code:`Calendars.ReadWrite.All`);
* for sending invitation to other users, the permission (:code:`Mail.Send`) must be granted;
* and, for reading the absence status of the user and sync it with chill, it must be able to read the mailboxSettings (:code:`MailboxSettings.Read`).
At this step, you might choose to accept those permissions for all users, or let them do it by yourself.
@@ -301,7 +311,7 @@ The calendar synchronization is processed using symfony messenger. It seems to b
The association between chill's users and Microsoft's users is done by this cli command:
.. code-block::
.. code-block::
bin/console chill:calendar:msgraph-user-map-subscribe

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 166 KiB

View File

@@ -0,0 +1,72 @@
<?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\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityPresenceRepositoryInterface;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final readonly class ActivityPresenceAggregator implements AggregatorInterface
{
public function __construct(private ActivityPresenceRepositoryInterface $activityPresenceRepository, private TranslatableStringHelperInterface $translatableStringHelper) {}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
return function (null|int|string $value): string {
if ('_header' === $value) {
return 'export.aggregator.activity.by_activity_presence.header';
}
if (null === $value || '' === $value || null === $presence = $this->activityPresenceRepository->find($value)) {
return '';
}
return $this->translatableStringHelper->localize($presence->getName());
};
}
public function getQueryKeys($data)
{
return ['activity_presence_aggregator_attendee'];
}
public function getTitle(): string
{
return 'export.aggregator.activity.by_activity_presence.Group activity by presence';
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data): void
{
$qb->addSelect('IDENTITY(activity.attendee) AS activity_presence_aggregator_attendee');
$qb->addGroupBy('activity_presence_aggregator_attendee');
}
public function applyOn()
{
return Declarations::ACTIVITY;
}
}

View File

@@ -14,18 +14,18 @@ namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class JobScopeAggregator implements AggregatorInterface
class CreatorJobAggregator implements AggregatorInterface
{
private const PREFIX = 'acp_agg_creator_job';
public function __construct(
private readonly ScopeRepository $scopeRepository,
private readonly UserJobRepositoryInterface $userJobRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
@@ -76,17 +76,15 @@ class JobScopeAggregator implements AggregatorInterface
{
return function ($value): string {
if ('_header' === $value) {
return 'Scope';
return 'Job';
}
if (null === $value || '' === $value) {
if (null === $value || '' === $value || null === $s = $this->userJobRepository->find($value)) {
return '';
}
$s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize(
$s->getName()
$s->getLabel()
);
};
}

View File

@@ -0,0 +1,65 @@
<?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\ActivityBundle\Export\Aggregator\PersonAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final readonly class PersonAggregator implements AggregatorInterface
{
public function __construct(private LabelPersonHelper $labelPersonHelper) {}
public function buildForm(FormBuilderInterface $builder)
{
// nothing to add here
}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
return $this->labelPersonHelper->getLabel($key, $values, 'export.aggregator.person.by_person.person');
}
public function getQueryKeys($data)
{
return ['activity_by_person_agg'];
}
public function getTitle()
{
return 'export.aggregator.person.by_person.title';
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb
->addSelect('IDENTITY(activity.person) AS activity_by_person_agg')
->addGroupBy('activity_by_person_agg');
}
public function applyOn()
{
return Declarations::ACTIVITY_PERSON;
}
}

View File

@@ -0,0 +1,138 @@
<?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\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountPersonsOnActivity implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->repository = $em->getRepository(Activity::class);
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.count_person_on_activity.description';
}
public function getGroup(): string
{
return 'Exports of activities linked to an accompanying period';
}
public function getLabels($key, array $values, $data)
{
if ('export_count_activity' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'export.export.count_person_on_activity.header' : $value;
}
public function getQueryKeys($data): array
{
return ['export_count_activity'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.count_person_on_activity.title';
}
public function getType(): string
{
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository
->createQueryBuilder('activity')
->join('activity.persons', 'person')
->join('activity.accompanyingPeriod', 'acp');
if ($this->filterStatsByCenters) {
$qb
->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)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
$qb->select('COUNT(DISTINCT person.id) as export_count_activity');
return $qb;
}
public function requiredRole(): string
{
return ActivityStatsVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
PersonDeclarations::ACP_TYPE,
PersonDeclarations::PERSON_TYPE,
];
}
}

View File

@@ -0,0 +1,82 @@
<?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\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityPresence;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
final readonly class ActivityPresenceFilter implements FilterInterface
{
public function __construct(
private TranslatableStringHelperInterface $translatableStringHelper,
private TranslatorInterface $translator
) {}
public function getTitle()
{
return 'export.filter.activity.by_presence.Filter activity by activity presence';
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('presences', EntityType::class, [
'class' => ActivityPresence::class,
'choice_label' => fn (ActivityPresence $presence) => $this->translatableStringHelper->localize($presence->getName())
.($presence->isActive() ? '' : ' ('.$this->translator->trans('inactive').')'),
'multiple' => true,
'expanded' => true,
'label' => 'export.filter.activity.by_presence.presences',
]);
}
public function getFormDefaultData(): array
{
return [];
}
public function describeAction($data, $format = 'string')
{
$presences = array_map(
fn (ActivityPresence $presence) => $this->translatableStringHelper->localize($presence->getName()),
$data['presences'] instanceof Collection ? $data['presences']->toArray() : $data['presences']
);
return [
'export.filter.activity.by_presence.Filtered by activity presence: only %presences%',
['%presences%' => implode(', ', $presences)],
];
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb
->andWhere('activity.attendee IN (:activity_presence_filter_presences)')
->setParameter('activity_presence_filter_presences', $data['presences']);
}
public function applyOn()
{
return Declarations::ACTIVITY;
}
}

View File

@@ -0,0 +1,116 @@
<?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\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
final readonly class CreatorJobFilter implements FilterInterface
{
private const PREFIX = 'acp_act_filter_creator_job';
public function __construct(
private TranslatableStringHelper $translatableStringHelper,
private TranslatorInterface $translator,
private UserJobRepositoryInterface $userJobRepository,
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin('activity.createdBy', "{$p}_user")
->leftJoin(
UserJobHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
)
// job_at based on activity.date
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'activity.date')
)
)
)
->andWhere(
$qb->expr()->in("{$p}_history.job", ":{$p}_jobs")
)
->setParameter(
"{$p}_jobs",
$data['jobs'],
);
}
public function applyOn(): string
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('jobs', EntityType::class, [
'choices' => $this->userJobRepository->findAllOrderedByName(),
'class' => UserJob::class,
'choice_label' => fn (UserJob $s) => $this->translatableStringHelper->localize(
$s->getLabel()
).($s->isActive() ? '' : '('.$this->translator->trans('inactive').')'),
'label' => 'export.filter.activity.by_creator_job.job_form_label',
'multiple' => true,
'expanded' => true,
]);
}
public function describeAction($data, $format = 'string'): array
{
$jobs = array_map(
fn (UserJob $job) => $this->translatableStringHelper->localize($job->getLabel()),
$data['jobs'] instanceof Collection ? $data['jobs']->toArray() : $data['jobs']
);
return ['export.filter.activity.by_creator_job.Filtered activity by user job: only %jobs%', [
'%jobs%' => implode(', ', $jobs),
]];
}
public function getFormDefaultData(): array
{
return [
'jobs' => [],
];
}
public function getTitle(): string
{
return 'export.filter.activity.by_creator_job.Filter activity by user job';
}
}

View File

@@ -0,0 +1,62 @@
<?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\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ActivityPresenceAggregator;
use Chill\ActivityBundle\Repository\ActivityPresenceRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class ActivityPresenceAggregatorTest extends AbstractAggregatorTest
{
private TranslatableStringHelperInterface $translatableStringHelper;
private ActivityPresenceRepositoryInterface $activityPresenceRepository;
protected function setUp(): void
{
self::bootKernel();
$this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class);
$this->activityPresenceRepository = self::$container->get(ActivityPresenceRepositoryInterface::class);
}
public function getAggregator()
{
return new ActivityPresenceAggregator($this->activityPresenceRepository, $this->translatableStringHelper);
}
public function getFormData()
{
return [
[],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -12,7 +12,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\JobScopeAggregator;
use Chill\ActivityBundle\Export\Aggregator\CreatorJobAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
@@ -21,15 +21,15 @@ use Doctrine\ORM\EntityManagerInterface;
*
* @coversNothing
*/
final class JobScopeAggregatorTest extends AbstractAggregatorTest
final class CreatorJobAggregatorTest extends AbstractAggregatorTest
{
private JobScopeAggregator $aggregator;
private CreatorJobAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get(JobScopeAggregator::class);
$this->aggregator = self::$container->get(CreatorJobAggregator::class);
}
public function getAggregator()

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\ActivityBundle\Tests\Export\Aggregator\PersonAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\PersonAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class PersonAggregatorTest extends AbstractAggregatorTest
{
private LabelPersonHelper $labelPersonHelper;
protected function setUp(): void
{
self::bootKernel();
$this->labelPersonHelper = self::$container->get(LabelPersonHelper::class);
}
public function getAggregator()
{
return new PersonAggregator($this->labelPersonHelper);
}
public function getFormData()
{
return [[]];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -0,0 +1,54 @@
<?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\ActivityBundle\Tests\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Export\Export\LinkedToACP\CountPersonsOnActivity;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CountPersonsOnActivityTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$em = self::$container->get(EntityManagerInterface::class);
yield new CountPersonsOnActivity($em, $this->getParameters(true));
yield new CountPersonsOnActivity($em, $this->getParameters(false));
}
public function getFormData()
{
return [[]];
}
public function getModifiersCombination()
{
return [[
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
PersonDeclarations::ACP_TYPE,
PersonDeclarations::PERSON_TYPE,
]];
}
}

View File

@@ -0,0 +1,76 @@
<?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\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ActivityPresenceFilter;
use Chill\ActivityBundle\Repository\ActivityPresenceRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
*
* @coversNothing
*/
class ActivityPresenceFilterTest extends AbstractFilterTest
{
private TranslatableStringHelperInterface $translatableStringHelper;
private TranslatorInterface $translator;
protected function setUp(): void
{
parent::setUp();
self::bootKernel();
$this->translator = self::$container->get(TranslatorInterface::class);
$this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class);
}
public function getFilter()
{
return new ActivityPresenceFilter($this->translatableStringHelper, $this->translator);
}
public function getFormData()
{
self::bootKernel();
$presences = self::$container->get(ActivityPresenceRepositoryInterface::class)
->findAll();
return [
[
'presences' => $presences,
],
[
'presences' => new ArrayCollection($presences),
],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
yield $em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity');
self::ensureKernelShutdown();
}
}

View File

@@ -0,0 +1,75 @@
<?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\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\CreatorJobFilter;
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorJobFilterTest extends AbstractFilterTest
{
private EntityManagerInterface $entityManager;
private TranslatableStringHelperInterface $translatableStringHelper;
private TranslatorInterface $translator;
private UserJobRepositoryInterface $userJobRepository;
protected function setUp(): void
{
parent::setUp();
self::bootKernel();
$this->entityManager = self::$container->get(EntityManagerInterface::class);
$this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class);
$this->translator = self::$container->get(TranslatorInterface::class);
$this->userJobRepository = self::$container->get(UserJobRepositoryInterface::class);
}
public function getFilter()
{
return new CreatorJobFilter(
$this->translatableStringHelper,
$this->translator,
$this->userJobRepository
);
}
public function getFormData()
{
$this->setUp();
$jobs = $this->userJobRepository->findAll();
return [
['jobs' => $jobs],
];
}
public function getQueryBuilders()
{
self::setUp();
return [
$this->entityManager->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.user', 'actuser'),
];
}
}

View File

@@ -16,6 +16,10 @@ services:
tags:
- { name: chill.export, alias: 'list_activity_linked_to_person' }
Chill\ActivityBundle\Export\Export\LinkedToACP\CountPersonsOnActivity:
tags:
- { name: chill.export, alias: 'count_person_on_activity' }
chill.activity.export.count_activity_linked_to_acp:
class: Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity
tags:
@@ -115,6 +119,10 @@ services:
# affect all saved exports (unless we write a migration for that)
- { name: chill.export_filter, alias: 'activity_userscope_filter' }
Chill\ActivityBundle\Export\Filter\CreatorJobFilter:
tags:
- { name: chill.export_filter, alias: 'activity_creatorjob_filter' }
Chill\ActivityBundle\Export\Filter\UsersJobFilter:
tags:
- { name: chill.export_filter, alias: 'activity_usersjob_filter' }
@@ -131,6 +139,11 @@ services:
tags:
- { name: chill.export_filter, alias: 'period_having_activity_betw_dates_filter' }
Chill\ActivityBundle\Export\Filter\ActivityPresenceFilter:
tags:
- { name: chill.export_filter, alias: 'activity_presence_filter' }
## Aggregators
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator:
tags:
@@ -179,7 +192,7 @@ services:
tags:
- { name: chill.export_aggregator, alias: activity_creator_scope_aggregator }
Chill\ActivityBundle\Export\Aggregator\JobScopeAggregator:
Chill\ActivityBundle\Export\Aggregator\CreatorJobAggregator:
tags:
- { name: chill.export_aggregator, alias: activity_creator_job_aggregator }
@@ -214,3 +227,11 @@ services:
Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityTypeAggregator:
tags:
- { name: chill.export_aggregator, alias: acp_by_activity_type_aggregator }
Chill\ActivityBundle\Export\Aggregator\ActivityPresenceAggregator:
tags:
- { name: chill.export_aggregator, alias: activity_presence_agg }
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\PersonAggregator:
tags:
- { name: chill.export_aggregator, alias: activity_person_agg }

View File

@@ -332,6 +332,11 @@ docgen:
myWorksOnly: Prendre en compte uniquement les actions d'accompagnement dont je suis référent
export:
export:
count_person_on_activity:
title: Nombre d'usagers concernés par les échanges
description: Compte le nombre d'usagers concernés par les échanges. Si un usager est présent dans plusieurs échanges, il n'est comptabilisé qu'une seule fois.
header: Nombre d'usagers concernés par des échanges
list:
activity:
users name: Nom des utilisateurs
@@ -376,7 +381,11 @@ export:
date mismatch: La date de fin de la période doit être supérieure à la date du début
by_creator_scope:
Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange
'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur de l'échange: uniquement %scopes%"
by_creator_job:
job_form_label: Métiers
Filter activity by user job: Filtrer les échanges par métier du créateur de l'échange
'Filtered activity by user job: only %jobs%': "Filtré par service du créateur de l'échange: uniquement %jobs%"
by_persons:
Filter activity by persons: Filtrer les échanges par usager participant
'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%'
@@ -385,8 +394,16 @@ export:
Sent or received: Envoyé ou reçu
is sent: envoyé
is received: reçu
by_presence:
Filter activity by activity presence: Filtrer les échanges par présence de l'usager
presences: Présences
'Filtered by activity presence: only %presences%': 'Filtré par présence de l''usager: seulement %presences%'
aggregator:
person:
by_person:
title: Grouper les échanges par usager (dossier d'usager dans lequel l'échange est enregistré)
person: Usager
acp:
by_activity_type:
title: Grouper les parcours par type d'échange
@@ -412,11 +429,14 @@ export:
Group activity by creator scope: Grouper les échanges par service du créateur de l'échange
Calc date: Date de calcul du service du créateur de l'échange
by_creator_job:
Group activity by creator job: Grouper les échanges par service du créateur de l'échange
Calc date: Date de calcul du service du créateur de l'échange
Group activity by creator job: Grouper les échanges par métier du créateur de l'échange
Calc date: Date de calcul du métier du créateur de l'échange
by_persons:
Group activity by persons: Grouper les échanges par usager participant
Persons: Usagers participants
by_activity_presence:
Group activity by presence: Grouper les échanges par présence de l'usager
header: Présence de(s) usager(s)
generic_doc:
filter:

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Export\Export;
namespace Chill\CalendarBundle\Export\Export\LinkedToAcp;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
@@ -17,17 +17,25 @@ use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Exception\LogicException;
class CountCalendars implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly CalendarRepository $calendarRepository,
) {}
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
@@ -46,12 +54,12 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
public function getDescription(): string
{
return 'Count calendars by various parameters.';
return 'export.export.count_calendar_linked_to_acp.description';
}
public function getGroup(): string
{
return 'Exports of calendar';
return 'export.export.calendar_linked_to_acp.group';
}
public function getLabels($key, array $values, $data)
@@ -78,7 +86,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
public function getTitle(): string
{
return 'Count calendars';
return 'export.export.count_calendar_linked_to_acp.title';
}
public function getType(): string
@@ -98,6 +106,19 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
$qb->select('COUNT(cal.id) AS export_result');
$qb->leftJoin('cal.accompanyingPeriod', 'acp');
if ($this->filterStatsByCenters) {
$qb
->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)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Export\Export;
namespace Chill\CalendarBundle\Export\Export\LinkedToAcp;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
@@ -17,14 +17,24 @@ use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
{
public function __construct(private readonly CalendarRepository $calendarRepository) {}
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly CalendarRepository $calendarRepository,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
{
@@ -43,12 +53,12 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
public function getDescription(): string
{
return 'Get the average of calendar duration according to various filters';
return 'export.export.avg_duration_calendar_linked_to_acp.description';
}
public function getGroup(): string
{
return 'Exports of calendar';
return 'export.export.calendar_linked_to_acp.group';
}
public function getLabels($key, array $values, $data)
@@ -75,7 +85,7 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
public function getTitle(): string
{
return 'Average calendar duration';
return 'export.export.avg_duration_calendar_linked_to_acp.title';
}
public function getType(): string
@@ -85,11 +95,26 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb->select('AVG(cal.endDate - cal.startDate) AS export_result');
$qb->join('cal.accompanyingPeriod', 'acp');
if ($this->filterStatsByCenters) {
$qb
->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)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Export\Export;
namespace Chill\CalendarBundle\Export\Export\LinkedToAcp;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
@@ -17,14 +17,24 @@ use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
{
public function __construct(private readonly CalendarRepository $calendarRepository) {}
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly CalendarRepository $calendarRepository,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
{
@@ -43,12 +53,12 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
public function getDescription(): string
{
return 'Get the sum of calendar durations according to various filters';
return 'export.export.sum_duration_calendar_linked_to_acp.description';
}
public function getGroup(): string
{
return 'Exports of calendar';
return 'export.export.calendar_linked_to_acp.group';
}
public function getLabels($key, array $values, $data)
@@ -75,7 +85,7 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
public function getTitle(): string
{
return 'Sum of calendar durations';
return 'export.export.sum_duration_calendar_linked_to_acp.description';
}
public function getType(): string
@@ -85,11 +95,26 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb->select('SUM(cal.endDate - cal.startDate) AS export_result');
$qb->join('cal.accompanyingPeriod', 'acp');
if ($this->filterStatsByCenters) {
$qb
->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)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;

View File

@@ -0,0 +1,137 @@
<?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\CalendarBundle\Export\Export\LinkedToPerson;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Exception\LogicException;
class CountCalendars implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly CalendarRepository $calendarRepository,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
// No form necessary
}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.count_calendar_linked_to_person.description';
}
public function getGroup(): string
{
return 'export.export.calendar_linked_to_person.group';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.count_calendar_linked_to_person.title';
}
public function getType(): string
{
return Declarations::CALENDAR_TYPE;
}
/**
* Initiate the query.
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb->select('COUNT(cal.id) AS export_result');
$qb->leftJoin('cal.person', 'person');
if ($this->filterStatsByCenters) {
$qb
->join('person.centerHistory', 'centerHistory')
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'cal.startDate'),
$qb->expr()->orX(
$qb->expr()->isNull('centerHistory.endDate'),
$qb->expr()->gt('centerHistory.endDate', 'cal.endDate')
)
)
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
}
return $qb;
}
public function requiredRole(): string
{
// which role should we give here?
return PersonVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::CALENDAR_TYPE,
];
}
}

View File

@@ -0,0 +1,132 @@
<?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\CalendarBundle\Export\Export\LinkedToPerson;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly CalendarRepository $calendarRepository,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
{
// no form needed
}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.stat_calendar_avg_duration_linked_to_person.description';
}
public function getGroup(): string
{
return 'export.export.calendar_linked_to_person.group';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.stat_calendar_avg_duration_linked_to_person.title';
}
public function getType(): string
{
return Declarations::CALENDAR_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb->select('AVG(cal.endDate - cal.startDate) AS export_result');
$qb->join('cal.person', 'person');
if ($this->filterStatsByCenters) {
$qb
->join('person.centerHistory', 'centerHistory')
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'cal.startDate'),
$qb->expr()->orX(
$qb->expr()->isNull('centerHistory.endDate'),
$qb->expr()->gt('centerHistory.endDate', 'cal.endDate')
)
)
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
}
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::CALENDAR_TYPE,
];
}
}

View File

@@ -0,0 +1,132 @@
<?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\CalendarBundle\Export\Export\LinkedToPerson;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly CalendarRepository $calendarRepository,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
{
// no form needed
}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.stat_calendar_sum_duration_linked_to_person.description';
}
public function getGroup(): string
{
return 'export.export.calendar_linked_to_person.group';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.stat_calendar_sum_duration_linked_to_person.title';
}
public function getType(): string
{
return Declarations::CALENDAR_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb->select('SUM(cal.endDate - cal.startDate) AS export_result');
$qb->join('cal.person', 'person');
if ($this->filterStatsByCenters) {
$qb
->join('person.centerHistory', 'centerHistory')
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'cal.startDate'),
$qb->expr()->orX(
$qb->expr()->isNull('centerHistory.endDate'),
$qb->expr()->gt('centerHistory.endDate', 'cal.endDate')
)
)
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
}
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::CALENDAR_TYPE,
];
}
}

View File

@@ -1,118 +1,139 @@
services:
## Indicators
chill.calendar.export.count_calendars:
class: Chill\CalendarBundle\Export\Export\CountCalendars
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: count_calendars }
## Indicators
chill.calendar.export.count_calendars_linked_to_acp:
class: Chill\CalendarBundle\Export\Export\LinkedToAcp\CountCalendars
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: count_calendars_linked_to_acp }
chill.calendar.export.average_duration_calendars:
class: Chill\CalendarBundle\Export\Export\StatCalendarAvgDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: average_duration_calendars }
chill.calendar.export.average_duration_calendars_linked_to_acp:
class: Chill\CalendarBundle\Export\Export\LinkedToAcp\StatCalendarAvgDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: average_duration_calendars_linked_to_acp }
chill.calendar.export.sum_duration_calendars:
class: Chill\CalendarBundle\Export\Export\StatCalendarSumDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: sum_duration_calendars }
chill.calendar.export.sum_duration_calendars_linked_to_acp:
class: Chill\CalendarBundle\Export\Export\LinkedToAcp\StatCalendarSumDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: sum_duration_calendars_linked_to_acp }
## Filters
chill.calendar.export.count_calendars_linked_to_person:
class: Chill\CalendarBundle\Export\Export\LinkedToPerson\CountCalendars
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: count_calendars_linked_to_person }
chill.calendar.export.agent_filter:
class: Chill\CalendarBundle\Export\Filter\AgentFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: agent_filter }
chill.calendar.export.average_duration_calendars_linked_to_person:
class: Chill\CalendarBundle\Export\Export\LinkedToPerson\StatCalendarAvgDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: average_duration_calendars_linked_to_person }
chill.calendar.export.job_filter:
class: Chill\CalendarBundle\Export\Filter\JobFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: job_filter }
chill.calendar.export.sum_duration_calendars_linked_to_person:
class: Chill\CalendarBundle\Export\Export\LinkedToPerson\StatCalendarSumDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: sum_duration_calendars_linked_to_person }
chill.calendar.export.scope_filter:
class: Chill\CalendarBundle\Export\Filter\ScopeFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: scope_filter }
## Filters
chill.calendar.export.between_dates_filter:
class: Chill\CalendarBundle\Export\Filter\BetweenDatesFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: between_dates_filter }
chill.calendar.export.agent_filter:
class: Chill\CalendarBundle\Export\Filter\AgentFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: agent_filter }
chill.calendar.export.calendar_range_filter:
class: Chill\CalendarBundle\Export\Filter\CalendarRangeFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: calendar_range_filter }
chill.calendar.export.job_filter:
class: Chill\CalendarBundle\Export\Filter\JobFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: job_filter }
## Aggregator
chill.calendar.export.scope_filter:
class: Chill\CalendarBundle\Export\Filter\ScopeFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: scope_filter }
chill.calendar.export.agent_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\AgentAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: agent_aggregator }
chill.calendar.export.between_dates_filter:
class: Chill\CalendarBundle\Export\Filter\BetweenDatesFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: between_dates_filter }
chill.calendar.export.job_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\JobAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: job_aggregator }
chill.calendar.export.calendar_range_filter:
class: Chill\CalendarBundle\Export\Filter\CalendarRangeFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: calendar_range_filter }
chill.calendar.export.scope_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\ScopeAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: scope_aggregator }
## Aggregator
chill.calendar.export.location_type_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationTypeAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: location_type_aggregator }
chill.calendar.export.agent_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\AgentAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: agent_aggregator }
chill.calendar.export.location_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: location_aggregator }
chill.calendar.export.job_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\JobAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: job_aggregator }
chill.calendar.export.cancel_reason_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\CancelReasonAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: cancel_reason_aggregator }
chill.calendar.export.scope_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\ScopeAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: scope_aggregator }
chill.calendar.export.month_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\MonthYearAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: month_aggregator }
chill.calendar.export.location_type_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationTypeAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: location_type_aggregator }
chill.calendar.export.urgency_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\UrgencyAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: urgency_aggregator }
chill.calendar.export.location_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: location_aggregator }
chill.calendar.export.cancel_reason_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\CancelReasonAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: cancel_reason_aggregator }
chill.calendar.export.month_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\MonthYearAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: month_aggregator }
chill.calendar.export.urgency_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\UrgencyAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: urgency_aggregator }

View File

@@ -0,0 +1,55 @@
<?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\CalendarBundle\Tests\Export\Export;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Export\Export\LinkedToAcp\CountCalendars as CountCalendarsLinkedToAcp;
use Chill\CalendarBundle\Export\Export\LinkedToPerson\CountCalendars as CountCalendarsLinkedToPerson;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
*
* @coversNothing
*/
class CountCalendarsTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$repository = self::$container->get(CalendarRepository::class);
yield new CountCalendarsLinkedToAcp($repository, $this->getParameters(true));
yield new CountCalendarsLinkedToAcp($repository, $this->getParameters(false));
yield new CountCalendarsLinkedToPerson($repository, $this->getParameters(true));
yield new CountCalendarsLinkedToPerson($repository, $this->getParameters(false));
}
public function getFormData()
{
return [];
}
public function getModifiersCombination()
{
return [
[
Declarations::CALENDAR_TYPE,
]];
}
}

View File

@@ -0,0 +1,55 @@
<?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\CalendarBundle\Tests\Export\Export;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Export\Export\LinkedToAcp\StatCalendarAvgDuration as StatCalendarAvgDurationLinkedToAcp;
use Chill\CalendarBundle\Export\Export\LinkedToPerson\StatCalendarAvgDuration as StatCalendarAvgDurationLinkedToPerson;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
*
* @coversNothing
*/
class StatCalendarAvgDurationTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$repository = self::$container->get(CalendarRepository::class);
yield new StatCalendarAvgDurationLinkedToAcp($repository, $this->getParameters(true));
yield new StatCalendarAvgDurationLinkedToAcp($repository, $this->getParameters(false));
yield new StatCalendarAvgDurationLinkedToPerson($repository, $this->getParameters(true));
yield new StatCalendarAvgDurationLinkedToPerson($repository, $this->getParameters(false));
}
public function getFormData()
{
return [];
}
public function getModifiersCombination()
{
return [
[
Declarations::CALENDAR_TYPE,
]];
}
}

View File

@@ -0,0 +1,55 @@
<?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\CalendarBundle\Tests\Export\Export;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Export\Export\LinkedToAcp\StatCalendarSumDuration as StatCalendarSumDurationLinkedToAcp;
use Chill\CalendarBundle\Export\Export\LinkedToPerson\StatCalendarSumDuration as StatCalendarSumDurationLinkedToPerson;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
*
* @coversNothing
*/
class StatCalendarSumDurationTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$repository = self::$container->get(CalendarRepository::class);
yield new StatCalendarSumDurationLinkedToAcp($repository, $this->getParameters(true));
yield new StatCalendarSumDurationLinkedToAcp($repository, $this->getParameters(false));
yield new StatCalendarSumDurationLinkedToPerson($repository, $this->getParameters(true));
yield new StatCalendarSumDurationLinkedToPerson($repository, $this->getParameters(false));
}
public function getFormData()
{
return [];
}
public function getModifiersCombination()
{
return [
[
Declarations::CALENDAR_TYPE,
]];
}
}

View File

@@ -356,20 +356,6 @@ final class CalendarSyncerTest extends TestCase
}
JSON;
protected function setUp(): void
{
parent::setUp();
// all tests should run when timezone = +02:00
$brussels = new \DateTimeZone('Europe/Brussels');
if (7200 === $brussels->getOffset(new \DateTimeImmutable())) {
date_default_timezone_set('Europe/Brussels');
} else {
date_default_timezone_set('Europe/Moscow');
}
}
public function testHandleAttendeesConfirmingCalendar(): void
{
$machineHttpClient = new MockHttpClient([

View File

@@ -112,6 +112,31 @@ Group calendars by month and year: Grouper les rendez-vous par mois et année
Group calendars by urgency: Grouper les rendez-vous par urgent ou non
export:
export:
calendar_linked_to_person:
group: Exports des rendez-vous liés à un usager
calendar_linked_to_acp:
group: Exports des rendez-vous liés à un parcours
stat_calendar_sum_duration_linked_to_person:
title: Somme de la durée des rendez-vous
description: Additionne la durée des rendez-vous en fonction de différents paramètres.
stat_calendar_avg_duration_linked_to_person:
title: Moyenne de la durée des rendez-vous
description: Moyenne de la durée des rendez-vous en fonction de différents paramètres.
count_calendar_linked_to_person:
title: Nombre des rendez-vous
description: Compte le nombre des rendez-vous enregistrés et liés à un usager en fonction de différents paramètres.
count_calendar_linked_to_acp:
title: Nombre des rendez-vous
description: Compte le nombre des rendez-vous enregistrés et liées à un parcours en fonction de différents paramètres.
avg_duration_calendar_linked_to_acp:
title: Moyenne de la durée des rendez-vous
description: Moyenne de la durée des rendez-vous en fonction de différents paramètres.
sum_duration_calendar_linked_to_acp:
title: Somme de la durée des rendez-vous
description: Additionne la durée des rendez-vous en fonction de différents paramètres.
aggregator.calendar:
agent_job:
Group calendars by agent job: Grouper les rendez-vous par métier de l'agent

View File

@@ -304,7 +304,7 @@ class ExportController extends AbstractController
FormType::class,
$defaultFormData,
[
'method' => $isGenerate ? 'GET' : 'POST',
'method' => $isGenerate ? Request::METHOD_GET : Request::METHOD_POST,
'csrf_protection' => !$isGenerate,
]
);
@@ -352,7 +352,7 @@ class ExportController extends AbstractController
$form = $this->createCreateFormExport($alias, 'export', $data, $savedExport);
if ('POST' === $request->getMethod()) {
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
@@ -406,7 +406,7 @@ class ExportController extends AbstractController
$form = $this->createCreateFormExport($alias, 'formatter', $data, $savedExport);
if ('POST' === $request->getMethod()) {
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
@@ -536,7 +536,7 @@ class ExportController extends AbstractController
$form = $this->createCreateFormExport($alias, 'centers', [], $savedExport);
if ('POST' === $request->getMethod()) {
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {

View File

@@ -37,9 +37,13 @@ class RollingDateDataMapper implements DataMapperInterface
{
$forms = iterator_to_array($forms);
$viewData = new RollingDate(
$forms['roll']->getData() ?? RollingDate::T_TODAY,
$forms['fixedDate']->getData()
);
if (null === $forms['roll']->getData()) {
$viewData = null;
} else {
$viewData = new RollingDate(
$forms['roll']->getData(),
$forms['fixedDate']->getData()
);
}
}
}

View File

@@ -54,7 +54,7 @@ class PickRollingDateType extends AbstractType
{
$resolver->setDefaults([
'class' => RollingDate::class,
'empty_data' => new RollingDate(RollingDate::T_TODAY),
'empty_data' => null,
'constraints' => [
new Callback($this->validate(...)),
],
@@ -66,6 +66,10 @@ class PickRollingDateType extends AbstractType
public function validate($data, ExecutionContextInterface $context, $payload): void
{
if (null === $data) {
return;
}
/** @var RollingDate $data */
if (RollingDate::T_FIXED_DATE === $data->getRoll() && null === $data->getFixedDate()) {
$context

View File

@@ -12,14 +12,15 @@ declare(strict_types=1);
namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
class UserJobRepository implements UserJobRepositoryInterface
readonly class UserJobRepository implements UserJobRepositoryInterface
{
private readonly EntityRepository $repository;
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em, private TranslatableStringHelperInterface $translatableStringHelper)
{
$this->repository = $em->getRepository(UserJob::class);
}
@@ -42,6 +43,15 @@ class UserJobRepository implements UserJobRepositoryInterface
return $this->repository->findBy(['active' => true]);
}
public function findAllOrderedByName(): array
{
$jobs = $this->findAll();
usort($jobs, fn (UserJob $a, UserJob $b) => $this->translatableStringHelper->localize($a->getLabel()) <=> $this->translatableStringHelper->localize($b->getLabel()));
return $jobs;
}
/**
* @param mixed|null $limit
* @param mixed|null $offset

View File

@@ -28,6 +28,13 @@ interface UserJobRepositoryInterface extends ObjectRepository
*/
public function findAllActive(): array;
/**
* a list of UserJob ordered by name.
*
* @return array<UserJob>
*/
public function findAllOrderedByName(): array;
/**
* @param mixed|null $limit
* @param mixed|null $offset

View File

@@ -1,7 +1,6 @@
import {ShowHide} from 'ChillMainAssets/lib/show_hide/index';
document.addEventListener('DOMContentLoaded', function(_e) {
console.log('pick-rolling-date');
document.querySelectorAll('div[data-rolling-date]').forEach( (picker) => {
const
roll_wrapper = picker.querySelector('div.roll-wrapper'),
@@ -11,12 +10,8 @@ document.addEventListener('DOMContentLoaded', function(_e) {
froms: [roll_wrapper],
container: [fixed_wrapper],
test: function (elems) {
console.log('testing');
console.log('elems', elems);
for (let el of elems) {
for (let select_roll of el.querySelectorAll('select[data-roll-picker]')) {
console.log('select_roll', select_roll);
console.log('value', select_roll.value);
return select_roll.value === 'fixed_date';
}
}

View File

@@ -28,9 +28,7 @@
{% block js %}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('page_export') }}
{% if export_alias == 'count_social_work_actions' %}
{{ encore_entry_script_tags('vue_export_action_goal_result') }}
{% endif %}
{{ encore_entry_script_tags('vue_export_action_goal_result') }}
{{ encore_entry_script_tags('mod_pick_rolling_date') }}
{% endblock js %}

View File

@@ -392,9 +392,13 @@ class AccompanyingPeriodWork implements AccompanyingPeriodLinkedWithSocialIssues
*/
public function getReferrers(): ReadableCollection
{
return $this->referrersHistory
$users = $this->referrersHistory
->filter(fn (AccompanyingPeriodWorkReferrerHistory $h) => null === $h->getEndDate())
->map(fn (AccompanyingPeriodWorkReferrerHistory $h) => $h->getUser());
->map(fn (AccompanyingPeriodWorkReferrerHistory $h) => $h->getUser())
->getValues()
;
return new ArrayCollection(array_values($users));
}
public function getReferrersHistory(): Collection

View File

@@ -83,7 +83,12 @@ final readonly class GeographicalUnitStatAggregator implements AggregatorInterfa
'acp_geog_units'
);
$qb->andWhere($qb->expr()->in('acp_geog_units.layer', ':acp_geog_unit_layer'));
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->isNull('acp_geog_units'),
$qb->expr()->in('acp_geog_units.layer', ':acp_geog_unit_layer')
)
);
$qb->setParameter('acp_geog_unit_layer', $data['level']);

View File

@@ -19,11 +19,10 @@ use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class ChildrenNumberAggregator implements AggregatorInterface
{
public function __construct(private readonly TranslatorInterface $translator, private readonly RollingDateConverterInterface $rollingDateConverter) {}
public function __construct(private readonly RollingDateConverterInterface $rollingDateConverter) {}
public function addRole(): ?string
{

View File

@@ -0,0 +1,99 @@
<?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\Aggregator\PersonAggregators;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final readonly class PostalCodeAggregator implements AggregatorInterface
{
private const PREFIX = 'person_postal_code_agg';
public function __construct(
private RollingDateConverterInterface $rollingDateConverter,
) {}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('calc_date', PickRollingDateType::class, [
'label' => 'export.aggregator.person.by_postal_code.at_date',
]);
}
public function getFormDefaultData(): array
{
return ['calc_date' => new RollingDate(RollingDate::T_TODAY)];
}
public function getLabels($key, array $values, mixed $data)
{
return function (null|int|string $value): string {
if ('_header' === $value) {
return 'export.aggregator.person.by_postal_code.header';
}
if (null === $value) {
return '';
}
return $value;
};
}
public function getQueryKeys($data)
{
return [self::PREFIX.'_postal_code_code', self::PREFIX.'_postal_code_label'];
}
public function getTitle()
{
return 'export.aggregator.person.by_postal_code.title';
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin(
'person.householdAddresses',
"{$p}_household_addresses",
Join::WITH,
"{$p}_household_addresses.validFrom <= :{$p}_calc_date AND ({$p}_household_addresses.validTo IS NULL OR {$p}_household_addresses.validTo > :{$p}_calc_date)"
)
->setParameter("{$p}_calc_date", $this->rollingDateConverter->convert($data['calc_date']))
->leftJoin("{$p}_household_addresses.address", "{$p}_address")
->leftJoin("{$p}_address.postcode", "{$p}_postal_code")
->addSelect("{$p}_postal_code.code AS {$p}_postal_code_code")
->addSelect("{$p}_postal_code.name AS {$p}_postal_code_label")
->addGroupBy("{$p}_postal_code_code")
->addGroupBy("{$p}_postal_code_label")
;
}
public function applyOn()
{
return Declarations::PERSON_TYPE;
}
}

View File

@@ -0,0 +1,82 @@
<?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\Aggregator\SocialWorkAggregators;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Entity\UserRender;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorAggregator implements AggregatorInterface
{
private const PREFIX = 'acpw_aggr_creator';
public function __construct(
private readonly UserRepository $userRepository,
private readonly UserRender $userRender
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->addSelect("IDENTITY(acpw.createdBy) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
return function ($value): string {
if ('_header' === $value) {
return 'export.aggregator.course_work.by_creator.Creator';
}
if (null === $value || '' === $value) {
return '';
}
$r = $this->userRepository->find($value);
return $this->userRender->renderString($r, ['absence' => false, 'user_job' => false, 'main_scope' => false]);
};
}
public function getQueryKeys($data): array
{
return [self::PREFIX.'_select'];
}
public function getTitle(): string
{
return 'export.aggregator.course_work.by_creator.title';
}
}

View File

@@ -0,0 +1,99 @@
<?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\Aggregator\SocialWorkAggregators;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserJobRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorJobAggregator implements AggregatorInterface
{
private const PREFIX = 'acpw_aggr_creator_job';
public function __construct(
private readonly UserJobRepository $jobRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin(
UserJobHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->andX(
$qb->expr()->eq("{$p}_history.user", 'acpw.createdBy'),
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'acpw.createdAt'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'acpw.createdAt')
)
)
)
)
->addSelect("IDENTITY({$p}_history.job) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
return function ($value): string {
if ('_header' === $value) {
return 'export.aggregator.course_work.by_creator_job.Creator\'s job';
}
if (null === $value || '' === $value || null === $j = $this->jobRepository->find($value)) {
return '';
}
return $this->translatableStringHelper->localize(
$j->getLabel()
);
};
}
public function getQueryKeys($data): array
{
return [self::PREFIX.'_select'];
}
public function getTitle(): string
{
return 'export.aggregator.course_work.by_creator_job.title';
}
}

View File

@@ -0,0 +1,99 @@
<?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\Aggregator\SocialWorkAggregators;
use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorScopeAggregator implements AggregatorInterface
{
private const PREFIX = 'acpw_aggr_creator_scope';
public function __construct(
private readonly ScopeRepository $scopeRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin(
UserScopeHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->andX(
$qb->expr()->eq("{$p}_history.user", 'acpw.createdBy'),
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'acpw.createdAt'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'acpw.createdAt')
)
)
)
)
->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
return function ($value): string {
if ('_header' === $value) {
return 'export.aggregator.course_work.by_creator_scope.Creator\'s scope';
}
if (null === $value || '' === $value || null === $s = $this->scopeRepository->find($value)) {
return '';
}
return $this->translatableStringHelper->localize(
$s->getName()
);
};
}
public function getQueryKeys($data): array
{
return [self::PREFIX.'_select'];
}
public function getTitle(): string
{
return 'export.aggregator.course_work.by_creator_scope.title';
}
}

View File

@@ -0,0 +1,131 @@
<?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\Export;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
ParameterBagInterface $parameterBag,
private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.avg_duration_acpw_associate_on_period.description';
}
public function getGroup(): string
{
return 'Exports of social work actions';
}
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 fn ($value) => '_header' === $value ? 'export.export.avg_duration_acpw_associate_on_period.header' : $value;
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.avg_duration_acpw_associate_on_period.title';
}
public function getType(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->accompanyingPeriodWorkRepository->createQueryBuilder('acpw');
$qb
->join('acpw.accompanyingPeriod', 'acp')
->join('acp.participations', 'acppart')
->join('acppart.person', 'person');
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'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);
}
$qb->select('AVG(DATE_DIFF(COALESCE(acpw.endDate, CURRENT_DATE()), acpw.startDate)) AS export_result');
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
];
}
}

View File

@@ -0,0 +1,130 @@
<?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\Export;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class AvgDurationAPWorkPersonAssociatedOnWork implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
ParameterBagInterface $parameterBag,
private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.avg_duration_acpw_associate_on_work.description';
}
public function getGroup(): string
{
return 'Exports of social work actions';
}
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 fn ($value) => '_header' === $value ? 'export.export.avg_duration_acpw_associate_on_work.header' : $value;
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.avg_duration_acpw_associate_on_work.title';
}
public function getType(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->accompanyingPeriodWorkRepository->createQueryBuilder('acpw');
$qb
->join('acpw.accompanyingPeriod', 'acp')
->join('acpw.persons', 'person');
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'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);
}
$qb->select('AVG(DATE_DIFF(COALESCE(acpw.endDate, CURRENT_DATE()), acpw.startDate)) AS export_result');
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
];
}
}

View File

@@ -25,7 +25,7 @@ use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInterface
class CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
@@ -53,7 +53,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter
public function getDescription(): string
{
return 'Count social work actions by various parameters';
return 'export.export.count_accompanying_period_work_associate_person.description';
}
public function getGroup(): string
@@ -68,7 +68,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
$labels['_header'] = 'export.export.count_accompanying_period_work_associate_person.header';
return static fn ($value) => $labels[$value];
}
@@ -85,7 +85,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter
public function getTitle(): string
{
return 'Count social work actions';
return 'export.export.count_accompanying_period_work_associate_person.title';
}
public function getType(): string

View File

@@ -0,0 +1,139 @@
<?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\Export;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountAccompanyingPeriodWorkAssociatePersonOnWork implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
protected EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
{
// No form necessary?
}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.count_accompanying_period_work_associate_work.description';
}
public function getGroup(): string
{
return 'Exports of social work actions';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = 'export.export.count_accompanying_period_work_associate_work.header';
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.count_accompanying_period_work_associate_work.title';
}
public function getType(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->em->createQueryBuilder();
$qb
->from(AccompanyingPeriod\AccompanyingPeriodWork::class, 'acpw')
->join('acpw.accompanyingPeriod', 'acp')
->join('acpw.persons', 'person');
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'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);
}
$qb->select('COUNT(DISTINCT acpw.id) as export_result');
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
];
}
}

View File

@@ -26,7 +26,7 @@ use Doctrine\ORM\Query;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountHousehold implements ExportInterface, GroupedExportInterface
class CountHouseholdInPeriod implements ExportInterface, GroupedExportInterface
{
private const TR_PREFIX = 'export.export.nb_household_with_course.';
private readonly bool $filterStatsByCenters;
@@ -120,6 +120,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface
->join('person.accompanyingPeriodParticipations', 'acppart')
->join('acppart.accompanyingPeriod', 'acp')
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL')
->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)')
->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date']));
$qb
@@ -135,7 +136,6 @@ class CountHousehold implements ExportInterface, GroupedExportInterface
'
)
)
->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)')
->setParameter('authorized_centers', $centers);
}

View File

@@ -0,0 +1,139 @@
<?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\Export;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountPersonOnAccompanyingPeriodWorkAssociatePersonOnWork implements ExportInterface, GroupedExportInterface
{
private readonly bool $filterStatsByCenters;
public function __construct(
protected EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
{
// No form necessary?
}
public function getFormDefaultData(): array
{
return [];
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'export.export.count_person_on_acpw_associate_person_on_work.description';
}
public function getGroup(): string
{
return 'Exports of social work actions';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = 'export.export.count_person_on_acpw_associate_person_on_work.header';
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.export.count_person_on_acpw_associate_person_on_work.title';
}
public function getType(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->em->createQueryBuilder();
$qb
->from(AccompanyingPeriod\AccompanyingPeriodWork::class, 'acpw')
->join('acpw.accompanyingPeriod', 'acp')
->join('acpw.persons', 'person');
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'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);
}
$qb->select('COUNT(DISTINCT person.id) as export_result');
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
];
}
}

View File

@@ -47,7 +47,7 @@ use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterface
class ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod implements ListInterface, GroupedExportInterface
{
private const FIELDS = [
'id',
@@ -121,7 +121,7 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
public function getDescription(): string
{
return 'export.list.acpw.List description';
return 'export.list.acpw_associate_period.List description';
}
public function getGroup(): string
@@ -190,12 +190,12 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
public function getResult($query, $data)
{
return dump($query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR));
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.list.acpw.List of accompanying period works';
return 'export.list.acpw_associate_period.List of accompanying period works';
}
public function getType(): string

View File

@@ -0,0 +1,348 @@
<?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\Export;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\Helper\AggregateStringHelper;
use Chill\MainBundle\Export\Helper\DateTimeHelper;
use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper;
use Chill\MainBundle\Export\Helper\UserHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkGoal;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkReferrerHistory;
use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Entity\SocialWork\Result;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class ListAccompanyingPeriodWorkAssociatePersonOnWork implements ListInterface, GroupedExportInterface
{
private const FIELDS = [
'id',
'socialActionId',
'socialAction',
'socialIssue',
'acp_id',
'acp_user',
'startDate',
'endDate',
'goalsId',
'goalsTitle',
'goalResultsId',
'goalResultsTitle',
'resultsId',
'resultsTitle',
'evaluationsId',
'evaluationsTitle',
'note',
'personsId',
'personsName',
'thirdParties',
'handlingThierParty',
// 'acpwReferrers',
'referrers',
'createdAt',
'createdBy',
'updatedAt',
'updatedBy',
];
private readonly bool $filterStatsByCenters;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly DateTimeHelper $dateTimeHelper,
private readonly UserHelper $userHelper,
private readonly LabelPersonHelper $personHelper,
private readonly LabelThirdPartyHelper $thirdPartyHelper,
private readonly TranslatableStringExportLabelHelper $translatableStringExportLabelHelper,
private readonly SocialIssueRender $socialIssueRender,
private readonly SocialIssueRepository $socialIssueRepository,
private readonly SocialActionRender $socialActionRender,
private readonly RollingDateConverterInterface $rollingDateConverter,
private readonly AggregateStringHelper $aggregateStringHelper,
private readonly SocialActionRepository $socialActionRepository,
ParameterBagInterface $parameterBag,
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('calc_date', PickRollingDateType::class, [
'label' => 'export.list.acpw.Date of calculation for associated elements',
'help' => 'export.list.acpw.help_description',
'required' => true,
]);
}
public function getFormDefaultData(): array
{
return ['calc_date' => new RollingDate(RollingDate::T_TODAY)];
}
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_LIST];
}
public function getDescription(): string
{
return 'export.list.acpw_associate_work.List description';
}
public function getGroup(): string
{
return 'Exports of social work actions';
}
public function getLabels($key, array $values, $data)
{
return match ($key) {
'startDate', 'endDate', 'createdAt', 'updatedAt' => $this->dateTimeHelper->getLabel('export.list.acpw.'.$key),
'socialAction' => function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acpw.'.$key;
}
if (null === $value) {
return '';
}
return $this->socialActionRender->renderString(
$this->socialActionRepository->find($value),
[]
);
},
'socialIssue' => function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acpw.'.$key;
}
if (null === $value) {
return '';
}
return $this->socialIssueRender->renderString(
$this->socialIssueRepository->find($value),
[]
);
},
'createdBy', 'updatedBy', 'acp_user' => $this->userHelper->getLabel($key, $values, 'export.list.acpw.'.$key),
'referrers' => $this->userHelper->getLabel($key, $values, 'export.list.acpw.'.$key),
// 'acpwReferrers' => $this->userHelper->getLabelMulti($key, $values, 'export.list.acpw.' . $key),
'personsName' => $this->personHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key),
'handlingThierParty' => $this->thirdPartyHelper->getLabel($key, $values, 'export.list.acpw.'.$key),
'thirdParties' => $this->thirdPartyHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key),
'personsId', 'goalsId', 'goalResultsId', 'resultsId', 'evaluationsId' => $this->aggregateStringHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key),
'goalsTitle', 'goalResultsTitle', 'resultsTitle', 'evaluationsTitle' => $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key),
default => static function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acpw.'.$key;
}
if (null === $value) {
return '';
}
return $value;
},
};
}
public function getQueryKeys($data)
{
return self::FIELDS;
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'export.list.acpw_associate_work.List of accompanying period works';
}
public function getType(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->entityManager->createQueryBuilder();
$qb
->from(AccompanyingPeriodWork::class, 'acpw')
->distinct()
->select('acpw.id AS id')
->join('acpw.accompanyingPeriod', 'acp')
->join('acpw.persons', 'person')
;
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'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);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
$this->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date']));
return $qb;
}
public function requiredRole(): string
{
return AccompanyingPeriodVoter::STATS;
}
public function supportsModifiers(): array
{
return [
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
];
}
private function addSelectClauses(QueryBuilder $qb, \DateTimeImmutable $calcDate): void
{
// add regular fields
foreach ([
'startDate',
'endDate',
'note',
'createdAt',
'updatedAt',
] as $field) {
$qb->addSelect(sprintf('acpw.%s AS %s', $field, $field));
}
// those with identity
foreach ([
'createdBy',
'updatedBy',
'handlingThierParty',
] as $field) {
$qb->addSelect(sprintf('IDENTITY(acpw.%s) AS %s', $field, $field));
}
// join socialaction
$qb
->join('acpw.socialAction', 'sa')
->addSelect('sa.id AS socialActionId')
->addSelect('sa.id AS socialAction')
->addSelect('IDENTITY(sa.issue) AS socialIssue');
// join acp
$qb
->addSelect('acp.id AS acp_id')
->addSelect('IDENTITY(acp.user) AS acp_user');
// persons
$qb
->addSelect('(SELECT AGGREGATE(person_acpw_member.id) FROM '.Person::class.' person_acpw_member '
.'WHERE person_acpw_member MEMBER OF acpw.persons) AS personsId')
->addSelect('(SELECT AGGREGATE(person1_acpw_member.id) FROM '.Person::class.' person1_acpw_member '
.'WHERE person1_acpw_member MEMBER OF acpw.persons) AS personsName');
// referrers => at date XXXX
$qb
->addSelect('(SELECT JSON_BUILD_OBJECT(\'uid\', IDENTITY(history.user), \'d\', history.startDate) FROM '.UserHistory::class.' history '.
'WHERE history.accompanyingPeriod = acp AND history.startDate <= :calcDate AND (history.endDate IS NULL OR history.endDate > :calcDate)) AS referrers');
/*
// acpwReferrers at date XXX
$qb
->addSelect('(
SELECT IDENTITY(acpw_ref_history.accompanyingPeriodWork) AS acpw_ref_history_id,
JSON_BUILD_OBJECT(\'uid\', IDENTITY(acpw_ref_history.user), \'d\', acpw_ref_history.startDate)
FROM ' . AccompanyingPeriodWorkReferrerHistory::class . ' acpw_ref_history ' .
'WHERE acpw_ref_history.accompanyingPeriodWork = acpw AND acpw_ref_history.startDate <= :calcDate AND (acpw_ref_history.endDate IS NULL or acpw_ref_history.endDate > :calcDate) GROUP BY acpw_ref_history_id) AS acpwReferrers'
);
*/
// thirdparties
$qb
->addSelect('(SELECT AGGREGATE(tp.id) FROM '.ThirdParty::class.' tp '
.'WHERE tp MEMBER OF acpw.thirdParties) AS thirdParties');
// goals
$qb
->addSelect('(SELECT AGGREGATE(IDENTITY(goal.goal)) FROM '.AccompanyingPeriodWorkGoal::class.' goal '
.'WHERE goal MEMBER OF acpw.goals) AS goalsId')
->addSelect('(SELECT AGGREGATE(g.title) FROM '.AccompanyingPeriodWorkGoal::class.' goal1 '
.'LEFT JOIN '.Goal::class.' g WITH goal1.goal = g.id WHERE goal1 MEMBER OF acpw.goals) AS goalsTitle');
// goals results
$qb
->addSelect('(SELECT AGGREGATE(wr.id) FROM '.Result::class.' wr '
.'JOIN '.AccompanyingPeriodWorkGoal::class.' wg WITH wr MEMBER OF wg.results '
.'WHERE wg MEMBER OF acpw.goals) AS goalResultsId')
->addSelect('(SELECT AGGREGATE(wr1.title) FROM '.Result::class.' wr1 '
.'JOIN '.AccompanyingPeriodWorkGoal::class.' wg1 WITH wr1 MEMBER OF wg1.results '
.'WHERE wg1 MEMBER OF acpw.goals) AS goalResultsTitle');
// results
$qb
->addSelect('(SELECT AGGREGATE(result.id) FROM '.Result::class.' result '
.'WHERE result MEMBER OF acpw.results ) AS resultsId ')
->addSelect('(SELECT AGGREGATE (result1.title) FROM '.Result::class.' result1 '
.'WHERE result1 MEMBER OF acpw.results ) AS resultsTitle ');
// evaluations
$qb
->addSelect('(SELECT AGGREGATE(IDENTITY(we.evaluation)) FROM '.AccompanyingPeriodWorkEvaluation::class.' we '
.'WHERE we MEMBER OF acpw.accompanyingPeriodWorkEvaluations ) AS evaluationsId ')
->addSelect('(SELECT AGGREGATE(ev.title) FROM '.AccompanyingPeriodWorkEvaluation::class.' we1 '
.'LEFT JOIN '.Evaluation::class.' ev WITH we1.evaluation = ev.id '
.'WHERE we1 MEMBER OF acpw.accompanyingPeriodWorkEvaluations ) AS evaluationsTitle ');
$qb->setParameter('calcDate', $calcDate);
}
}

View File

@@ -12,6 +12,8 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Export\Declarations;
@@ -19,10 +21,17 @@ use Chill\PersonBundle\Form\Type\PickSocialActionType;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
final readonly class SocialActionFilter implements FilterInterface
{
public function __construct(private SocialActionRender $actionRender) {}
private const PREFIX = 'acp_by_social_action_filter';
public function __construct(
private SocialActionRender $actionRender,
private RollingDateConverterInterface $rollingDateConverter,
private TranslatorInterface $translator
) {}
public function addRole(): ?string
{
@@ -31,17 +40,40 @@ final readonly class SocialActionFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->andWhere(
$qb->expr()->exists(
sprintf(
'SELECT 1 FROM %s acp_by_social_action_filter WHERE acp_by_social_action_filter.socialAction '
.'IN (:acp_by_social_action_filter_actions) AND acp_by_social_action_filter.accompanyingPeriod = acp',
AccompanyingPeriod\AccompanyingPeriodWork::class
)
)
);
$p = self::PREFIX;
$qb->setParameter('acp_by_social_action_filter_actions', SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions']));
$dql =
sprintf(
'SELECT 1 FROM %s acp_by_social_action_filter WHERE acp_by_social_action_filter.accompanyingPeriod = acp ',
AccompanyingPeriod\AccompanyingPeriodWork::class
);
if (0 < count($data['accepted_socialactions'])) {
$dql .= 'AND acp_by_social_action_filter.socialAction IN (:acp_by_social_action_filter_actions)';
$qb->setParameter("{$p}_actions", SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions']));
}
if (null !== ($data['start_date_after'] ?? null)) {
$dql .= " AND acp_by_social_action_filter.startDate > :{$p}_start_date_after";
$qb->setParameter("{$p}_start_date_after", $this->rollingDateConverter->convert($data['start_date_after']));
}
if (null !== ($data['start_date_before'] ?? null)) {
$dql .= " AND acp_by_social_action_filter.startDate <= :{$p}_start_date_before";
$qb->setParameter("{$p}_start_date_before", $this->rollingDateConverter->convert($data['start_date_before']));
}
if (null !== ($data['end_date_after'] ?? null)) {
$dql .= " AND acp_by_social_action_filter.endDate > :{$p}_end_date_after OR acp_by_social_action_filter.endDate IS NULL";
$qb->setParameter("{$p}_end_date_after", $this->rollingDateConverter->convert($data['end_date_after']));
}
if (null !== ($data['end_date_before'] ?? null)) {
$dql .= " AND acp_by_social_action_filter.endDate <= :{$p}_end_date_before OR acp_by_social_action_filter.endDate IS NULL";
$qb->setParameter("{$p}_end_date_before", $this->rollingDateConverter->convert($data['end_date_before']));
}
$qb->andWhere($qb->expr()->exists($dql));
}
public function applyOn(): string
@@ -51,14 +83,44 @@ final readonly class SocialActionFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_socialactions', PickSocialActionType::class, [
'multiple' => true,
]);
$builder
->add('accepted_socialactions', PickSocialActionType::class, [
'multiple' => true,
'label' => 'export.filter.course.by_social_action.Accepted socialactions',
'help' => 'export.filter.course.by_social_action.accepted socialations help',
])
->add('start_date_after', PickRollingDateType::class, [
'label' => 'export.filter.course.by_social_action.start date after',
'help' => 'export.filter.course.by_social_action.start date after help',
'required' => false,
])
->add('start_date_before', PickRollingDateType::class, [
'label' => 'export.filter.course.by_social_action.start date before',
'help' => 'export.filter.course.by_social_action.start date before help',
'required' => false,
])
->add('end_date_after', PickRollingDateType::class, [
'label' => 'export.filter.course.by_social_action.end date after',
'help' => 'export.filter.course.by_social_action.end date after help',
'required' => false,
])
->add('end_date_before', PickRollingDateType::class, [
'label' => 'export.filter.course.by_social_action.end date before',
'help' => 'export.filter.course.by_social_action.end date before help',
'required' => false,
])
;
}
public function getFormDefaultData(): array
{
return [];
return [
'accepted_social_actions' => [],
'start_date_after' => null,
'start_date_before' => null,
'end_date_after' => null,
'end_date_before' => null,
];
}
public function describeAction($data, $format = 'string'): array
@@ -73,13 +135,17 @@ final readonly class SocialActionFilter implements FilterInterface
]);
}
return ['Filtered by socialactions: only %socialactions%', [
return ['export.filter.course.by_social_action.Filtered by socialactions: only %socialactions%', [
'%socialactions%' => implode(', ', $actions),
'%start_date_after%' => null === ($data['start_date_after'] ?? null) ? '('.$this->translator->trans('export.filter.course.by_social_action.date ignored').')' : $this->rollingDateConverter->convert($data['start_date_after'])->format('d-m-Y'),
'%start_date_before%' => null === ($data['start_date_before'] ?? null) ? '('.$this->translator->trans('export.filter.course.by_social_action.date ignored').')' : $this->rollingDateConverter->convert($data['start_date_before'])->format('d-m-Y'),
'%end_date_after%' => null === ($data['end_date_after'] ?? null) ? '('.$this->translator->trans('export.filter.course.by_social_action.date ignored').')' : $this->rollingDateConverter->convert($data['end_date_after'])->format('d-m-Y'),
'%end_date_before%' => null === ($data['end_date_before'] ?? null) ? '('.$this->translator->trans('export.filter.course.by_social_action.date ignored').')' : $this->rollingDateConverter->convert($data['end_date_before'])->format('d-m-Y'),
]];
}
public function getTitle(): string
{
return 'Filter by socialaction';
return 'export.filter.course.by_social_action.title';
}
}

View File

@@ -54,7 +54,7 @@ final readonly class AccompanyingPeriodWorkEndDateBetweenDateFilter implements F
public function describeAction($data, $format = 'string'): array
{
return [
'export.filter.work.end_between_dates.Only where end date is between %endDate% and %endDate%',
'export.filter.work.end_between_dates.Only where start date is between %startDate% and %endDate%',
[
'%startDate%' => null !== $data['start_date'] ? $this->rollingDateConverter->convert($data['start_date'])->format('d-m-Y') : '',
'%endDate%' => null !== $data['end_date'] ? $this->rollingDateConverter->convert($data['end_date'])->format('d-m-Y') : '',

View File

@@ -0,0 +1,74 @@
<?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\SocialWorkFilters;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorFilter implements FilterInterface
{
private const PREFIX = 'acpw_filter_creator';
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin('acpw.createdBy', "{$p}_creator")
->andWhere($qb->expr()->in("{$p}_creator", ":{$p}_creators"))
->setParameter("{$p}_creators", $data['creators']);
}
public function applyOn(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('creators', PickUserDynamicType::class, [
'multiple' => true,
'label' => 'export.filter.work.by_creator.Creators',
]);
}
public function describeAction($data, $format = 'string'): array
{
return [
'export.filter.work.by_creator.Filtered by creator: only %creators%', [
'%creators%' => implode(', ', array_map(static fn (User $u) => $u->getLabel(), $data['creators'])),
],
];
}
public function getFormDefaultData(): array
{
return [
'creators' => [],
];
}
public function getTitle(): string
{
return 'export.filter.work.by_creator.title';
}
}

View File

@@ -0,0 +1,107 @@
<?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\SocialWorkFilters;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Repository\UserJobRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorJobFilter implements FilterInterface
{
private const PREFIX = 'acpw_filter_creator_job';
public function __construct(
private readonly UserJobRepository $userJobRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin(
UserJobHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->andX(
$qb->expr()->eq("{$p}_history.user", 'acpw.createdBy'),
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'acpw.createdAt'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'acpw.createdAt')
)
)
)
)
->andWhere($qb->expr()->in("{$p}_history.job", ":{$p}_jobs"))
->setParameter("{$p}_jobs", $data['jobs']);
}
public function applyOn(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('jobs', EntityType::class, [
'class' => UserJob::class,
'choices' => $this->userJobRepository->findAllActive(),
'multiple' => true,
'expanded' => true,
'choice_label' => fn (UserJob $job) => $this->translatableStringHelper->localize($job->getLabel()),
'label' => 'Job',
]);
}
public function describeAction($data, $format = 'string'): array
{
$creatorJobs = [];
foreach ($data['jobs'] as $j) {
$creatorJobs[] = $this->translatableStringHelper->localize(
$j->getLabel()
);
}
return ['export.filter.work.by_creator_job.Filtered by creator job: only %jobs%', [
'%jobs%' => implode(', ', $creatorJobs),
]];
}
public function getFormDefaultData(): array
{
return [
'jobs' => [],
];
}
public function getTitle(): string
{
return 'export.filter.work.by_creator_job.title';
}
}

View File

@@ -0,0 +1,107 @@
<?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\SocialWorkFilters;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorScopeFilter implements FilterInterface
{
private const PREFIX = 'acpw_filter_creator_scope';
public function __construct(
private readonly ScopeRepository $scopeRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin(
UserScopeHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->andX(
$qb->expr()->eq("{$p}_history.user", 'acpw.createdBy'),
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'acpw.createdAt'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'acpw.createdAt')
)
)
)
)
->andWhere($qb->expr()->in("{$p}_history.scope", ":{$p}_scopes"))
->setParameter("{$p}_scopes", $data['scopes']);
}
public function applyOn(): string
{
return Declarations::SOCIAL_WORK_ACTION_TYPE;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('scopes', EntityType::class, [
'class' => Scope::class,
'choices' => $this->scopeRepository->findAllActive(),
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()),
'multiple' => true,
'expanded' => true,
'label' => 'Scope',
]);
}
public function describeAction($data, $format = 'string'): array
{
$creatorScopes = [];
foreach ($data['scopes'] as $s) {
$creatorScopes[] = $this->translatableStringHelper->localize(
$s->getName()
);
}
return ['export.filter.work.by_creator_scope.Filtered by creator scope: only %scopes%', [
'%scopes%' => implode(', ', $creatorScopes),
]];
}
public function getFormDefaultData(): array
{
return [
'scopes' => [],
];
}
public function getTitle(): string
{
return 'export.filter.work.by_creator_scope.title';
}
}

View File

@@ -1,11 +1,11 @@
<template>
<teleport to="#export_filters_social_work_type_filter_form">
<fieldset class="mb-3" id="actionType">
<div class="row">
<legend class="col-sm-4 col-form-label">{{ $t('action.label')}}</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="action"
:options="actions.options"
@@ -18,16 +18,16 @@
track-by="id"
:searchable="true"
></VueMultiselect>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="goal">
<div class="row">
<legend class="col-sm-4 col-form-label">{{ $t('goal.label')}}</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="goal"
:options="goals.options"
@@ -41,16 +41,16 @@
track-by="id"
:searchable="true"
></VueMultiselect>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="result">
<div class="row">
<legend class="col-sm-4 col-form-label">{{ $t('result.label')}}</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="result"
:options="results.options"
@@ -64,11 +64,11 @@
track-by="id"
:searchable="true"
></VueMultiselect>
</div>
</div>
</fieldset>
</teleport>
</template>
@@ -152,18 +152,18 @@ export default {
},
mounted() {
this.getSocialActionsList();
this.actions.hiddenField.value = '';
this.goals.hiddenField.value = '';
this.results.hiddenField.value = '';
//console.log(this.actions.hiddenField, this.goals.hiddenField, this.results.hiddenField);
},
methods: {
async getSocialActionsList() {
this.actions.options = await getSocialActions();
},
/**
* Select/unselect in Action Multiselect
* @param value
@@ -172,7 +172,7 @@ export default {
//console.log('----'); console.log('select action', value.id);
let children = this.getChildrensFromParent(value);
this.addSelectedElement('actions', children);
let parentAndChildren = [...[value], ...children];
parentAndChildren.forEach(elem => {
getGoalByAction(elem.id).then(response => new Promise((resolve, reject) => {
@@ -185,7 +185,7 @@ export default {
})).catch;
});
},
unselectAction(value) {
//console.log('----'); console.log('unselect action', value.id);
getGoalByAction(value.id).then(response => new Promise((resolve, reject) => {
@@ -197,7 +197,7 @@ export default {
resolve();
})).catch;
},
/**
* Select/unselect in Goal Multiselect
* @param value
@@ -209,7 +209,7 @@ export default {
resolve();
})).catch;
},
unselectGoal(value) {
//console.log('----'); console.log('unselect goal', value.id);
getResultByGoal(value.id).then(response => new Promise((resolve, reject) => {
@@ -217,7 +217,7 @@ export default {
resolve();
})).catch;
},
/**
* Select/unselect in Result Multiselect
* @param value
@@ -225,11 +225,11 @@ export default {
selectResult(value) {
//console.log('----'); console.log('select result', value.id);
},
unselectResult(value) {
//console.log('----'); console.log('unselect result', value.id);
},
/**
* Choose parent action will involve retaining the "children" actions.
* @param value
@@ -244,7 +244,7 @@ export default {
}
return [];
},
/**
* Add response elements in data target
* @param target string -> 'actions', 'goals' or 'results'
@@ -264,7 +264,7 @@ export default {
//console.log('push ' + dump.length + ' elems in', target, dump);
}
},
/**
* Remove response elements from data target
* @param target string -> 'actions', 'goals' or 'results'
@@ -279,7 +279,7 @@ export default {
if (found) {
data.options = data.options.filter(e => e.id !== elem.id);
dump.push(elem.id);
this.removeSelectedElement(target, elem);
}
})
@@ -288,7 +288,7 @@ export default {
}
return [ data.options, data.value ];
},
/**
*
* @param target
@@ -300,10 +300,10 @@ export default {
elements.forEach(elem => {
let selected = data.value.some(e => e.id === elem.id);
if (!selected) {
data.value.push(elem);
dump.push(elem.id);
// add in hiddenField
this.rebuildHiddenFieldValues(target);
}
@@ -312,7 +312,7 @@ export default {
//console.log('add ' + dump.length + ' selected elems in', target, dump);
}
},
/**
* Remove element from selected and from hiddenField
* @param target
@@ -322,19 +322,19 @@ export default {
let data = this[target];
let selected = data.value.some(e => e.id === elem.id);
if (selected) {
// remove from selected
data.value = data.value.filter(e => e.id !== elem.id);
//console.log('remove ' + elem.id + ' from selected ' + target);
// remove from hiddenField
this.rebuildHiddenFieldValues(target);
// in any cases, remove should be recursive
this.unselectToNextField(target, elem);
}
},
/**
* When unselect Action, it could remove elements in goals multiselect.
* In that case, we have to unselect Goal to remove elements in results too.
@@ -348,7 +348,7 @@ export default {
//console.log('!!!! done');
}
},
/**
* Rebuild values serie (string) in target HiddenField
* @param target
@@ -362,14 +362,14 @@ export default {
})
//console.log(data.hiddenField);
},
addIdToValue(string, id) {
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
},
transTitle ({ title }) {
return title.fr //TODO multilang
},
@@ -378,4 +378,4 @@ export default {
</script>
<style scoped>
</style>
</style>

View File

@@ -2,12 +2,13 @@ import { createApp } from "vue";
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
import App from './App.vue';
const i18n = _createI18n({});
if (null !== document.getElementById('export_filters_social_work_type_filter_enabled')) {
const i18n = _createI18n({});
const app = createApp({
template: `<app></app>`,
})
.use(i18n)
.component('app', App)
.mount('#export_export')
;
const app = createApp({
template: `<app></app>`,
})
.use(i18n)
.component('app', App)
.mount('#export_export');
}

View File

@@ -78,7 +78,7 @@ class HouseholdVoter extends Voter implements ProvideRoleHierarchyInterface, Chi
return match ($attribute) {
self::SEE => $this->checkAssociatedMembersRole($subject, PersonVoter::SEE),
self::EDIT => $this->checkAssociatedMembersRole($subject, PersonVoter::UPDATE),
self::STATS => $this->voteOnAttribute($attribute, $subject, $token),
self::STATS => $this->helper->voteOnAttribute($attribute, $subject, $token),
default => throw new \UnexpectedValueException('attribute not supported'),
};
}

View File

@@ -55,6 +55,8 @@ class AccompanyingPeriodWorkTest extends TestCase
self::assertNotContains($userA, $work->getReferrers());
self::assertNotContains($userB, $work->getReferrers());
self::assertContains($userC, $work->getReferrers());
self::assertTrue(array_is_list($work->getReferrers()->toArray()));
}
public function testReferrerHistoryOnDifferentDays(): void
@@ -92,5 +94,7 @@ class AccompanyingPeriodWorkTest extends TestCase
self::assertNotFalse($historyA);
self::assertSame($userA, $historyA->getUser());
self::assertEquals((new \DateTimeImmutable())->format('Y-m-d'), $historyA->getEndDate()->format('Y-m-d'));
self::assertTrue(array_is_list($work->getReferrers()->toArray()));
}
}

View File

@@ -0,0 +1,61 @@
<?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\Aggregator\PersonAggregators;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Export\Aggregator\PersonAggregators\PostalCodeAggregator;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class PostalCodeAggregatorTest extends AbstractAggregatorTest
{
private RollingDateConverterInterface $rollingDateConverter;
protected function setUp(): void
{
self::bootKernel();
$this->rollingDateConverter = self::$container->get(RollingDateConverterInterface::class);
}
public function getAggregator()
{
return new PostalCodeAggregator($this->rollingDateConverter);
}
public function getFormData()
{
return [
['calc_date' => new RollingDate(RollingDate::T_TODAY)],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container
->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(person.id)')
->from(Person::class, 'person'),
];
}
}

View File

@@ -0,0 +1,60 @@
<?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 App\Tests\Export\Aggregator\SocialWorkAggregators;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CreatorAggregator;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorAggregatorTest extends AbstractAggregatorTest
{
private CreatorAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get(CreatorAggregator::class);
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData()
{
return [
[],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(acp.id)')
->from(AccompanyingPeriod::class, 'acp')
->join('acp.works', 'acpw'),
];
}
}

View File

@@ -0,0 +1,60 @@
<?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 App\Tests\Export\Aggregator\SocialWorkAggregators;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CreatorJobAggregator;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorJobAggregatorTest extends AbstractAggregatorTest
{
private CreatorJobAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get(CreatorJobAggregator::class);
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData()
{
return [
[],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(acp.id)')
->from(AccompanyingPeriod::class, 'acp')
->join('acp.works', 'acpw'),
];
}
}

View File

@@ -0,0 +1,60 @@
<?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 App\Tests\Export\Aggregator\SocialWorkAggregators;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CreatorScopeAggregator;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorScopeAggregatorTest extends AbstractAggregatorTest
{
private CreatorScopeAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get(CreatorScopeAggregator::class);
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData()
{
return [
[],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(acp.id)')
->from(AccompanyingPeriod::class, 'acp')
->join('acp.works', 'acpw'),
];
}
}

View File

@@ -0,0 +1,53 @@
<?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\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
/**
* @internal
*
* @coversNothing
*/
class AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriodTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$repository = self::$container->get(AccompanyingPeriodWorkRepository::class);
yield new AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod($this->getParameters(true), $repository);
yield new AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod($this->getParameters(false), $repository);
}
public function getFormData()
{
return [];
}
public function getModifiersCombination()
{
return [
[
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
]];
}
}

View File

@@ -0,0 +1,53 @@
<?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\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
/**
* @internal
*
* @coversNothing
*/
class AvgDurationAPWorkPersonAssociatedOnWorkTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$repository = self::$container->get(AccompanyingPeriodWorkRepository::class);
yield new AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod($this->getParameters(true), $repository);
yield new AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod($this->getParameters(false), $repository);
}
public function getFormData()
{
return [];
}
public function getModifiersCombination()
{
return [
[
Declarations::SOCIAL_WORK_ACTION_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
]];
}
}

View File

@@ -13,7 +13,7 @@ namespace Export\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork;
use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
/**
@@ -21,23 +21,19 @@ use Doctrine\ORM\EntityManagerInterface;
*
* @coversNothing
*/
final class CountAccompanyingPeriodWorkTest extends AbstractExportTest
final class CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest extends AbstractExportTest
{
private CountAccompanyingPeriodWork $export;
protected function setUp(): void
{
self::bootKernel();
$this->export = self::$container->get(CountAccompanyingPeriodWork::class);
}
public function getExport()
{
$em = self::$container->get(EntityManagerInterface::class);
yield new CountAccompanyingPeriodWork($em, $this->getParameters(true));
yield new CountAccompanyingPeriodWork($em, $this->getParameters(false));
yield new CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod($em, $this->getParameters(true));
yield new CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod($em, $this->getParameters(false));
}
public function getFormData(): array

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\PersonBundle\Tests\Export\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnWork;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
final class CountAccompanyingPeriodWorkAssociatePersonOnWorkTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$em = self::$container->get(EntityManagerInterface::class);
yield new CountAccompanyingPeriodWorkAssociatePersonOnWork($em, $this->getParameters(true));
yield new CountAccompanyingPeriodWorkAssociatePersonOnwork($em, $this->getParameters(false));
}
public function getFormData(): array
{
return [[]];
}
public function getModifiersCombination()
{
return [[Declarations::SOCIAL_WORK_ACTION_TYPE]];
}
}

View File

@@ -0,0 +1,58 @@
<?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\Export;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\CountHouseholdInPeriod;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CountHouseholdInPeriodTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$em = self::$container->get(EntityManagerInterface::class);
$rollingDate = self::$container->get(RollingDateConverterInterface::class);
yield new CountHouseholdInPeriod($em, $rollingDate, $this->getParameters(true));
yield new CountHouseholdInPeriod($em, $rollingDate, $this->getParameters(false));
}
public function getFormData()
{
return [
['calc_date' => new RollingDate(RollingDate::T_TODAY)],
];
}
public function getModifiersCombination()
{
return [
[
Declarations::HOUSEHOLD_TYPE,
Declarations::ACP_TYPE,
Declarations::PERSON_TYPE,
]];
}
}

View File

@@ -0,0 +1,50 @@
<?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\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnWork;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CountPersonOnAccompanyingPeriodWorkAssociatePersonOnWorkTest extends AbstractExportTest
{
protected function setUp(): void
{
self::bootKernel();
}
public function getExport()
{
$em = self::$container->get(EntityManagerInterface::class);
yield new CountAccompanyingPeriodWorkAssociatePersonOnWork($em, $this->getParameters(true));
yield new CountAccompanyingPeriodWorkAssociatePersonOnWork($em, $this->getParameters(false));
}
public function getFormData()
{
return [[]];
}
public function getModifiersCombination()
{
return [
[Declarations::SOCIAL_WORK_ACTION_TYPE, Declarations::PERSON_TYPE, Declarations::ACP_TYPE],
];
}
}

View File

@@ -0,0 +1,103 @@
<?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\Export;
use Chill\MainBundle\Export\Helper\AggregateStringHelper;
use Chill\MainBundle\Export\Helper\DateTimeHelper;
use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper;
use Chill\MainBundle\Export\Helper\UserHelper;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod;
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
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 Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest extends AbstractExportTest
{
protected function setUp(): void
{
parent::setUp();
self::bootKernel();
}
public function getExport()
{
$entityManager = self::$container->get(EntityManagerInterface::class);
$dateTimeHelper = self::$container->get(DateTimeHelper::class);
$userHelper = self::$container->get(UserHelper::class);
$personHelper = self::$container->get(LabelPersonHelper::class);
$thirdPartyHelper = self::$container->get(LabelThirdPartyHelper::class);
$translatableStringExportLabelHelper = self::$container->get(TranslatableStringExportLabelHelper::class);
$socialIssueRender = self::$container->get(SocialIssueRender::class);
$socialIssueRepository = self::$container->get(SocialIssueRepository::class);
$socialActionRender = self::$container->get(SocialActionRender::class);
$rollingDateConverter = self::$container->get(RollingDateConverterInterface::class);
$aggregateStringHelper = self::$container->get(AggregateStringHelper::class);
$socialActionRepository = self::$container->get(SocialActionRepository::class);
yield new ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod(
$entityManager,
$dateTimeHelper,
$userHelper,
$personHelper,
$thirdPartyHelper,
$translatableStringExportLabelHelper,
$socialIssueRender,
$socialIssueRepository,
$socialActionRender,
$rollingDateConverter,
$aggregateStringHelper,
$socialActionRepository,
$this->getParameters(true),
);
yield new ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod(
$entityManager,
$dateTimeHelper,
$userHelper,
$personHelper,
$thirdPartyHelper,
$translatableStringExportLabelHelper,
$socialIssueRender,
$socialIssueRepository,
$socialActionRender,
$rollingDateConverter,
$aggregateStringHelper,
$socialActionRepository,
$this->getParameters(false),
);
}
public function getFormData()
{
return [
['calc_date' => new RollingDate(RollingDate::T_TODAY)],
];
}
public function getModifiersCombination()
{
return [[Declarations::ACP_TYPE]];
}
}

View File

@@ -19,7 +19,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWork;
use Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnWork;
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
@@ -33,7 +33,7 @@ use Doctrine\ORM\EntityManagerInterface;
*
* @coversNothing
*/
class ListAccompanyingPeriodWorkTest extends AbstractExportTest
class ListAccompanyingPeriodWorkAssociatePersonOnWorkTest extends AbstractExportTest
{
protected function setUp(): void
{
@@ -56,7 +56,7 @@ class ListAccompanyingPeriodWorkTest extends AbstractExportTest
$aggregateStringHelper = self::$container->get(AggregateStringHelper::class);
$socialActionRepository = self::$container->get(SocialActionRepository::class);
yield new ListAccompanyingPeriodWork(
yield new ListAccompanyingPeriodWorkAssociatePersonOnWork(
$entityManager,
$dateTimeHelper,
$userHelper,
@@ -72,7 +72,7 @@ class ListAccompanyingPeriodWorkTest extends AbstractExportTest
$this->getParameters(true),
);
yield new ListAccompanyingPeriodWork(
yield new ListAccompanyingPeriodWorkAssociatePersonOnWork(
$entityManager,
$dateTimeHelper,
$userHelper,

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Export\Filter\AccompanyingCourseFilters;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
@@ -50,7 +51,36 @@ final class SocialActionFilterTest extends AbstractFilterTest
->setMaxResults(1)
->getResult();
yield ['accepted_socialactions' => $array];
return [
[
'accepted_socialactions' => $array,
'start_date_after' => null,
'start_date_before' => null,
'end_date_after' => null,
'end_date_before' => null,
],
[
'accepted_socialactions' => $array,
'start_date_after' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'start_date_before' => new RollingDate(RollingDate::T_TODAY),
'end_date_after' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'end_date_before' => new RollingDate(RollingDate::T_TODAY),
],
[
'accepted_socialactions' => [],
'start_date_after' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'start_date_before' => new RollingDate(RollingDate::T_TODAY),
'end_date_after' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'end_date_before' => new RollingDate(RollingDate::T_TODAY),
],
[
'accepted_socialactions' => [],
'start_date_after' => null,
'start_date_before' => null,
'end_date_after' => null,
'end_date_before' => null,
],
];
}
public function getQueryBuilders(): array

View File

@@ -0,0 +1,70 @@
<?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 App\Tests\Export\Filter\SocialWorkFilters;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Export\Filter\SocialWorkFilters\CreatorFilter;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorFilterTest extends AbstractFilterTest
{
private CreatorFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$this->filter = self::$container->get(CreatorFilter::class);
}
public function getFilter()
{
return $this->filter;
}
public function getFormData()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
$creators = $em->createQuery('SELECT u FROM '.User::class.' u')
->setMaxResults(1)
->getResult();
return [
[
'creators' => $creators,
],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('acpw.id')
->from(AccompanyingPeriodWork::class, 'acpw'),
];
}
}

View File

@@ -0,0 +1,70 @@
<?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 App\Tests\Export\Filter\SocialWorkFilters;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Export\Filter\SocialWorkFilters\CreatorJobFilter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorJobFilterTest extends AbstractFilterTest
{
private CreatorJobFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$this->filter = self::$container->get(CreatorJobFilter::class);
}
public function getFilter()
{
return $this->filter;
}
public function getFormData()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
$jobs = $em->createQuery('SELECT j FROM '.UserJob::class.' j')
->setMaxResults(1)
->getResult();
return [
[
'jobs' => new ArrayCollection($jobs),
],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('acpw.id')
->from(AccompanyingPeriodWork::class, 'acpw'),
];
}
}

View File

@@ -0,0 +1,69 @@
<?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 App\Tests\Export\Filter\SocialWorkFilters;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Export\Filter\SocialWorkFilters\CreatorScopeFilter;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
*
* @coversNothing
*/
class CreatorScopeFilterTest extends AbstractFilterTest
{
private CreatorScopeFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$this->filter = self::$container->get(CreatorScopeFilter::class);
}
public function getFilter()
{
return $this->filter;
}
public function getFormData()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
$scopes = $em->createQuery('SELECT s FROM '.Scope::class.' s')
->setMaxResults(1)
->getResult();
return [
[
'scopes' => $scopes,
],
];
}
public function getQueryBuilders()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('acpw.id')
->from(AccompanyingPeriodWork::class, 'acpw'),
];
}
}

View File

@@ -1,38 +1,30 @@
services:
_defaults:
autoconfigure: true
autowire: true
## Indicators
chill.person.export.count_household:
class: Chill\PersonBundle\Export\Export\CountHousehold
autowire: true
autoconfigure: true
Chill\PersonBundle\Export\Export\CountHouseholdInPeriod:
tags:
- { name: chill.export, alias: count_household }
Chill\PersonBundle\Export\Export\ListHouseholdInPeriod:
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: list_household_in_period }
## Filters
chill.person.export.filter_household_composition:
class: Chill\PersonBundle\Export\Filter\HouseholdFilters\CompositionFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: household_composition_filter }
## Aggregators
chill.person.export.aggregator_household_composition:
class: Chill\PersonBundle\Export\Aggregator\HouseholdAggregators\CompositionAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: household_composition_aggregator }
chill.person.export.aggregator_household_childrennumber:
class: Chill\PersonBundle\Export\Aggregator\HouseholdAggregators\ChildrenNumberAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: household_childrennumber_aggregator }

View File

@@ -173,4 +173,6 @@ services:
tags:
- { name: chill.export_aggregator, alias: person_center_aggregator }
Chill\PersonBundle\Export\Aggregator\PersonAggregators\PostalCodeAggregator:
tags:
- { name: chill.export_aggregator, alias: person_postal_code_aggregator }

View File

@@ -4,14 +4,36 @@ services:
autoconfigure: true
## Indicators
Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork:
Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod:
tags:
# the name is not matching the class name: it is kept for backward compatibility
- { name: chill.export, alias: count_social_work_actions }
Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWork:
Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnWork:
tags:
- { name: chill.export, alias: count_social_work_actions_associate_person_work }
Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod:
tags:
# the name is not matching the class name: it is kept for backward compatibility
- { name: chill.export, alias: list_social_work_actions }
Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnWork:
tags:
- { name: chill.export, alias: list_social_work_actions_associate_person_work }
Chill\PersonBundle\Export\Export\CountPersonOnAccompanyingPeriodWorkAssociatePersonOnWork:
tags:
- { name: chill.export, alias: count_person_on_acwp_associate_person_work }
Chill\PersonBundle\Export\Export\AvgDurationAPWorkPersonAssociatedOnAccompanyingPeriod:
tags:
- { name: chill.export, alias: avg_duration_social_work_actions_person_associated_on_period }
Chill\PersonBundle\Export\Export\AvgDurationAPWorkPersonAssociatedOnWork:
tags:
- { name: chill.export, alias: avg_duration_social_work_actions_person_associated_on_work }
## FILTERS
chill.person.export.filter_social_work_type:
class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\SocialWorkTypeFilter
@@ -45,6 +67,19 @@ services:
tags:
- { name: chill.export_filter, alias: social_work_actions_end_btw_dates_filter }
Chill\PersonBundle\Export\Filter\SocialWorkFilters\CreatorFilter:
tags:
- { name: chill.export_filter, alias: social_work_actions_creator_filter }
Chill\PersonBundle\Export\Filter\SocialWorkFilters\CreatorJobFilter:
tags:
- { name: chill.export_filter, alias: social_work_actions_creator_job_filter }
Chill\PersonBundle\Export\Filter\SocialWorkFilters\CreatorScopeFilter:
tags:
- { name: chill.export_filter, alias: social_work_actions_creator_scope_filter }
## AGGREGATORS
chill.person.export.aggregator_action_type:
class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ActionTypeAggregator
@@ -88,6 +123,18 @@ services:
tags:
- { name: chill.export_aggregator, alias: accompanyingcourse_handling3party_aggregator }
Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CreatorAggregator:
tags:
- { name: chill.export_aggregator, alias: social_work_actions_creator_aggregator }
Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CreatorJobAggregator:
tags:
- { name: chill.export_aggregator, alias: social_work_actions_creator_job_aggregator }
Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CreatorScopeAggregator:
tags:
- { name: chill.export_aggregator, alias: social_work_actions_creator_scope_aggregator }
Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\HandlingThirdPartyFilter:
tags:
- { name: chill.export_filter, alias: 'acpw_handling3party_filter'}

View File

@@ -381,7 +381,8 @@ Closingdate to apply: Date de fin à prendre en compte lorsque le parcours n'est
Exports of social work actions: Exports des actions d'accompagnement
Count social work actions: Nombre d'actions
Count social work actions by various parameters: Compte le nombre d'actions d'accompagnement en fonction de différents filtres.
Average duration of social work actions: Durée moyenne des actions
Calculate the average duration of social work actions: Moyenne de la durée des actions.
Exports of evaluations: Exports des évaluations
Count evaluations: Nombre d'évaluations
@@ -482,9 +483,6 @@ Select a geographical layer: Choisir une couche géographique
Group people by geographical unit based on his address: Grouper les usagers par zone géographique (sur base de l'adresse)
Filter by person's geographical unit (based on address): Filtrer les usagers par zone géographique (sur base de l'adresse)
Filter by socialaction: Filtrer les parcours par action d'accompagnement
Accepted socialactions: Actions d'accompagnement
"Filtered by socialactions: only %socialactions%": "Filtré par action d'accompagnement: uniquement %socialactions%"
Group by social action: Grouper les parcours par action d'accompagnement
Filter by type of action, goals and results: "Filtrer les actions par type, objectif et résultat"
@@ -575,7 +573,7 @@ Group by number of actions: Grouper les parcours par nombre dactions
Filter by creator: Filtrer les parcours par créateur
'Filtered by creator: only %creators%': 'Filtré par créateur: uniquement %creators%'
Filter actions without end date: Filtre les actions sans date de fin (ouvertes)
Filter actions without end date: Filtrer les actions sans date de fin (ouvertes)
Filtered actions without end date: 'Filtré: uniquement les actions sans date de fin (ouvertes)'
Filter by start date evaluations: Filtrer les évaluations par date de début
Filter by end date evaluations: Filtrer les évaluations par date de fin
@@ -1000,6 +998,30 @@ export:
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
count_accompanying_period_work_associate_person:
title: Nombre d'actions, filtres et regroupements sur les usagers du parcours
description: Compte le nombre d'actions d'accompagnement avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements relatifs aux usagers agissent sur les usagers concernés par le parcours de l'action.
header: Nombre d'actions
count_accompanying_period_work_associate_work:
title: Nombre d'actions, filtres et regroupements sur les usagers de l'action
description: Compte le nombre d'actions d'accompagnement avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements relatifs aux usagers agissent sur les usagers concernés par l'action.
header: Nombre d'actions
count_person_on_acpw_associate_person_on_work:
title: Nombre d'usagers concernés par une action d'accompagnement, filtres et regroupements sur les usagers de l'action
description: Compte le nombre d'usager concernés par une action d'accompagnement, avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements relatifs aux usagers agissent sur les usagers concernés par l'action. Si un usager est concerné par plusieurs actions, il n'est comptabilisé qu'une fois.
header: Nombre d'usagers concernés par une action
avg_duration_acpw_associate_on_period:
title: Durée moyenne des actions d'accompagnements, filtres et regroupement sur les usagers du parcours
header: Durée moyenne des actions d'accompagnements (en jours)
description: Calcule la moyenne durée des actions d'accompagnements avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements agissent sur les usagers concernés par le parcours de l'action.
avg_duration_acpw_associate_on_work:
title: Durée moyenne des actions d'accompagnements, filtres et regroupement sur les usagers de l'action
header: Durée moyenne des actions d'accompagnements (en jours)
description: Calcule la moyenne durée des actions d'accompagnements avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements agissent sur les usagers concernés par l'action.
aggregator:
person:
by_household_composition:
@@ -1010,6 +1032,10 @@ export:
title: Grouper les usagers par centre
at_date: Date de calcul du centre
center: Centre de l'usager
by_postal_code:
title: Grouper les usagers par code postal de l'adresse
at_date: Date de calcul de l'adresse
header: Code postal
course:
by_referrer:
@@ -1069,6 +1095,15 @@ export:
by_handling_third_party:
title: Grouper les actions par tiers traitant
header: Tiers traitant
by_creator:
title: Grouper les actions par créateur
Creator: Créateur de l'action
by_creator_job:
title: Grouper les actions par métier du créateur
Creator's job: Métier du créateur
by_creator_scope:
title: Grouper les actions par service du créateur
Creator's scope: Service du créateur
eval:
by_end_date:
@@ -1155,17 +1190,31 @@ export:
by_user_job:
Filter by user job: Filtrer les parcours par métier du référent
"Filtered by user job: only %job%": "Filtré par métier du référent: uniquement %job%"
by_social_action:
title: Filtrer les parcours par action d'accompagnement
Accepted socialactions: Actions d'accompagnement
accepted socialations help: Si laissé vide, tous les types d'action seront pris en compte
"Filtered by socialactions: only %socialactions%": "Filtré par action d'accompagnement: uniquement %socialactions%, date d'ouverture après le %start_date_after%, et avant le %start_date_before%, date de fermeture après le %end_date_after% et avant le %end_date_before%"
start date after: Date de début de l'action après le
start date after help: Sera ignoré si laissé vide
start date before: Date de début de l'action avant le
start date before help: Sera ignoré si laissé vide
end date after: Date de fin de l'action après le
end date after help: Sera ignoré si laissé vide. Les actions sans date de fin seront toujours prises en compte.
end date before: Date de fin de l'action avant le
end date before help: Sera ignoré si laissé vide. Les actions sans date de fin seront toujours prises en compte.
date ignored: clause de date ignorée
work:
start_between_dates:
title: Filtre les actions d'accompagnement dont la date d'ouverture est entre deux dates
title: Filtrer les actions dont la date d'ouverture est entre deux dates
start_date: Date de début
end_date: Date de fin
keep_null: Conserver les actions dont la date de début n'est pas indiquée
keep_null_help: Si coché, les actions dont la date de début est vide seront prises en compte. Si non coché, elles ne seront pas comptabilisée.
Only where start date is between %startDate% and %endDate%: Seulement les actions dont la date de début est entre le %startDate% et le %endDate%
end_between_dates:
title: Filtre les actions d'accompagnement dont la date de clotûre est entre deux dates (ou l'action est toujours ouverte)
title: Filtrer les actions dont la date de clotûre est entre deux dates (ou l'action est toujours ouverte)
start_date: Date de début
end_date: Date de fin
keep_null: Conserver les actions dont la date de fin n'est pas indiquée (actions en cours)
@@ -1189,6 +1238,16 @@ export:
title: Filtrer les actions par tiers traitant
Only 3 parties %3parties%: "Seulement les actions d'accompagnement qui ont pour tiers traitant: %3parties%"
pick_3parties: Tiers traitants des actions
by_creator:
title: Filtrer les actions par créateur
Creators: Créateur de l'action
"Filtered by creator: only %creators%": "Filtré par créateur de l'action: uniquement %creators%"
by_creator_job:
title: Filtrer les actions par métier du créateur
"Filtered by creator job: only %jobs%": "Filtré par métier du créateur: uniquement %jobs%"
by_creator_scope:
title: Filtrer les actions par service du créateur
"Filtered by creator scope: only %scopes%": "Filtré par service du créateur: uniquement %scopes%"
list:
person_with_acp:
@@ -1268,6 +1327,14 @@ export:
updatedBy: Modifié par
timeSpent: Temps de rédaction (minutes)
acpw_associate_work:
List of accompanying period works: Liste des actions, filtres sur les usagers de l'action
List description: Compte le nombre d'actions d'accompagnement avec des filtres possibles sur les usagers, les parcours et les actions. Les filtres et regroupements agissent sur les usagers concernés par l'action.
acpw_associate_period:
List of accompanying period works: Liste des actions, filtres sur les usagers du parcours
List description: Génère une liste des actions d'accompagnement, avec des filtres possibles sur les usagers, les parcours et les actions. Les filtres des usagers agissent sur les usagers concernés par le parcours de l'action.
acpw:
List of accompanying period works: Liste des actions
List description: Génère une liste des actions d'accompagnement, filtrée sur différents paramètres.