mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-10 16:55:00 +00:00
Compare commits
78 Commits
2.10.6
...
226-upgrad
Author | SHA1 | Date | |
---|---|---|---|
b19a1ba53b
|
|||
3d4c439be4 | |||
4727a57825
|
|||
5f441eb5ac
|
|||
2e4e5ee79a
|
|||
1467c708f2 | |||
170bb9586d
|
|||
c704ffa379 | |||
947b7b90e2
|
|||
992f7761bb
|
|||
35170e1f7c
|
|||
7132dfa3f6 | |||
7e09e0ea54 | |||
ccf8cc4d6e | |||
63124f8f92
|
|||
75d80ebd98 | |||
0ea6f36297 | |||
975ea417b7 | |||
af8e02f76b | |||
cbaeb3d7e8 | |||
f609ddb315 | |||
d0bceb59dc
|
|||
2883e085ed
|
|||
b05ed86d1e
|
|||
c855d0badc | |||
be57c96a2f | |||
eb01c7c203
|
|||
53b4747697
|
|||
89e19502d3
|
|||
ff344dbb0c
|
|||
8719b4dedd | |||
d8fa743bc9
|
|||
eaa40d6725
|
|||
1f47f157ea
|
|||
5ab0d3f8da
|
|||
98fd5cae78 | |||
2bb29242e4 | |||
e6cab938c8
|
|||
f5f4d8fcdd
|
|||
e9df26c2f7
|
|||
af6bee2497
|
|||
af585bada3
|
|||
f9763b866d | |||
7f18a2fb7d | |||
3cdad6caff | |||
200ab836c7 | |||
3e39c0ced7 | |||
83c3621c26 | |||
b790e2fcf1 | |||
fde6000d0b | |||
3892d1e877 | |||
6944773868 | |||
d5bc9d10d5 | |||
3743b336a6 | |||
3332413fe0 | |||
86e659edd4
|
|||
2e60ba3137
|
|||
1663c6f7c7
|
|||
d01b6db5dc
|
|||
847c8238e8
|
|||
2cc5fa06ae
|
|||
0d741ab886
|
|||
9cb794fef2 | |||
fd03855ee6 | |||
ac9897d9e7
|
|||
88469dbe8e
|
|||
cbc83c0e63
|
|||
27012d842d
|
|||
4112e59af4
|
|||
1b0a30baf8 | |||
9673b369ef
|
|||
43966c4d5a
|
|||
c9f438319c
|
|||
58b45c6f1b
|
|||
f756c0d71e | |||
bb1602934c
|
|||
83fe3ec3fc
|
|||
abebb79e8b
|
5
.changes/unreleased/Fixed-20231127-210138.yaml
Normal file
5
.changes/unreleased/Fixed-20231127-210138.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: 'Export: fix list person with custom fields'
|
||||||
|
time: 2023-11-27T21:01:38.260730706+01:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
6
.changes/v2.11.0.md
Normal file
6
.changes/v2.11.0.md
Normal 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
26
.changes/v2.12.0.md
Normal 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
3
.changes/v2.12.1.md
Normal 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"
|
9
.changes/v2.13.0.md
Normal file
9
.changes/v2.13.0.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## v2.13.0 - 2023-11-21
|
||||||
|
### Feature
|
||||||
|
* ([#173](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/173)) Allow user to add a phonenumber to their profile which will be included in automatically generated documents
|
||||||
|
### Fixed
|
||||||
|
* ([#211](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/211)) Export: fix loading of "Group activity by type"
|
||||||
|
* ([#190](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/190)) Export: fix loading of "group activity by reasons"
|
||||||
|
* ([#213](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/213)) Export: fix usage of some Collection returned instead of array in export filters
|
||||||
|
* ([#215](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/215)) Use only the string 'both' for gender (with a database migration)
|
||||||
|
* ([#212](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/212)) Clean the database to make working the "Group people by gender" aggregator
|
8
.changes/v2.14.0.md
Normal file
8
.changes/v2.14.0.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## v2.14.0 - 2023-11-24
|
||||||
|
### Feature
|
||||||
|
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
|
||||||
|
### Fixed
|
||||||
|
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
|
||||||
|
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
|
||||||
|
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
|
||||||
|
* Fix various errors in custom fields administration
|
@@ -11,6 +11,10 @@ cache:
|
|||||||
services:
|
services:
|
||||||
- name: postgis/postgis:14-3.3-alpine
|
- name: postgis/postgis:14-3.3-alpine
|
||||||
alias: db
|
alias: db
|
||||||
|
command:
|
||||||
|
- postgres
|
||||||
|
- "-c"
|
||||||
|
- max_connections=1000
|
||||||
- name: redis
|
- name: redis
|
||||||
alias: redis
|
alias: redis
|
||||||
|
|
||||||
@@ -108,8 +112,6 @@ rector_tests:
|
|||||||
# - tests/app/vendor/
|
# - tests/app/vendor/
|
||||||
|
|
||||||
unit_tests:
|
unit_tests:
|
||||||
# temporarily allow failure due to problem with timezone
|
|
||||||
allow_failure: true
|
|
||||||
stage: Tests
|
stage: Tests
|
||||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
||||||
script:
|
script:
|
||||||
|
57
CHANGELOG.md
57
CHANGELOG.md
@@ -6,6 +6,63 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|||||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||||
|
|
||||||
|
|
||||||
|
## v2.14.0 - 2023-11-24
|
||||||
|
### Feature
|
||||||
|
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
|
||||||
|
### Fixed
|
||||||
|
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
|
||||||
|
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
|
||||||
|
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
|
||||||
|
* Fix various errors in custom fields administration
|
||||||
|
|
||||||
|
## v2.13.0 - 2023-11-21
|
||||||
|
### Feature
|
||||||
|
* ([#173](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/173)) Allow user to add a phonenumber to their profile which will be included in automatically generated documents
|
||||||
|
### Fixed
|
||||||
|
* ([#211](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/211)) Export: fix loading of "Group activity by type"
|
||||||
|
* ([#190](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/190)) Export: fix loading of "group activity by reasons"
|
||||||
|
* ([#213](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/213)) Export: fix usage of some Collection returned instead of array in export filters
|
||||||
|
* ([#215](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/215)) Use only the string 'both' for gender (with a database migration)
|
||||||
|
* ([#212](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/212)) Clean the database to make working the "Group people by gender" aggregator
|
||||||
|
|
||||||
|
## 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"
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
## 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
|
## v2.10.6 - 2023-11-07
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
|
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
|
||||||
|
@@ -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:
|
Chill offers the possibility to:
|
||||||
|
|
||||||
* authenticate users using Microsoft Graph, with relatively small adaptations;
|
* 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>`_).
|
* 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
|
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:
|
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_BASE_URL=https://test.chill.be # must be
|
||||||
SAML_ENTITY_ID=https://test.chill.be # must match the one entered
|
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::
|
.. note::
|
||||||
|
|
||||||
Two flows are in use:
|
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.
|
* 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 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`);
|
* 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`)
|
* 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.
|
* 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.
|
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:
|
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
|
bin/console chill:calendar:msgraph-user-map-subscribe
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 166 KiB |
@@ -15,7 +15,7 @@
|
|||||||
"@symfony/webpack-encore": "^4.1.0",
|
"@symfony/webpack-encore": "^4.1.0",
|
||||||
"@tsconfig/node14": "^1.0.1",
|
"@tsconfig/node14": "^1.0.1",
|
||||||
"bindings": "^1.5.0",
|
"bindings": "^1.5.0",
|
||||||
"bootstrap": "^5.0.1",
|
"bootstrap": "^5.3.0",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"fork-awesome": "^1.1.7",
|
"fork-awesome": "^1.1.7",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -56,20 +56,15 @@ class ActivityTypeAggregator implements AggregatorInterface
|
|||||||
|
|
||||||
public function getLabels($key, array $values, $data): \Closure
|
public function getLabels($key, array $values, $data): \Closure
|
||||||
{
|
{
|
||||||
// for performance reason, we load data from db only once
|
return function (null|int|string $value): string {
|
||||||
$this->activityTypeRepository->findBy(['id' => $values]);
|
|
||||||
|
|
||||||
return function ($value): string {
|
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'Activity type';
|
return 'Activity type';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value || '' === $value) {
|
if (null === $value || '' === $value || null === $t = $this->activityTypeRepository->find($value)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$t = $this->activityTypeRepository->find($value);
|
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize($t->getName());
|
return $this->translatableStringHelper->localize($t->getName());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -14,18 +14,18 @@ namespace Chill\ActivityBundle\Export\Aggregator;
|
|||||||
use Chill\ActivityBundle\Export\Declarations;
|
use Chill\ActivityBundle\Export\Declarations;
|
||||||
use Chill\MainBundle\Entity\User\UserJobHistory;
|
use Chill\MainBundle\Entity\User\UserJobHistory;
|
||||||
use Chill\MainBundle\Export\AggregatorInterface;
|
use Chill\MainBundle\Export\AggregatorInterface;
|
||||||
use Chill\MainBundle\Repository\ScopeRepository;
|
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
use Doctrine\ORM\Query\Expr\Join;
|
use Doctrine\ORM\Query\Expr\Join;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
class JobScopeAggregator implements AggregatorInterface
|
class CreatorJobAggregator implements AggregatorInterface
|
||||||
{
|
{
|
||||||
private const PREFIX = 'acp_agg_creator_job';
|
private const PREFIX = 'acp_agg_creator_job';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly ScopeRepository $scopeRepository,
|
private readonly UserJobRepositoryInterface $userJobRepository,
|
||||||
private readonly TranslatableStringHelper $translatableStringHelper
|
private readonly TranslatableStringHelper $translatableStringHelper
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -76,17 +76,15 @@ class JobScopeAggregator implements AggregatorInterface
|
|||||||
{
|
{
|
||||||
return function ($value): string {
|
return function ($value): string {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'Scope';
|
return 'Job';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value || '' === $value) {
|
if (null === $value || '' === $value || null === $s = $this->userJobRepository->find($value)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$s = $this->scopeRepository->find($value);
|
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize(
|
return $this->translatableStringHelper->localize(
|
||||||
$s->getName()
|
$s->getLabel()
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
@@ -99,12 +99,6 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
|
|||||||
|
|
||||||
public function getLabels($key, array $values, $data)
|
public function getLabels($key, array $values, $data)
|
||||||
{
|
{
|
||||||
match ($data['level']) {
|
|
||||||
'reasons' => $this->activityReasonRepository->findBy(['id' => $values]),
|
|
||||||
'categories' => $this->activityReasonCategoryRepository->findBy(['id' => $values]),
|
|
||||||
default => throw new \RuntimeException(sprintf("The level data '%s' is invalid.", $data['level'])),
|
|
||||||
};
|
|
||||||
|
|
||||||
return function ($value) use ($data) {
|
return function ($value) use ($data) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason';
|
return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason';
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
@@ -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'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -12,7 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
|
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
|
||||||
|
|
||||||
use Chill\ActivityBundle\Entity\Activity;
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
use Chill\ActivityBundle\Export\Aggregator\JobScopeAggregator;
|
use Chill\ActivityBundle\Export\Aggregator\CreatorJobAggregator;
|
||||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
@@ -21,15 +21,15 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
*
|
*
|
||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
final class JobScopeAggregatorTest extends AbstractAggregatorTest
|
final class CreatorJobAggregatorTest extends AbstractAggregatorTest
|
||||||
{
|
{
|
||||||
private JobScopeAggregator $aggregator;
|
private CreatorJobAggregator $aggregator;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
self::bootKernel();
|
self::bootKernel();
|
||||||
|
|
||||||
$this->aggregator = self::$container->get(JobScopeAggregator::class);
|
$this->aggregator = self::$container->get(CreatorJobAggregator::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAggregator()
|
public function getAggregator()
|
@@ -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'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -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,
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
}
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
@@ -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'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,10 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export, alias: 'list_activity_linked_to_person' }
|
- { 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:
|
chill.activity.export.count_activity_linked_to_acp:
|
||||||
class: Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity
|
class: Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity
|
||||||
tags:
|
tags:
|
||||||
@@ -115,6 +119,10 @@ services:
|
|||||||
# affect all saved exports (unless we write a migration for that)
|
# affect all saved exports (unless we write a migration for that)
|
||||||
- { name: chill.export_filter, alias: 'activity_userscope_filter' }
|
- { 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:
|
Chill\ActivityBundle\Export\Filter\UsersJobFilter:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_filter, alias: 'activity_usersjob_filter' }
|
- { name: chill.export_filter, alias: 'activity_usersjob_filter' }
|
||||||
@@ -131,6 +139,11 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export_filter, alias: 'period_having_activity_betw_dates_filter' }
|
- { 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
|
## Aggregators
|
||||||
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator:
|
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator:
|
||||||
tags:
|
tags:
|
||||||
@@ -179,7 +192,7 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_creator_scope_aggregator }
|
- { name: chill.export_aggregator, alias: activity_creator_scope_aggregator }
|
||||||
|
|
||||||
Chill\ActivityBundle\Export\Aggregator\JobScopeAggregator:
|
Chill\ActivityBundle\Export\Aggregator\CreatorJobAggregator:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_creator_job_aggregator }
|
- { name: chill.export_aggregator, alias: activity_creator_job_aggregator }
|
||||||
|
|
||||||
@@ -214,3 +227,11 @@ services:
|
|||||||
Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityTypeAggregator:
|
Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityTypeAggregator:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: acp_by_activity_type_aggregator }
|
- { 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 }
|
||||||
|
@@ -332,6 +332,11 @@ docgen:
|
|||||||
myWorksOnly: Prendre en compte uniquement les actions d'accompagnement dont je suis référent
|
myWorksOnly: Prendre en compte uniquement les actions d'accompagnement dont je suis référent
|
||||||
|
|
||||||
export:
|
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:
|
list:
|
||||||
activity:
|
activity:
|
||||||
users name: Nom des utilisateurs
|
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
|
date mismatch: La date de fin de la période doit être supérieure à la date du début
|
||||||
by_creator_scope:
|
by_creator_scope:
|
||||||
Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange
|
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:
|
by_persons:
|
||||||
Filter activity by persons: Filtrer les échanges par usager participant
|
Filter activity by persons: Filtrer les échanges par usager participant
|
||||||
'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%'
|
'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
|
Sent or received: Envoyé ou reçu
|
||||||
is sent: envoyé
|
is sent: envoyé
|
||||||
is received: reçu
|
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:
|
aggregator:
|
||||||
|
person:
|
||||||
|
by_person:
|
||||||
|
title: Grouper les échanges par usager (dossier d'usager dans lequel l'échange est enregistré)
|
||||||
|
person: Usager
|
||||||
acp:
|
acp:
|
||||||
by_activity_type:
|
by_activity_type:
|
||||||
title: Grouper les parcours par type d'échange
|
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
|
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
|
Calc date: Date de calcul du service du créateur de l'échange
|
||||||
by_creator_job:
|
by_creator_job:
|
||||||
Group activity by creator job: Grouper les échanges par 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 service du créateur de l'échange
|
Calc date: Date de calcul du métier du créateur de l'échange
|
||||||
by_persons:
|
by_persons:
|
||||||
Group activity by persons: Grouper les échanges par usager participant
|
Group activity by persons: Grouper les échanges par usager participant
|
||||||
Persons: Usagers participants
|
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:
|
generic_doc:
|
||||||
filter:
|
filter:
|
||||||
|
@@ -356,20 +356,6 @@ final class CalendarSyncerTest extends TestCase
|
|||||||
}
|
}
|
||||||
JSON;
|
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
|
public function testHandleAttendeesConfirmingCalendar(): void
|
||||||
{
|
{
|
||||||
$machineHttpClient = new MockHttpClient([
|
$machineHttpClient = new MockHttpClient([
|
||||||
|
@@ -30,7 +30,7 @@ class CustomFieldController extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* Creates a new CustomField entity.
|
* Creates a new CustomField entity.
|
||||||
*
|
*
|
||||||
* @Route("/{_locale}/admin/customfield/new", name="customfield_new")
|
* @Route("/{_locale}/admin/customfield/new", name="customfield_create")
|
||||||
*/
|
*/
|
||||||
public function createAction(Request $request)
|
public function createAction(Request $request)
|
||||||
{
|
{
|
||||||
|
@@ -232,7 +232,7 @@ class CustomFieldsGroupController extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* Finds and displays a CustomFieldsGroup entity.
|
* Finds and displays a CustomFieldsGroup entity.
|
||||||
*
|
*
|
||||||
* @Route("/{_locale}/admin/customfieldsgroup/{id}/show", name="customfieldsgroup/show")
|
* @Route("/{_locale}/admin/customfieldsgroup/{id}/show", name="customfieldsgroup_show")
|
||||||
*/
|
*/
|
||||||
public function showAction(mixed $id)
|
public function showAction(mixed $id)
|
||||||
{
|
{
|
||||||
@@ -256,7 +256,7 @@ class CustomFieldsGroupController extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* Edits an existing CustomFieldsGroup entity.
|
* Edits an existing CustomFieldsGroup entity.
|
||||||
*
|
*
|
||||||
* @Route("/{_locale}/admin/customfieldsgroup/{id}/update", name="customfieldsgroup/update")
|
* @Route("/{_locale}/admin/customfieldsgroup/{id}/update", name="customfieldsgroup_update")
|
||||||
*/
|
*/
|
||||||
public function updateAction(Request $request, mixed $id)
|
public function updateAction(Request $request, mixed $id)
|
||||||
{
|
{
|
||||||
@@ -383,7 +383,7 @@ class CustomFieldsGroupController extends AbstractController
|
|||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$customFieldsGroupIds = $em->createQuery('SELECT g.id FROM '
|
$customFieldsGroupIds = $em->createQuery('SELECT g.id FROM '
|
||||||
.'ChillCustomFieldsBundle:CustomFieldsDefaultGroup d '
|
.CustomFieldsDefaultGroup::class.' d '
|
||||||
.'JOIN d.customFieldsGroup g')
|
.'JOIN d.customFieldsGroup g')
|
||||||
->getResult(Query::HYDRATE_SCALAR);
|
->getResult(Query::HYDRATE_SCALAR);
|
||||||
|
|
||||||
|
@@ -280,7 +280,7 @@ class CustomFieldChoice extends AbstractCustomField
|
|||||||
$template = '@ChillCustomFields/CustomFieldsRendering/choice.html.twig';
|
$template = '@ChillCustomFields/CustomFieldsRendering/choice.html.twig';
|
||||||
|
|
||||||
if ('csv' === $documentType) {
|
if ('csv' === $documentType) {
|
||||||
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.csv.twig';
|
$template = '@ChillCustomFields/CustomFieldsRendering/choice.csv.twig';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->templating
|
return $this->templating
|
||||||
|
@@ -68,7 +68,7 @@ class CustomFieldDate extends AbstractCustomField
|
|||||||
{
|
{
|
||||||
$validatorFunction = static function ($value, ExecutionContextInterface $context) {
|
$validatorFunction = static function ($value, ExecutionContextInterface $context) {
|
||||||
try {
|
try {
|
||||||
$date = new \DateTime($value);
|
$date = new \DateTime((string) $value);
|
||||||
} catch (\Exception) {
|
} catch (\Exception) {
|
||||||
$context->buildViolation('The expression "%expression%" is invalid', [
|
$context->buildViolation('The expression "%expression%" is invalid', [
|
||||||
'%expression%' => $value,
|
'%expression%' => $value,
|
||||||
@@ -125,7 +125,7 @@ class CustomFieldDate extends AbstractCustomField
|
|||||||
return $date->format('Y-m-d');
|
return $date->format('Y-m-d');
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:date.'
|
$template = '@ChillCustomFields/CustomFieldsRendering/date.'
|
||||||
.$documentType.'.twig';
|
.$documentType.'.twig';
|
||||||
|
|
||||||
return $this->templating
|
return $this->templating
|
||||||
|
@@ -96,7 +96,7 @@ class CustomFieldLongChoice extends AbstractCustomField
|
|||||||
public function render($value, CustomField $customField, $documentType = 'html')
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
{
|
{
|
||||||
$option = $this->deserialize($value, $customField);
|
$option = $this->deserialize($value, $customField);
|
||||||
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice_long.'
|
$template = '@ChillCustomFields/CustomFieldsRendering/choice_long.'
|
||||||
.$documentType.'.twig';
|
.$documentType.'.twig';
|
||||||
|
|
||||||
return $this->templating
|
return $this->templating
|
||||||
|
@@ -95,7 +95,7 @@ class CustomFieldNumber extends AbstractCustomField
|
|||||||
|
|
||||||
public function render($value, CustomField $customField, $documentType = 'html')
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
{
|
{
|
||||||
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:number.'
|
$template = '@ChillCustomFields/CustomFieldsRendering/number.'
|
||||||
.$documentType.'.twig';
|
.$documentType.'.twig';
|
||||||
$options = $customField->getOptions();
|
$options = $customField->getOptions();
|
||||||
|
|
||||||
|
@@ -89,7 +89,7 @@ class CustomFieldText extends AbstractCustomField
|
|||||||
$template = '@ChillCustomFields/CustomFieldsRendering/text.html.twig';
|
$template = '@ChillCustomFields/CustomFieldsRendering/text.html.twig';
|
||||||
|
|
||||||
if ('csv' === $documentType) {
|
if ('csv' === $documentType) {
|
||||||
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.csv.twig';
|
$template = '@ChillCustomFields/CustomFieldsRendering/text.csv.twig';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->templating
|
return $this->templating
|
||||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\CustomFieldsBundle\Form;
|
namespace Chill\CustomFieldsBundle\Form;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer;
|
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer;
|
||||||
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
||||||
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
@@ -45,7 +46,7 @@ class CustomFieldType extends AbstractType
|
|||||||
|
|
||||||
if ('entity' === $options['group_widget']) {
|
if ('entity' === $options['group_widget']) {
|
||||||
$builder->add('customFieldsGroup', EntityType::class, [
|
$builder->add('customFieldsGroup', EntityType::class, [
|
||||||
'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup',
|
'class' => CustomFieldsGroup::class,
|
||||||
'choice_label' => fn ($g) => $this->translatableStringHelper->localize($g->getName()),
|
'choice_label' => fn ($g) => $this->translatableStringHelper->localize($g->getName()),
|
||||||
]);
|
]);
|
||||||
} elseif ('hidden' === $options['group_widget']) {
|
} elseif ('hidden' === $options['group_widget']) {
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
Chill\CustomFieldsBundle\Controller\:
|
Chill\CustomFieldsBundle\Controller\:
|
||||||
resource: '../../Controller'
|
resource: '../../Controller'
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
@@ -11,14 +11,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\DocGeneratorBundle\Serializer\Helper;
|
namespace Chill\DocGeneratorBundle\Serializer\Helper;
|
||||||
|
|
||||||
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
use Symfony\Component\Serializer\Mapping\ClassMetadataInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
class NormalizeNullValueHelper
|
class NormalizeNullValueHelper
|
||||||
{
|
{
|
||||||
public function __construct(private readonly NormalizerInterface $normalizer, private readonly ?string $discriminatorType = null, private readonly ?string $discriminatorValue = null) {}
|
public function __construct(private readonly NormalizerInterface $normalizer, private readonly ?string $discriminatorType = null, private readonly ?string $discriminatorValue = null) {}
|
||||||
|
|
||||||
public function normalize(array $attributes, string $format = 'docgen', ?array $context = [], ClassMetadata $classMetadata = null)
|
public function normalize(array $attributes, string $format = 'docgen', ?array $context = [], ClassMetadataInterface $classMetadata = null)
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
$data['isNull'] = true;
|
$data['isNull'] = true;
|
||||||
@@ -44,7 +44,7 @@ class NormalizeNullValueHelper
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getContextForAttribute(string $key, array $initialContext, ?ClassMetadata $classMetadata): array
|
private function getContextForAttribute(string $key, array $initialContext, ?ClassMetadataInterface $classMetadata): array
|
||||||
{
|
{
|
||||||
if (null === $classMetadata) {
|
if (null === $classMetadata) {
|
||||||
return $initialContext;
|
return $initialContext;
|
||||||
|
@@ -19,6 +19,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessor;
|
|||||||
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||||
use Symfony\Component\Serializer\Exception\LogicException;
|
use Symfony\Component\Serializer\Exception\LogicException;
|
||||||
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
|
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
|
||||||
|
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
||||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
@@ -52,12 +53,15 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
$metadata = $this->classMetadataFactory->getMetadataFor($classMetadataKey);
|
$metadata = $this->classMetadataFactory->getMetadataFor($classMetadataKey);
|
||||||
|
if (!$metadata instanceof ClassMetadata) {
|
||||||
|
throw new \LogicException('ClassMetadata should be the only one implementation for ClassMetadataInterface. See https://github.com/symfony/symfony/pull/17114');
|
||||||
|
}
|
||||||
$expectedGroups = \array_key_exists(AbstractNormalizer::GROUPS, $context) ?
|
$expectedGroups = \array_key_exists(AbstractNormalizer::GROUPS, $context) ?
|
||||||
\is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]]
|
\is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]]
|
||||||
: [];
|
: [];
|
||||||
$attributes = \array_filter(
|
$attributes = \array_filter(
|
||||||
$metadata->getAttributesMetadata(),
|
$metadata->getAttributesMetadata(),
|
||||||
static function (AttributeMetadata $a) use ($expectedGroups) {
|
static function (AttributeMetadataInterface $a) use ($expectedGroups) {
|
||||||
foreach ($a->getGroups() as $g) {
|
foreach ($a->getGroups() as $g) {
|
||||||
if (\in_array($g, $expectedGroups, true)) {
|
if (\in_array($g, $expectedGroups, true)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -119,7 +123,7 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte
|
|||||||
return $type->getName();
|
return $type->getName();
|
||||||
}
|
}
|
||||||
if ($type instanceof \ReflectionIntersectionType) {
|
if ($type instanceof \ReflectionIntersectionType) {
|
||||||
foreach (array_map(fn (\ReflectionNamedType $t) => $t->getName(), $type->getTypes()) as $classString) {
|
foreach (array_map(fn (\ReflectionType $t) => $t->getName(), $type->getTypes()) as $classString) {
|
||||||
if (ReadableCollection::class === $classString) {
|
if (ReadableCollection::class === $classString) {
|
||||||
return ReadableCollection::class;
|
return ReadableCollection::class;
|
||||||
}
|
}
|
||||||
@@ -211,7 +215,7 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|AttributeMetadata[] $attributes
|
* @param array<AttributeMetadata> $attributes
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
|
@@ -304,7 +304,7 @@ class ExportController extends AbstractController
|
|||||||
FormType::class,
|
FormType::class,
|
||||||
$defaultFormData,
|
$defaultFormData,
|
||||||
[
|
[
|
||||||
'method' => $isGenerate ? 'GET' : 'POST',
|
'method' => $isGenerate ? Request::METHOD_GET : Request::METHOD_POST,
|
||||||
'csrf_protection' => !$isGenerate,
|
'csrf_protection' => !$isGenerate,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -352,7 +352,7 @@ class ExportController extends AbstractController
|
|||||||
|
|
||||||
$form = $this->createCreateFormExport($alias, 'export', $data, $savedExport);
|
$form = $this->createCreateFormExport($alias, 'export', $data, $savedExport);
|
||||||
|
|
||||||
if ('POST' === $request->getMethod()) {
|
if (Request::METHOD_POST === $request->getMethod()) {
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
@@ -406,7 +406,7 @@ class ExportController extends AbstractController
|
|||||||
|
|
||||||
$form = $this->createCreateFormExport($alias, 'formatter', $data, $savedExport);
|
$form = $this->createCreateFormExport($alias, 'formatter', $data, $savedExport);
|
||||||
|
|
||||||
if ('POST' === $request->getMethod()) {
|
if (Request::METHOD_POST === $request->getMethod()) {
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
@@ -536,7 +536,7 @@ class ExportController extends AbstractController
|
|||||||
|
|
||||||
$form = $this->createCreateFormExport($alias, 'centers', [], $savedExport);
|
$form = $this->createCreateFormExport($alias, 'centers', [], $savedExport);
|
||||||
|
|
||||||
if ('POST' === $request->getMethod()) {
|
if (Request::METHOD_POST === $request->getMethod()) {
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
|
@@ -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\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Form\UserPhonenumberType;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class UserProfileController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User profile that allows editing of phonenumber and visualization of certain data.
|
||||||
|
*
|
||||||
|
* @Route("/{_locale}/main/user/my-profile", name="chill_main_user_profile")
|
||||||
|
*/
|
||||||
|
public function __invoke(Request $request)
|
||||||
|
{
|
||||||
|
$user = $this->getUser();
|
||||||
|
$editForm = $this->createPhonenumberEditForm($user);
|
||||||
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
|
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||||
|
$phonenumber = $editForm->get('phonenumber')->getData();
|
||||||
|
|
||||||
|
$user->setPhonenumber($phonenumber);
|
||||||
|
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
$this->addFlash('success', $this->translator->trans('user.profile.Phonenumber successfully updated!'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('chill_main_user_profile');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('@ChillMain/User/profile.html.twig', [
|
||||||
|
'user' => $user,
|
||||||
|
'form' => $editForm->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createPhonenumberEditForm(UserInterface $user): FormInterface
|
||||||
|
{
|
||||||
|
return $this->createForm(
|
||||||
|
UserPhonenumberType::class,
|
||||||
|
$user,
|
||||||
|
)
|
||||||
|
->add('submit', SubmitType::class, ['label' => $this->translator->trans('Save')]);
|
||||||
|
}
|
||||||
|
}
|
@@ -18,9 +18,11 @@ use Doctrine\Common\Collections\Collection;
|
|||||||
use Doctrine\Common\Collections\Criteria;
|
use Doctrine\Common\Collections\Criteria;
|
||||||
use Doctrine\Common\Collections\Selectable;
|
use Doctrine\Common\Collections\Selectable;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
|
use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User.
|
* User.
|
||||||
@@ -161,6 +163,15 @@ class User implements UserInterface, \Stringable
|
|||||||
*/
|
*/
|
||||||
private ?string $usernameCanonical = null;
|
private ?string $usernameCanonical = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's mobile phone number.
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="phone_number", nullable=true)
|
||||||
|
*
|
||||||
|
* @PhonenumberConstraint()
|
||||||
|
*/
|
||||||
|
private ?PhoneNumber $phonenumber = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User constructor.
|
* User constructor.
|
||||||
*/
|
*/
|
||||||
@@ -419,6 +430,11 @@ class User implements UserInterface, \Stringable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPhonenumber(): ?PhoneNumber
|
||||||
|
{
|
||||||
|
return $this->phonenumber;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \RuntimeException if the groupCenter is not in the collection
|
* @throws \RuntimeException if the groupCenter is not in the collection
|
||||||
*/
|
*/
|
||||||
@@ -639,4 +655,11 @@ class User implements UserInterface, \Stringable
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setPhonenumber(?PhoneNumber $phonenumber): self
|
||||||
|
{
|
||||||
|
$this->phonenumber = $phonenumber;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,9 +37,13 @@ class RollingDateDataMapper implements DataMapperInterface
|
|||||||
{
|
{
|
||||||
$forms = iterator_to_array($forms);
|
$forms = iterator_to_array($forms);
|
||||||
|
|
||||||
$viewData = new RollingDate(
|
if (null === $forms['roll']->getData()) {
|
||||||
$forms['roll']->getData() ?? RollingDate::T_TODAY,
|
$viewData = null;
|
||||||
$forms['fixedDate']->getData()
|
} else {
|
||||||
);
|
$viewData = new RollingDate(
|
||||||
|
$forms['roll']->getData(),
|
||||||
|
$forms['fixedDate']->getData()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,7 @@ class PickRollingDateType extends AbstractType
|
|||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'class' => RollingDate::class,
|
'class' => RollingDate::class,
|
||||||
'empty_data' => new RollingDate(RollingDate::T_TODAY),
|
'empty_data' => null,
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
new Callback($this->validate(...)),
|
new Callback($this->validate(...)),
|
||||||
],
|
],
|
||||||
@@ -66,6 +66,10 @@ class PickRollingDateType extends AbstractType
|
|||||||
|
|
||||||
public function validate($data, ExecutionContextInterface $context, $payload): void
|
public function validate($data, ExecutionContextInterface $context, $payload): void
|
||||||
{
|
{
|
||||||
|
if (null === $data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/** @var RollingDate $data */
|
/** @var RollingDate $data */
|
||||||
if (RollingDate::T_FIXED_DATE === $data->getRoll() && null === $data->getFixedDate()) {
|
if (RollingDate::T_FIXED_DATE === $data->getRoll() && null === $data->getFixedDate()) {
|
||||||
$context
|
$context
|
||||||
|
36
src/Bundle/ChillMainBundle/Form/UserPhonenumberType.php
Normal file
36
src/Bundle/ChillMainBundle/Form/UserPhonenumberType.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Form;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class UserPhonenumberType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('phonenumber', ChillPhoneNumberType::class, [
|
||||||
|
'required' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => User::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Location;
|
|||||||
use Chill\MainBundle\Entity\Scope;
|
use Chill\MainBundle\Entity\Scope;
|
||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
|
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||||
use Chill\MainBundle\Form\Type\PickCivilityType;
|
use Chill\MainBundle\Form\Type\PickCivilityType;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
@@ -44,6 +45,9 @@ class UserType extends AbstractType
|
|||||||
->add('email', EmailType::class, [
|
->add('email', EmailType::class, [
|
||||||
'required' => true,
|
'required' => true,
|
||||||
])
|
])
|
||||||
|
->add('phonenumber', ChillPhoneNumberType::class, [
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
->add('label', TextType::class)
|
->add('label', TextType::class)
|
||||||
->add('civility', PickCivilityType::class, [
|
->add('civility', PickCivilityType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
@@ -12,14 +12,15 @@ declare(strict_types=1);
|
|||||||
namespace Chill\MainBundle\Repository;
|
namespace Chill\MainBundle\Repository;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
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);
|
$this->repository = $em->getRepository(UserJob::class);
|
||||||
}
|
}
|
||||||
@@ -42,6 +43,15 @@ class UserJobRepository implements UserJobRepositoryInterface
|
|||||||
return $this->repository->findBy(['active' => true]);
|
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 $limit
|
||||||
* @param mixed|null $offset
|
* @param mixed|null $offset
|
||||||
|
@@ -28,6 +28,13 @@ interface UserJobRepositoryInterface extends ObjectRepository
|
|||||||
*/
|
*/
|
||||||
public function findAllActive(): array;
|
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 $limit
|
||||||
* @param mixed|null $offset
|
* @param mixed|null $offset
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
// 3. Include remainder of required Bootstrap stylesheets
|
// 3. Include remainder of required Bootstrap stylesheets
|
||||||
@import "bootstrap/scss/variables";
|
@import "bootstrap/scss/variables";
|
||||||
|
@import "bootstrap/scss/variables-dark";
|
||||||
|
|
||||||
// 4. Include any default map overrides here
|
// 4. Include any default map overrides here
|
||||||
@import "custom/_maps";
|
@import "custom/_maps";
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import {ShowHide} from 'ChillMainAssets/lib/show_hide/index';
|
import {ShowHide} from 'ChillMainAssets/lib/show_hide/index';
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function(_e) {
|
document.addEventListener('DOMContentLoaded', function(_e) {
|
||||||
console.log('pick-rolling-date');
|
|
||||||
document.querySelectorAll('div[data-rolling-date]').forEach( (picker) => {
|
document.querySelectorAll('div[data-rolling-date]').forEach( (picker) => {
|
||||||
const
|
const
|
||||||
roll_wrapper = picker.querySelector('div.roll-wrapper'),
|
roll_wrapper = picker.querySelector('div.roll-wrapper'),
|
||||||
@@ -11,12 +10,8 @@ document.addEventListener('DOMContentLoaded', function(_e) {
|
|||||||
froms: [roll_wrapper],
|
froms: [roll_wrapper],
|
||||||
container: [fixed_wrapper],
|
container: [fixed_wrapper],
|
||||||
test: function (elems) {
|
test: function (elems) {
|
||||||
console.log('testing');
|
|
||||||
console.log('elems', elems);
|
|
||||||
for (let el of elems) {
|
for (let el of elems) {
|
||||||
for (let select_roll of el.querySelectorAll('select[data-roll-picker]')) {
|
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';
|
return select_roll.value === 'fixed_date';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,9 +28,7 @@
|
|||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||||
{{ encore_entry_script_tags('page_export') }}
|
{{ encore_entry_script_tags('page_export') }}
|
||||||
{% if export_alias == 'count_social_work_actions' %}
|
{{ encore_entry_script_tags('vue_export_action_goal_result') }}
|
||||||
{{ encore_entry_script_tags('vue_export_action_goal_result') }}
|
|
||||||
{% endif %}
|
|
||||||
{{ encore_entry_script_tags('mod_pick_rolling_date') }}
|
{{ encore_entry_script_tags('mod_pick_rolling_date') }}
|
||||||
{% endblock js %}
|
{% endblock js %}
|
||||||
|
|
||||||
|
@@ -0,0 +1,58 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
|
||||||
|
|
||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}{{"My profile"|trans}}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="justify-content-center col-10">
|
||||||
|
<h1>{{ 'user.profile.title'|trans }}</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>{{ 'Job'|trans }}</dt>
|
||||||
|
{% if user.getUserJob is not null %}
|
||||||
|
<dd>{{ user.getUserJob.label|localize_translatable_string }}</dd>
|
||||||
|
{% else %}
|
||||||
|
<dd class="chill-no-data-statement">{{ 'user.profile.no job'|trans }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{{ 'Scope'|trans }}</dt>
|
||||||
|
{% if user.getMainScope is not null %}
|
||||||
|
<dd>{{ user.getMainScope.name|localize_translatable_string }}</dd>
|
||||||
|
{% else %}
|
||||||
|
<dd class="chill-no-data-statement">{{ 'user.profile.no scope'|trans }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
<div>
|
||||||
|
{{ form_start(form) }}
|
||||||
|
{{ form_row(form.phonenumber) }}
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr': { 'class': 'btn btn-save' } } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@@ -29,6 +29,14 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
$user = $this->security->getUser();
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
if ($user instanceof User) {
|
if ($user instanceof User) {
|
||||||
|
$menu->addChild($this->translator->trans('user.profile.title'), [
|
||||||
|
'route' => 'chill_main_user_profile',
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => -11_111_111,
|
||||||
|
'icon' => 'user',
|
||||||
|
]);
|
||||||
|
|
||||||
if (null !== $user->getCurrentLocation()) {
|
if (null !== $user->getCurrentLocation()) {
|
||||||
$locationTextMenu = $user->getCurrentLocation()->getName();
|
$locationTextMenu = $user->getCurrentLocation()->getName();
|
||||||
} else {
|
} else {
|
||||||
|
@@ -18,6 +18,7 @@ use Chill\MainBundle\Entity\Scope;
|
|||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||||
@@ -34,6 +35,7 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
|
|||||||
'text_without_absent' => '',
|
'text_without_absent' => '',
|
||||||
'label' => '',
|
'label' => '',
|
||||||
'email' => '',
|
'email' => '',
|
||||||
|
'isAbsent' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(private readonly UserRender $userRender) {}
|
public function __construct(private readonly UserRender $userRender) {}
|
||||||
@@ -61,9 +63,13 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
|
|||||||
$context,
|
$context,
|
||||||
['docgen:expects' => Civility::class, 'groups' => 'docgen:read']
|
['docgen:expects' => Civility::class, 'groups' => 'docgen:read']
|
||||||
);
|
);
|
||||||
|
$phonenumberContext = array_merge(
|
||||||
|
$context,
|
||||||
|
['docgen:expects' => PhoneNumber::class, 'groups' => 'docgen:read']
|
||||||
|
);
|
||||||
|
|
||||||
if (null === $object && 'docgen' === $format) {
|
if (null === $object && 'docgen' === $format) {
|
||||||
return [...self::NULL_USER, 'civility' => $this->normalizer->normalize(null, $format, $civilityContext), 'user_job' => $this->normalizer->normalize(null, $format, $userJobContext), 'main_center' => $this->normalizer->normalize(null, $format, $centerContext), 'main_scope' => $this->normalizer->normalize(null, $format, $scopeContext), 'current_location' => $this->normalizer->normalize(null, $format, $locationContext), 'main_location' => $this->normalizer->normalize(null, $format, $locationContext)];
|
return [...self::NULL_USER, 'phonenumber' => $this->normalizer->normalize(null, $format, $phonenumberContext), 'civility' => $this->normalizer->normalize(null, $format, $civilityContext), 'user_job' => $this->normalizer->normalize(null, $format, $userJobContext), 'main_center' => $this->normalizer->normalize(null, $format, $centerContext), 'main_scope' => $this->normalizer->normalize(null, $format, $scopeContext), 'current_location' => $this->normalizer->normalize(null, $format, $locationContext), 'main_location' => $this->normalizer->normalize(null, $format, $locationContext)];
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@@ -74,6 +80,7 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
|
|||||||
'text_without_absent' => $this->userRender->renderString($object, ['absence' => false]),
|
'text_without_absent' => $this->userRender->renderString($object, ['absence' => false]),
|
||||||
'label' => $object->getLabel(),
|
'label' => $object->getLabel(),
|
||||||
'email' => (string) $object->getEmail(),
|
'email' => (string) $object->getEmail(),
|
||||||
|
'phonenumber' => $this->normalizer->normalize($object->getPhonenumber(), $format, $phonenumberContext),
|
||||||
'user_job' => $this->normalizer->normalize($object->getUserJob(), $format, $userJobContext),
|
'user_job' => $this->normalizer->normalize($object->getUserJob(), $format, $userJobContext),
|
||||||
'main_center' => $this->normalizer->normalize($object->getMainCenter(), $format, $centerContext),
|
'main_center' => $this->normalizer->normalize($object->getMainCenter(), $format, $centerContext),
|
||||||
'main_scope' => $this->normalizer->normalize($object->getMainScope(), $format, $scopeContext),
|
'main_scope' => $this->normalizer->normalize($object->getMainScope(), $format, $scopeContext),
|
||||||
|
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
final class UserProfileControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
use PrepareClientTrait;
|
||||||
|
|
||||||
|
public function testPage()
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request('GET', '/fr/main/user/my-profile');
|
||||||
|
$this->assertResponseIsSuccessful('Request GET /main/user/my-profile was successful');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,140 @@
|
|||||||
|
<?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 Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Entity\Civility;
|
||||||
|
use Chill\MainBundle\Entity\Location;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
|
use Chill\MainBundle\Serializer\Normalizer\UserNormalizer;
|
||||||
|
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||||
|
use libphonenumber\NumberParseException;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
|
use libphonenumber\PhoneNumberUtil;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Prophecy\Argument;
|
||||||
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
|
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
final class UserNormalizerTest extends TestCase
|
||||||
|
{
|
||||||
|
use ProphecyTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NumberParseException
|
||||||
|
*/
|
||||||
|
public function dataProviderUserNormalizer()
|
||||||
|
{
|
||||||
|
$user = new User();
|
||||||
|
$userNoPhone = new User();
|
||||||
|
|
||||||
|
$user
|
||||||
|
->setUsername('SomeUser')
|
||||||
|
->setLabel('SomeUser')
|
||||||
|
->setPhonenumber(PhoneNumberUtil::getInstance()->parse('+32475928635'))
|
||||||
|
->setEmail('some.user@chill.com');
|
||||||
|
|
||||||
|
$userNoPhone
|
||||||
|
->setUsername('AnotherUser')
|
||||||
|
->setLabel('AnotherUser');
|
||||||
|
|
||||||
|
yield [$user, 'docgen', ['docgen:expects' => User::class],
|
||||||
|
[
|
||||||
|
'id' => $user->getId(), // id
|
||||||
|
'type' => 'user', // type
|
||||||
|
'username' => 'SomeUser', // username
|
||||||
|
'email' => 'some.user@chill.com', // email
|
||||||
|
'text' => 'SomeUser', // text
|
||||||
|
'label' => 'SomeUser', // label
|
||||||
|
'phonenumber' => ['context' => PhoneNumber::class], // phonenumber
|
||||||
|
'main_scope' => ['context' => Scope::class], // scope
|
||||||
|
'user_job' => ['context' => UserJob::class], // user job
|
||||||
|
'current_location' => ['context' => Location::class], // curent location
|
||||||
|
'main_location' => ['context' => Location::class], // main location
|
||||||
|
'civility' => ['context' => Civility::class], // civility
|
||||||
|
'text_without_absent' => 'SomeUser',
|
||||||
|
'isAbsent' => false,
|
||||||
|
'main_center' => ['context' => Center::class],
|
||||||
|
]];
|
||||||
|
|
||||||
|
yield [$userNoPhone, 'docgen', ['docgen:expects' => User::class],
|
||||||
|
[
|
||||||
|
'id' => $user->getId(), // id
|
||||||
|
'type' => 'user', // type
|
||||||
|
'username' => 'AnotherUser', // username
|
||||||
|
'email' => '', // email
|
||||||
|
'text' => 'AnotherUser', // text
|
||||||
|
'label' => 'AnotherUser', // label
|
||||||
|
'phonenumber' => ['context' => PhoneNumber::class], // phonenumber
|
||||||
|
'main_scope' => ['context' => Scope::class], // scope
|
||||||
|
'user_job' => ['context' => UserJob::class], // user job
|
||||||
|
'current_location' => ['context' => Location::class], // curent location
|
||||||
|
'main_location' => ['context' => Location::class], // main location
|
||||||
|
'civility' => ['context' => Civility::class], // civility
|
||||||
|
'text_without_absent' => 'AnotherUser',
|
||||||
|
'isAbsent' => false,
|
||||||
|
'main_center' => ['context' => Center::class],
|
||||||
|
]];
|
||||||
|
|
||||||
|
yield [null, 'docgen', ['docgen:expects' => User::class], [
|
||||||
|
'id' => '', // id
|
||||||
|
'type' => 'user', // type
|
||||||
|
'username' => '', // username
|
||||||
|
'email' => '', // email
|
||||||
|
'text' => '', // text
|
||||||
|
'label' => '', // label
|
||||||
|
'phonenumber' => ['context' => PhoneNumber::class], // phonenumber
|
||||||
|
'main_scope' => ['context' => Scope::class], // scope
|
||||||
|
'user_job' => ['context' => UserJob::class], // user job
|
||||||
|
'current_location' => ['context' => Location::class], // curent location
|
||||||
|
'main_location' => ['context' => Location::class], // main location
|
||||||
|
'civility' => ['context' => Civility::class], // civility
|
||||||
|
'text_without_absent' => '',
|
||||||
|
'isAbsent' => false,
|
||||||
|
'main_center' => ['context' => Center::class],
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataProviderUserNormalizer
|
||||||
|
*
|
||||||
|
* @throws ExceptionInterface
|
||||||
|
*/
|
||||||
|
public function testNormalize(null|User $user, mixed $format, mixed $context, mixed $expected)
|
||||||
|
{
|
||||||
|
$userRender = $this->prophesize(UserRender::class);
|
||||||
|
$userRender->renderString(Argument::type(User::class), Argument::type('array'))->willReturn($user ? $user->getLabel() : '');
|
||||||
|
|
||||||
|
$normalizer = new UserNormalizer($userRender->reveal());
|
||||||
|
$normalizer->setNormalizer(new class () implements NormalizerInterface {
|
||||||
|
public function normalize($object, string $format = null, array $context = [])
|
||||||
|
{
|
||||||
|
return ['context' => $context['docgen:expects'] ?? null];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsNormalization($data, string $format = null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $normalizer->normalize($user, $format, $context));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
<?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\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add phonenumber to user profile.
|
||||||
|
*/
|
||||||
|
final class Version20231020075524 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add phonenumber to user profile';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE users ADD phonenumber VARCHAR(35) DEFAULT NULL');
|
||||||
|
$this->addSql('COMMENT ON COLUMN users.phonenumber IS \'(DC2Type:phone_number)\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE users DROP phonenumber');
|
||||||
|
}
|
||||||
|
}
|
@@ -44,6 +44,13 @@ address_fields: Données liées à l'adresse
|
|||||||
Datas: Données
|
Datas: Données
|
||||||
No title: Aucun titre
|
No title: Aucun titre
|
||||||
|
|
||||||
|
user:
|
||||||
|
profile:
|
||||||
|
title: Mon profil
|
||||||
|
Phonenumber successfully updated!: Numéro de téléphone mis à jour!
|
||||||
|
no job: Pas de métier assigné
|
||||||
|
no scope: Pas de cercle assigné
|
||||||
|
|
||||||
inactive: inactif
|
inactive: inactif
|
||||||
|
|
||||||
Edit: Modifier
|
Edit: Modifier
|
||||||
|
@@ -39,6 +39,13 @@ Last updated by: Laatste update door
|
|||||||
on: "op "
|
on: "op "
|
||||||
Last updated on: Laatste update op
|
Last updated on: Laatste update op
|
||||||
by_user: "door "
|
by_user: "door "
|
||||||
|
lifecycleUpdate: Updates en creatie gebeurtenissen
|
||||||
|
address_fields: Gegevens gelinked aan het adres
|
||||||
|
Datas: Gegevens
|
||||||
|
No title: Geen titel
|
||||||
|
User profile: Mijn gebruikersprofiel
|
||||||
|
Phonenumber successfully updated!: Telefoonnummer bijgewerkt!
|
||||||
|
|
||||||
|
|
||||||
Edit: Bewerken
|
Edit: Bewerken
|
||||||
Update: Updaten
|
Update: Updaten
|
||||||
|
@@ -392,9 +392,13 @@ class AccompanyingPeriodWork implements AccompanyingPeriodLinkedWithSocialIssues
|
|||||||
*/
|
*/
|
||||||
public function getReferrers(): ReadableCollection
|
public function getReferrers(): ReadableCollection
|
||||||
{
|
{
|
||||||
return $this->referrersHistory
|
$users = $this->referrersHistory
|
||||||
->filter(fn (AccompanyingPeriodWorkReferrerHistory $h) => null === $h->getEndDate())
|
->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
|
public function getReferrersHistory(): Collection
|
||||||
|
@@ -83,7 +83,12 @@ final readonly class GeographicalUnitStatAggregator implements AggregatorInterfa
|
|||||||
'acp_geog_units'
|
'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']);
|
$qb->setParameter('acp_geog_unit_layer', $data['level']);
|
||||||
|
|
||||||
|
@@ -19,11 +19,10 @@ use Chill\PersonBundle\Export\Declarations;
|
|||||||
use Doctrine\ORM\Query\Expr;
|
use Doctrine\ORM\Query\Expr;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
|
|
||||||
class ChildrenNumberAggregator implements AggregatorInterface
|
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
|
public function addRole(): ?string
|
||||||
{
|
{
|
||||||
@@ -71,7 +70,7 @@ class ChildrenNumberAggregator implements AggregatorInterface
|
|||||||
|
|
||||||
public function getLabels($key, array $values, $data)
|
public function getLabels($key, array $values, $data)
|
||||||
{
|
{
|
||||||
return static function ($value): string {
|
return static function (null|int|string $value): string {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'Number of children';
|
return 'Number of children';
|
||||||
}
|
}
|
||||||
@@ -80,7 +79,7 @@ class ChildrenNumberAggregator implements AggregatorInterface
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return (string) $value;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
@@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -25,7 +25,7 @@ use Doctrine\ORM\QueryBuilder;
|
|||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInterface
|
class CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod implements ExportInterface, GroupedExportInterface
|
||||||
{
|
{
|
||||||
private readonly bool $filterStatsByCenters;
|
private readonly bool $filterStatsByCenters;
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter
|
|||||||
|
|
||||||
public function getDescription(): string
|
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
|
public function getGroup(): string
|
||||||
@@ -68,7 +68,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter
|
|||||||
}
|
}
|
||||||
|
|
||||||
$labels = array_combine($values, $values);
|
$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];
|
return static fn ($value) => $labels[$value];
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter
|
|||||||
|
|
||||||
public function getTitle(): string
|
public function getTitle(): string
|
||||||
{
|
{
|
||||||
return 'Count social work actions';
|
return 'export.export.count_accompanying_period_work_associate_person.title';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getType(): string
|
public function getType(): string
|
@@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -26,7 +26,7 @@ use Doctrine\ORM\Query;
|
|||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
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 const TR_PREFIX = 'export.export.nb_household_with_course.';
|
||||||
private readonly bool $filterStatsByCenters;
|
private readonly bool $filterStatsByCenters;
|
||||||
@@ -120,6 +120,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface
|
|||||||
->join('person.accompanyingPeriodParticipations', 'acppart')
|
->join('person.accompanyingPeriodParticipations', 'acppart')
|
||||||
->join('acppart.accompanyingPeriod', 'acp')
|
->join('acppart.accompanyingPeriod', 'acp')
|
||||||
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL')
|
->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']));
|
->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date']));
|
||||||
|
|
||||||
$qb
|
$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);
|
->setParameter('authorized_centers', $centers);
|
||||||
}
|
}
|
||||||
|
|
@@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -47,7 +47,7 @@ use Doctrine\ORM\QueryBuilder;
|
|||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterface
|
class ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
||||||
{
|
{
|
||||||
private const FIELDS = [
|
private const FIELDS = [
|
||||||
'id',
|
'id',
|
||||||
@@ -121,7 +121,7 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
|
|||||||
|
|
||||||
public function getDescription(): string
|
public function getDescription(): string
|
||||||
{
|
{
|
||||||
return 'export.list.acpw.List description';
|
return 'export.list.acpw_associate_period.List description';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getGroup(): string
|
public function getGroup(): string
|
||||||
@@ -190,12 +190,12 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
|
|||||||
|
|
||||||
public function getResult($query, $data)
|
public function getResult($query, $data)
|
||||||
{
|
{
|
||||||
return dump($query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR));
|
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitle(): string
|
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
|
public function getType(): string
|
||||||
@@ -206,6 +206,7 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
|
|||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
|
$calcDate = $data['calc_date'] ?? new RollingDate(RollingDate::T_TODAY);
|
||||||
|
|
||||||
$qb = $this->entityManager->createQueryBuilder();
|
$qb = $this->entityManager->createQueryBuilder();
|
||||||
|
|
||||||
@@ -220,7 +221,7 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
|
|||||||
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL')
|
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL')
|
||||||
// get participants at the given date
|
// get participants at the given date
|
||||||
->andWhere('acppart.startDate <= :calc_date AND (acppart.endDate > :calc_date OR acppart.endDate IS NULL)')
|
->andWhere('acppart.startDate <= :calc_date AND (acppart.endDate > :calc_date OR acppart.endDate IS NULL)')
|
||||||
->setParameter('calc_date', $this->rollingDateConverter->convert($data['calc_date']));
|
->setParameter('calc_date', $this->rollingDateConverter->convert($calcDate));
|
||||||
|
|
||||||
if ($this->filterStatsByCenters) {
|
if ($this->filterStatsByCenters) {
|
||||||
$qb
|
$qb
|
||||||
@@ -236,7 +237,7 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac
|
|||||||
|
|
||||||
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
|
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
|
||||||
|
|
||||||
$this->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date']));
|
$this->addSelectClauses($qb, $this->rollingDateConverter->convert($calcDate));
|
||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
}
|
}
|
@@ -0,0 +1,349 @@
|
|||||||
|
<?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);
|
||||||
|
$calcDate = $data['calc_date'] ?? new RollingDate(RollingDate::T_TODAY);
|
||||||
|
|
||||||
|
$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($calcDate));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@@ -332,13 +332,18 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
|
|||||||
if (null === $value) {
|
if (null === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$decoded = json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);
|
|
||||||
|
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
$label = $cfType->getChoices($cf)[$slugChoice];
|
$label = $cfType->getChoices($cf)[$slugChoice];
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize($cf->getName())
|
return $this->translatableStringHelper->localize($cf->getName())
|
||||||
.' | '.$label;
|
.' | '.$label;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$decoded = json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
} catch (\JsonException $e) {
|
||||||
|
throw new \RuntimeException(sprintf('unable to decode json: %s, %s', json_last_error(), json_last_error_msg()), $e->getCode(), $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('_other' === $slugChoice && $cfType->isChecked($cf, $slugChoice, $decoded)) {
|
if ('_other' === $slugChoice && $cfType->isChecked($cf, $slugChoice, $decoded)) {
|
||||||
|
@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\User;
|
|||||||
use Chill\MainBundle\Export\FilterInterface;
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
@@ -59,7 +60,13 @@ class CreatorFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'Filtered by creator: only %creators%', [
|
'Filtered by creator: only %creators%', [
|
||||||
'%creators%' => implode(', ', array_map(static fn (User $u) => $u->getLabel(), $data['accepted_creators'])),
|
'%creators%' => implode(
|
||||||
|
', ',
|
||||||
|
array_map(
|
||||||
|
static fn (User $u) => $u->getLabel(),
|
||||||
|
$data['accepted_creators'] instanceof Collection ? $data['accepted_creators']->toArray() : $data['accepted_creators']
|
||||||
|
)
|
||||||
|
),
|
||||||
], ];
|
], ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
|||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
|
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -68,7 +69,10 @@ class GeographicalUnitStatFilter implements FilterInterface
|
|||||||
'acp_geog_filter_date',
|
'acp_geog_filter_date',
|
||||||
$this->rollingDateConverter->convert($data['date_calc'])
|
$this->rollingDateConverter->convert($data['date_calc'])
|
||||||
)
|
)
|
||||||
->setParameter('acp_geog_filter_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units']));
|
->setParameter('acp_geog_filter_units', array_map(
|
||||||
|
static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id,
|
||||||
|
$data['units'] instanceof Collection ? $data['units']->toArray() : $data['units']
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyOn(): string
|
public function applyOn(): string
|
||||||
|
@@ -16,6 +16,7 @@ use Chill\PersonBundle\Export\Declarations;
|
|||||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
|
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
|
||||||
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
|
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
@@ -52,7 +53,10 @@ final readonly class HandlingThirdPartyFilter implements FilterInterface
|
|||||||
[
|
[
|
||||||
'%3parties%' => implode(
|
'%3parties%' => implode(
|
||||||
', ',
|
', ',
|
||||||
array_map(fn (ThirdParty $thirdParty) => $this->thirdPartyRender->renderString($thirdParty, []), $data['handling_3parties'])
|
array_map(
|
||||||
|
fn (ThirdParty $thirdParty) => $this->thirdPartyRender->renderString($thirdParty, []),
|
||||||
|
$data['handling_3parties'] instanceof Collection ? $data['handling_3parties']->toArray() : $data['handling_3parties']
|
||||||
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@@ -21,6 +21,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
|||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -115,7 +116,7 @@ readonly class JobWorkingOnCourseFilter implements FilterInterface
|
|||||||
', ',
|
', ',
|
||||||
array_map(
|
array_map(
|
||||||
fn (UserJob $userJob) => $this->translatableStringHelper->localize($userJob->getLabel()),
|
fn (UserJob $userJob) => $this->translatableStringHelper->localize($userJob->getLabel()),
|
||||||
$data['jobs']
|
$data['jobs'] instanceof Collection ? $data['jobs']->toArray() : $data['jobs']
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'%start_date%' => $this->rollingDateConverter->convert($data['start_date'])?->format('d-m-Y'),
|
'%start_date%' => $this->rollingDateConverter->convert($data['start_date'])?->format('d-m-Y'),
|
||||||
|
@@ -21,6 +21,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
|||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -110,7 +111,7 @@ readonly class ScopeWorkingOnCourseFilter implements FilterInterface
|
|||||||
', ',
|
', ',
|
||||||
array_map(
|
array_map(
|
||||||
fn (Scope $scope) => $this->translatableStringHelper->localize($scope->getName()),
|
fn (Scope $scope) => $this->translatableStringHelper->localize($scope->getName()),
|
||||||
$data['scopes']
|
$data['scopes'] instanceof Collection ? $data['scopes']->toArray() : $data['scopes']
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'%start_date%' => $this->rollingDateConverter->convert($data['start_date'])?->format('d-m-Y'),
|
'%start_date%' => $this->rollingDateConverter->convert($data['start_date'])?->format('d-m-Y'),
|
||||||
|
@@ -12,6 +12,8 @@ declare(strict_types=1);
|
|||||||
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
|
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
|
||||||
|
|
||||||
use Chill\MainBundle\Export\FilterInterface;
|
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\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
@@ -19,10 +21,17 @@ use Chill\PersonBundle\Form\Type\PickSocialActionType;
|
|||||||
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
final readonly class SocialActionFilter implements FilterInterface
|
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
|
public function addRole(): ?string
|
||||||
{
|
{
|
||||||
@@ -31,17 +40,40 @@ final readonly class SocialActionFilter implements FilterInterface
|
|||||||
|
|
||||||
public function alterQuery(QueryBuilder $qb, $data)
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
{
|
{
|
||||||
$qb->andWhere(
|
$p = self::PREFIX;
|
||||||
$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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$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
|
public function applyOn(): string
|
||||||
@@ -51,14 +83,44 @@ final readonly class SocialActionFilter implements FilterInterface
|
|||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder)
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
{
|
{
|
||||||
$builder->add('accepted_socialactions', PickSocialActionType::class, [
|
$builder
|
||||||
'multiple' => true,
|
->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
|
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
|
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),
|
'%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
|
public function getTitle(): string
|
||||||
{
|
{
|
||||||
return 'Filter by socialaction';
|
return 'export.filter.course.by_social_action.title';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDate;
|
|||||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -98,7 +99,10 @@ class StepFilterBetweenDates implements FilterInterface
|
|||||||
|
|
||||||
public function describeAction($data, $format = 'string')
|
public function describeAction($data, $format = 'string')
|
||||||
{
|
{
|
||||||
$steps = array_map(fn (string $step) => $this->translator->trans(array_flip(self::STEPS)[$step]), $data['accepted_steps_multi']);
|
$steps = array_map(
|
||||||
|
fn (string $step) => $this->translator->trans(array_flip(self::STEPS)[$step]),
|
||||||
|
$data['accepted_steps_multi'] instanceof Collection ? $data['accepted_steps_multi']->toArray() : $data['accepted_steps_multi']
|
||||||
|
);
|
||||||
|
|
||||||
return ['export.filter.course.by_step.Filtered by steps: only %step% and between %date_from% and %date_to%', [
|
return ['export.filter.course.by_step.Filtered by steps: only %step% and between %date_from% and %date_to%', [
|
||||||
'%step%' => implode(', ', $steps),
|
'%step%' => implode(', ', $steps),
|
||||||
|
@@ -17,6 +17,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDate;
|
|||||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -101,7 +102,10 @@ class StepFilterOnDate implements FilterInterface
|
|||||||
|
|
||||||
public function describeAction($data, $format = 'string')
|
public function describeAction($data, $format = 'string')
|
||||||
{
|
{
|
||||||
$steps = array_map(fn (string $step) => $this->translator->trans(array_flip(self::STEPS)[$step]), $data['accepted_steps_multi']);
|
$steps = array_map(
|
||||||
|
fn (string $step) => $this->translator->trans(array_flip(self::STEPS)[$step]),
|
||||||
|
$data['accepted_steps_multi'] instanceof Collection ? $data['accepted_steps_multi']->toArray() : $data['accepted_steps_multi']
|
||||||
|
);
|
||||||
|
|
||||||
return ['Filtered by steps: only %step%', [
|
return ['Filtered by steps: only %step%', [
|
||||||
'%step%' => implode(', ', $steps),
|
'%step%' => implode(', ', $steps),
|
||||||
|
@@ -20,6 +20,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
|||||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ final readonly class UserWorkingOnCourseFilter implements FilterInterface
|
|||||||
', ',
|
', ',
|
||||||
array_map(
|
array_map(
|
||||||
fn (User $u) => $this->userRender->renderString($u, []),
|
fn (User $u) => $this->userRender->renderString($u, []),
|
||||||
$data['users']
|
$data['users'] instanceof Collection ? $data['users']->toArray() : $data['users']
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'%start_date%' => $this->rollingDateConverter->convert($data['start_date'])?->format('d-m-Y'),
|
'%start_date%' => $this->rollingDateConverter->convert($data['start_date'])?->format('d-m-Y'),
|
||||||
|
@@ -21,6 +21,7 @@ use Chill\PersonBundle\Entity\Household\HouseholdCompositionType;
|
|||||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface;
|
use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\DBAL\Types\Types;
|
use Doctrine\DBAL\Types\Types;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
@@ -84,7 +85,7 @@ class ByHouseholdCompositionFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
$compos = array_map(
|
$compos = array_map(
|
||||||
fn (HouseholdCompositionType $compositionType) => $this->translatableStringHelper->localize($compositionType->getLabel()),
|
fn (HouseholdCompositionType $compositionType) => $this->translatableStringHelper->localize($compositionType->getLabel()),
|
||||||
$data['compositions']->toArray()
|
$data['compositions'] instanceof Collection ? $data['compositions']->toArray() : $data['compositions']
|
||||||
);
|
);
|
||||||
|
|
||||||
return ['export.filter.person.by_composition.Filtered by composition at %date%: only %compositions%', [
|
return ['export.filter.person.by_composition.Filtered by composition at %date%: only %compositions%', [
|
||||||
|
@@ -77,6 +77,7 @@ class GenderFilter implements
|
|||||||
'Woman' => Person::FEMALE_GENDER,
|
'Woman' => Person::FEMALE_GENDER,
|
||||||
'Man' => Person::MALE_GENDER,
|
'Man' => Person::MALE_GENDER,
|
||||||
'Both' => Person::BOTH_GENDER,
|
'Both' => Person::BOTH_GENDER,
|
||||||
|
'Unknown' => Person::NO_INFORMATION,
|
||||||
'Not given' => 'null',
|
'Not given' => 'null',
|
||||||
],
|
],
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
|
@@ -20,6 +20,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
|||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
|
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -102,7 +103,7 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface
|
|||||||
', ',
|
', ',
|
||||||
array_map(
|
array_map(
|
||||||
fn (SimpleGeographicalUnitDTO $item) => $this->translatableStringHelper->localize($this->geographicalUnitLayerRepository->find($item->layerId)->getName()).' > '.$item->unitName,
|
fn (SimpleGeographicalUnitDTO $item) => $this->translatableStringHelper->localize($this->geographicalUnitLayerRepository->find($item->layerId)->getName()).' > '.$item->unitName,
|
||||||
$data['units']
|
$data['units'] instanceof Collection ? $data['units']->toArray() : $data['units']
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@@ -54,7 +54,7 @@ final readonly class AccompanyingPeriodWorkEndDateBetweenDateFilter implements F
|
|||||||
public function describeAction($data, $format = 'string'): array
|
public function describeAction($data, $format = 'string'): array
|
||||||
{
|
{
|
||||||
return [
|
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') : '',
|
'%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') : '',
|
'%endDate%' => null !== $data['end_date'] ? $this->rollingDateConverter->convert($data['end_date'])->format('d-m-Y') : '',
|
||||||
|
@@ -0,0 +1,81 @@
|
|||||||
|
<?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\Common\Collections\Collection;
|
||||||
|
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'] instanceof Collection ? $data['creators']->toArray() : $data['creators']
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'creators' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.work.by_creator.title';
|
||||||
|
}
|
||||||
|
}
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
@@ -144,6 +144,9 @@ class SocialWorkTypeFilter implements FilterInterface
|
|||||||
$ids = [];
|
$ids = [];
|
||||||
|
|
||||||
foreach ($asIterable as $value) {
|
foreach ($asIterable as $value) {
|
||||||
|
if (null === $value) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$ids[] = $value->getId();
|
$ids[] = $value->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#export_filters_social_work_type_filter_form">
|
|
||||||
|
|
||||||
<fieldset class="mb-3" id="actionType">
|
<fieldset class="mb-3" id="actionType">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<legend class="col-sm-4 col-form-label">{{ $t('action.label')}}</legend>
|
<legend class="col-sm-4 col-form-label">{{ $t('action.label')}}</legend>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
v-model="action"
|
v-model="action"
|
||||||
:options="actions.options"
|
:options="actions.options"
|
||||||
@@ -14,20 +13,20 @@
|
|||||||
:multiple="true"
|
:multiple="true"
|
||||||
:close-on-select="false"
|
:close-on-select="false"
|
||||||
:placeholder="$t('action.placeholder')"
|
:placeholder="$t('action.placeholder')"
|
||||||
label="text"
|
:custom-label="formatSocialAction"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
></VueMultiselect>
|
></VueMultiselect>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="mb-3" id="goal">
|
<fieldset class="mb-3" id="goal">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<legend class="col-sm-4 col-form-label">{{ $t('goal.label')}}</legend>
|
<legend class="col-sm-4 col-form-label">{{ $t('goal.label')}}</legend>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
v-model="goal"
|
v-model="goal"
|
||||||
:options="goals.options"
|
:options="goals.options"
|
||||||
@@ -41,16 +40,16 @@
|
|||||||
track-by="id"
|
track-by="id"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
></VueMultiselect>
|
></VueMultiselect>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="mb-3" id="result">
|
<fieldset class="mb-3" id="result">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<legend class="col-sm-4 col-form-label">{{ $t('result.label')}}</legend>
|
<legend class="col-sm-4 col-form-label">{{ $t('result.label')}}</legend>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
v-model="result"
|
v-model="result"
|
||||||
:options="results.options"
|
:options="results.options"
|
||||||
@@ -64,12 +63,10 @@
|
|||||||
track-by="id"
|
track-by="id"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
></VueMultiselect>
|
></VueMultiselect>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
</teleport>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -150,74 +147,120 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.getSocialActionsList();
|
await this.getSocialActionsList();
|
||||||
|
|
||||||
this.actions.hiddenField.value = '';
|
if ('' !== this.actions.hiddenField.value) {
|
||||||
this.goals.hiddenField.value = '';
|
const actionIds = this.actions.hiddenField.value.split(',');
|
||||||
this.results.hiddenField.value = '';
|
for (const aid of actionIds) {
|
||||||
|
let action = this.actions.options.find(a => Number.parseInt(aid) === a.id);
|
||||||
//console.log(this.actions.hiddenField, this.goals.hiddenField, this.results.hiddenField);
|
if (undefined !== action) {
|
||||||
|
this.action.push(action);
|
||||||
|
await this.selectAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' !== this.goals.hiddenField.value) {
|
||||||
|
const goalsIds = this.goals.hiddenField.value.split(',').map(s => Number.parseInt(s));
|
||||||
|
for (const gid of goalsIds) {
|
||||||
|
let goal = this.goals.options.find(g => gid === g.id);
|
||||||
|
if (undefined !== goal) {
|
||||||
|
this.goal.push(goal);
|
||||||
|
await this.selectGoal(goal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' !== this.results.hiddenField.value) {
|
||||||
|
const resultsIds = this.results.hiddenField.value.split(',').map(s => Number.parseInt(s));
|
||||||
|
for (const rid of resultsIds) {
|
||||||
|
let result = this.results.options.find(r => rid === r.id);
|
||||||
|
if (undefined !== result) {
|
||||||
|
this.result.push(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async getSocialActionsList() {
|
async getSocialActionsList() {
|
||||||
this.actions.options = await getSocialActions();
|
let actions = await getSocialActions();
|
||||||
|
this.actions.options = actions.toSorted(function (a, b) {
|
||||||
|
if (a.issue.ordering === b.issue.ordering) {
|
||||||
|
if (a.ordering === b.ordering) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (a.ordering < b.ordering) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.issue.ordering < b.issue.ordering) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
})
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
formatSocialAction({text, issue}) {
|
||||||
|
return text + ' (' + issue.text + ')';
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select/unselect in Action Multiselect
|
* Select/unselect in Action Multiselect
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
selectAction(value) {
|
async selectAction(value) {
|
||||||
//console.log('----'); console.log('select action', value.id);
|
//console.log('----'); console.log('select action', value.id);
|
||||||
let children = this.getChildrensFromParent(value);
|
let children = this.getChildrensFromParent(value);
|
||||||
this.addSelectedElement('actions', children);
|
this.addSelectedElement('actions', children);
|
||||||
|
|
||||||
let parentAndChildren = [...[value], ...children];
|
let parentAndChildren = [...[value], ...children];
|
||||||
|
const promises = [];
|
||||||
parentAndChildren.forEach(elem => {
|
parentAndChildren.forEach(elem => {
|
||||||
getGoalByAction(elem.id).then(response => new Promise((resolve, reject) => {
|
promises.push(getGoalByAction(elem.id).then(goals => {
|
||||||
this.addElementInData('goals', response.results);
|
this.addElementInData('goals', goals);
|
||||||
resolve();
|
return Promise.resolve();
|
||||||
})).catch;
|
}));
|
||||||
getResultByAction(elem.id).then(response => new Promise((resolve, reject) => {
|
promises.push(getResultByAction(elem.id).then(results => {
|
||||||
this.addElementInData('results', response.results);
|
this.addElementInData('results', results);
|
||||||
resolve();
|
return Promise.resolve();
|
||||||
})).catch;
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
unselectAction(value) {
|
||||||
|
getGoalByAction(value.id).then(goals => {
|
||||||
|
[this.results.options, this.results.value ] = this.removeElementInData('goals', goals);
|
||||||
|
});
|
||||||
|
getResultByAction(value.id).then(results => {
|
||||||
|
[this.results.options, this.results.value ] = this.removeElementInData('results', results);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
unselectAction(value) {
|
|
||||||
//console.log('----'); console.log('unselect action', value.id);
|
|
||||||
getGoalByAction(value.id).then(response => new Promise((resolve, reject) => {
|
|
||||||
[ this.goals.options, this.goals.value ] = this.removeElementInData('goals', response.results);
|
|
||||||
resolve();
|
|
||||||
})).catch;
|
|
||||||
getResultByAction(value.id).then(response => new Promise((resolve, reject) => {
|
|
||||||
[ this.results.options, this.results.value ] = this.removeElementInData('results', response.results);
|
|
||||||
resolve();
|
|
||||||
})).catch;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select/unselect in Goal Multiselect
|
* Select/unselect in Goal Multiselect
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
selectGoal(value) {
|
async selectGoal(value) {
|
||||||
//console.log('----'); console.log('select goal', value.id);
|
return getResultByGoal(value.id).then(results => {
|
||||||
getResultByGoal(value.id).then(response => new Promise((resolve, reject) => {
|
this.addElementInData('results', results);
|
||||||
this.addElementInData('results', response.results);
|
})
|
||||||
resolve();
|
|
||||||
})).catch;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
unselectGoal(value) {
|
unselectGoal(value) {
|
||||||
//console.log('----'); console.log('unselect goal', value.id);
|
getResultByGoal(value.id).then(results => {
|
||||||
getResultByGoal(value.id).then(response => new Promise((resolve, reject) => {
|
[ this.results.options, this.results.value ] = this.removeElementInData('results', results);
|
||||||
[ this.results.options, this.results.value ] = this.removeElementInData('results', response.results);
|
}).catch;
|
||||||
resolve();
|
|
||||||
})).catch;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select/unselect in Result Multiselect
|
* Select/unselect in Result Multiselect
|
||||||
* @param value
|
* @param value
|
||||||
@@ -225,11 +268,11 @@ export default {
|
|||||||
selectResult(value) {
|
selectResult(value) {
|
||||||
//console.log('----'); console.log('select result', value.id);
|
//console.log('----'); console.log('select result', value.id);
|
||||||
},
|
},
|
||||||
|
|
||||||
unselectResult(value) {
|
unselectResult(value) {
|
||||||
//console.log('----'); console.log('unselect result', value.id);
|
//console.log('----'); console.log('unselect result', value.id);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose parent action will involve retaining the "children" actions.
|
* Choose parent action will involve retaining the "children" actions.
|
||||||
* @param value
|
* @param value
|
||||||
@@ -244,7 +287,7 @@ export default {
|
|||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add response elements in data target
|
* Add response elements in data target
|
||||||
* @param target string -> 'actions', 'goals' or 'results'
|
* @param target string -> 'actions', 'goals' or 'results'
|
||||||
@@ -263,8 +306,9 @@ export default {
|
|||||||
if (dump.length > 0) {
|
if (dump.length > 0) {
|
||||||
//console.log('push ' + dump.length + ' elems in', target, dump);
|
//console.log('push ' + dump.length + ' elems in', target, dump);
|
||||||
}
|
}
|
||||||
|
data.options.sort();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove response elements from data target
|
* Remove response elements from data target
|
||||||
* @param target string -> 'actions', 'goals' or 'results'
|
* @param target string -> 'actions', 'goals' or 'results'
|
||||||
@@ -279,7 +323,7 @@ export default {
|
|||||||
if (found) {
|
if (found) {
|
||||||
data.options = data.options.filter(e => e.id !== elem.id);
|
data.options = data.options.filter(e => e.id !== elem.id);
|
||||||
dump.push(elem.id);
|
dump.push(elem.id);
|
||||||
|
|
||||||
this.removeSelectedElement(target, elem);
|
this.removeSelectedElement(target, elem);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -288,7 +332,7 @@ export default {
|
|||||||
}
|
}
|
||||||
return [ data.options, data.value ];
|
return [ data.options, data.value ];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param target
|
* @param target
|
||||||
@@ -300,10 +344,10 @@ export default {
|
|||||||
elements.forEach(elem => {
|
elements.forEach(elem => {
|
||||||
let selected = data.value.some(e => e.id === elem.id);
|
let selected = data.value.some(e => e.id === elem.id);
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
|
|
||||||
data.value.push(elem);
|
data.value.push(elem);
|
||||||
dump.push(elem.id);
|
dump.push(elem.id);
|
||||||
|
|
||||||
// add in hiddenField
|
// add in hiddenField
|
||||||
this.rebuildHiddenFieldValues(target);
|
this.rebuildHiddenFieldValues(target);
|
||||||
}
|
}
|
||||||
@@ -312,7 +356,7 @@ export default {
|
|||||||
//console.log('add ' + dump.length + ' selected elems in', target, dump);
|
//console.log('add ' + dump.length + ' selected elems in', target, dump);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove element from selected and from hiddenField
|
* Remove element from selected and from hiddenField
|
||||||
* @param target
|
* @param target
|
||||||
@@ -322,19 +366,19 @@ export default {
|
|||||||
let data = this[target];
|
let data = this[target];
|
||||||
let selected = data.value.some(e => e.id === elem.id);
|
let selected = data.value.some(e => e.id === elem.id);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
|
|
||||||
// remove from selected
|
// remove from selected
|
||||||
data.value = data.value.filter(e => e.id !== elem.id);
|
data.value = data.value.filter(e => e.id !== elem.id);
|
||||||
//console.log('remove ' + elem.id + ' from selected ' + target);
|
//console.log('remove ' + elem.id + ' from selected ' + target);
|
||||||
|
|
||||||
// remove from hiddenField
|
// remove from hiddenField
|
||||||
this.rebuildHiddenFieldValues(target);
|
this.rebuildHiddenFieldValues(target);
|
||||||
|
|
||||||
// in any cases, remove should be recursive
|
// in any cases, remove should be recursive
|
||||||
this.unselectToNextField(target, elem);
|
this.unselectToNextField(target, elem);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When unselect Action, it could remove elements in goals multiselect.
|
* When unselect Action, it could remove elements in goals multiselect.
|
||||||
* In that case, we have to unselect Goal to remove elements in results too.
|
* In that case, we have to unselect Goal to remove elements in results too.
|
||||||
@@ -348,7 +392,7 @@ export default {
|
|||||||
//console.log('!!!! done');
|
//console.log('!!!! done');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuild values serie (string) in target HiddenField
|
* Rebuild values serie (string) in target HiddenField
|
||||||
* @param target
|
* @param target
|
||||||
@@ -362,14 +406,14 @@ export default {
|
|||||||
})
|
})
|
||||||
//console.log(data.hiddenField);
|
//console.log(data.hiddenField);
|
||||||
},
|
},
|
||||||
|
|
||||||
addIdToValue(string, id) {
|
addIdToValue(string, id) {
|
||||||
let array = string ? string.split(',') : [];
|
let array = string ? string.split(',') : [];
|
||||||
array.push(id.toString());
|
array.push(id.toString());
|
||||||
let str = array.join();
|
let str = array.join();
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
transTitle ({ title }) {
|
transTitle ({ title }) {
|
||||||
return title.fr //TODO multilang
|
return title.fr //TODO multilang
|
||||||
},
|
},
|
||||||
@@ -378,4 +422,4 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
</style>
|
</style>
|
||||||
|
@@ -8,29 +8,17 @@ const getSocialActions = () => fetchResults(
|
|||||||
|
|
||||||
const getGoalByAction = (id) => {
|
const getGoalByAction = (id) => {
|
||||||
let url = `/api/1.0/person/social-work/goal/by-social-action/${id}.json`;
|
let url = `/api/1.0/person/social-work/goal/by-social-action/${id}.json`;
|
||||||
return fetch(url)
|
return fetchResults(url);
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getResultByAction = (id) => {
|
const getResultByAction = (id) => {
|
||||||
let url = `/api/1.0/person/social-work/result/by-social-action/${id}.json`;
|
let url = `/api/1.0/person/social-work/result/by-social-action/${id}.json`;
|
||||||
return fetch(url)
|
return fetchResults(url);
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getResultByGoal = (id) => {
|
const getResultByGoal = (id) => {
|
||||||
let url = `/api/1.0/person/social-work/result/by-goal/${id}.json`;
|
let url = `/api/1.0/person/social-work/result/by-goal/${id}.json`;
|
||||||
return fetch(url)
|
return fetchResults(url);
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -38,4 +26,4 @@ export {
|
|||||||
getGoalByAction,
|
getGoalByAction,
|
||||||
getResultByAction,
|
getResultByAction,
|
||||||
getResultByGoal,
|
getResultByGoal,
|
||||||
}
|
}
|
||||||
|
@@ -2,12 +2,15 @@ import { createApp } from "vue";
|
|||||||
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
|
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
|
||||||
const i18n = _createI18n({});
|
if (null !== document.getElementById('export_filters_social_work_type_filter_enabled')) {
|
||||||
|
const i18n = _createI18n({});
|
||||||
|
const form = document.getElementById('export_filters_social_work_type_filter_form');
|
||||||
|
const after = form.appendChild(document.createElement('div'));
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: `<app></app>`,
|
template: `<app></app>`,
|
||||||
})
|
})
|
||||||
.use(i18n)
|
.use(i18n)
|
||||||
.component('app', App)
|
.component('app', App)
|
||||||
.mount('#export_export')
|
.mount(after);
|
||||||
;
|
}
|
||||||
|
@@ -12,7 +12,7 @@ const visMessages = {
|
|||||||
Holder: 'Titulaire',
|
Holder: 'Titulaire',
|
||||||
Legend: 'Calques',
|
Legend: 'Calques',
|
||||||
concerned: 'concerné',
|
concerned: 'concerné',
|
||||||
both: 'neutre, non binaire',
|
// both: 'neutre, non binaire',
|
||||||
woman: 'féminin',
|
woman: 'féminin',
|
||||||
man: 'masculin',
|
man: 'masculin',
|
||||||
undefined: "genre non précisé",
|
undefined: "genre non précisé",
|
||||||
@@ -64,8 +64,9 @@ const visMessages = {
|
|||||||
placeholder: "Choisissez le genre de l'usager",
|
placeholder: "Choisissez le genre de l'usager",
|
||||||
woman: "Féminin",
|
woman: "Féminin",
|
||||||
man: "Masculin",
|
man: "Masculin",
|
||||||
neuter: "Neutre, non binaire",
|
both: "Neutre, non binaire",
|
||||||
undefined: "Non renseigné"
|
undefined: "Non renseigné",
|
||||||
|
unknown: "Non renseigné"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error_only_one_person: "Une seule personne peut être sélectionnée !",
|
error_only_one_person: "Une seule personne peut être sélectionnée !",
|
||||||
|
@@ -153,6 +153,8 @@ const getGender = (gender) => {
|
|||||||
return visMessages.fr.visgraph.woman
|
return visMessages.fr.visgraph.woman
|
||||||
case 'man':
|
case 'man':
|
||||||
return visMessages.fr.visgraph.man
|
return visMessages.fr.visgraph.man
|
||||||
|
case 'unknown':
|
||||||
|
return visMessages.fr.visgraph.unknown
|
||||||
default:
|
default:
|
||||||
return visMessages.fr.visgraph.undefined
|
return visMessages.fr.visgraph.undefined
|
||||||
}
|
}
|
||||||
|
@@ -81,7 +81,7 @@
|
|||||||
<li v-else-if="options.addNoData">
|
<li v-else-if="options.addNoData">
|
||||||
<i class="fa fa-li fa-map-marker"></i><p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
<i class="fa fa-li fa-map-marker"></i><p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<template v-if="this.showResidentialAddresses && (person.current_residential_addresses || []).length > 0">
|
<template v-if="this.showResidentialAddresses && (person.current_residential_addresses || []).length > 0">
|
||||||
<li v-for="(addr, i) in person.current_residential_addresses" :key="i">
|
<li v-for="(addr, i) in person.current_residential_addresses" :key="i">
|
||||||
<i class="fa fa-li fa-map-marker"></i>
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
@@ -223,13 +223,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getGenderIcon: function () {
|
getGenderIcon: function () {
|
||||||
return this.person.gender === 'woman' ? 'fa-venus' : this.person.gender === 'man' ? 'fa-mars' : this.person.gender === 'neuter' ? 'fa-neuter' : 'fa-genderless';
|
return this.person.gender === 'woman' ? 'fa-venus' : this.person.gender === 'man' ? 'fa-mars' : this.person.gender === 'both' ? 'fa-neuter' : 'fa-genderless';
|
||||||
},
|
},
|
||||||
getGenderTranslation: function () {
|
getGenderTranslation: function () {
|
||||||
return this.person.gender === 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
|
return this.person.gender === 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
|
||||||
},
|
},
|
||||||
getGender() {
|
getGender() {
|
||||||
return this.person.gender === 'woman' ? 'person.gender.woman' : this.person.gender === 'man' ? 'person.gender.man' : this.person.gender === 'neuter' ? 'person.gender.neuter' : 'person.gender.undefined';
|
return this.person.gender === 'woman' ? 'person.gender.woman' : this.person.gender === 'man' ? 'person.gender.man' : this.person.gender === 'both' ? 'person.gender.both' : 'person.gender.undefined';
|
||||||
},
|
},
|
||||||
birthdate: function () {
|
birthdate: function () {
|
||||||
if (this.person.birthdate !== null || this.person.birthdate === "undefined") {
|
if (this.person.birthdate !== null || this.person.birthdate === "undefined") {
|
||||||
|
@@ -82,7 +82,7 @@
|
|||||||
<option selected disabled >{{ $t('person.gender.placeholder') }}</option>
|
<option selected disabled >{{ $t('person.gender.placeholder') }}</option>
|
||||||
<option value="woman">{{ $t('person.gender.woman') }}</option>
|
<option value="woman">{{ $t('person.gender.woman') }}</option>
|
||||||
<option value="man">{{ $t('person.gender.man') }}</option>
|
<option value="man">{{ $t('person.gender.man') }}</option>
|
||||||
<option value="neuter">{{ $t('person.gender.neuter') }}</option>
|
<option value="both">{{ $t('person.gender.both') }}</option>
|
||||||
</select>
|
</select>
|
||||||
<label>{{ $t('person.gender.title') }}</label>
|
<label>{{ $t('person.gender.title') }}</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -291,8 +291,12 @@ export default {
|
|||||||
return 'fa-venus';
|
return 'fa-venus';
|
||||||
case 'man':
|
case 'man':
|
||||||
return 'fa-mars';
|
return 'fa-mars';
|
||||||
case 'neuter':
|
case 'both':
|
||||||
return 'fa-neuter';
|
return 'fa-neuter';
|
||||||
|
case 'unknown':
|
||||||
|
return 'fa-genderless';
|
||||||
|
default:
|
||||||
|
return 'fa-genderless';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
genderTranslation() {
|
genderTranslation() {
|
||||||
@@ -301,8 +305,12 @@ export default {
|
|||||||
return 'person.gender.woman';
|
return 'person.gender.woman';
|
||||||
case 'man':
|
case 'man':
|
||||||
return 'person.gender.man';
|
return 'person.gender.man';
|
||||||
case 'neuter':
|
case 'both':
|
||||||
return 'person.gender.neuter';
|
return 'person.gender.both';
|
||||||
|
case 'unknown':
|
||||||
|
return 'person.gender.unknown';
|
||||||
|
default:
|
||||||
|
return 'person.gender.unknown';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
feminized() {
|
feminized() {
|
||||||
|
@@ -36,7 +36,8 @@ const personMessages = {
|
|||||||
placeholder: "Choisissez le genre de l'usager",
|
placeholder: "Choisissez le genre de l'usager",
|
||||||
woman: "Féminin",
|
woman: "Féminin",
|
||||||
man: "Masculin",
|
man: "Masculin",
|
||||||
neuter: "Neutre, non binaire",
|
both: "Neutre, non binaire",
|
||||||
|
unknown: "Non renseigné",
|
||||||
undefined: "Non renseigné"
|
undefined: "Non renseigné"
|
||||||
},
|
},
|
||||||
civility: {
|
civility: {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user