mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-11 09:14:59 +00:00
Compare commits
231 Commits
upgrade-ph
...
710_vendee
Author | SHA1 | Date | |
---|---|---|---|
ed556d9ee8 | |||
ff03299f80 | |||
5749660760 | |||
b679dbe26c
|
|||
6c3fa5cb98
|
|||
6bdd1f31d3 | |||
ff3dab0934
|
|||
977299192f | |||
77997e2b6f | |||
6e618e688b | |||
dad36927f3 | |||
f5448f9d95 | |||
a31c4063a1 | |||
c8f95528c0 | |||
20023dff67
|
|||
d82a3e0ff6
|
|||
04359f27c6
|
|||
5109490aad
|
|||
8b82e0c535 | |||
5351223d44 | |||
674e057f67
|
|||
b2e79b677b
|
|||
748e566c7e
|
|||
1f4c51f3bc | |||
dc6eeccaab | |||
0083842509
|
|||
ca7be4ecd0 | |||
785c70fe92 | |||
8bbca7e61a
|
|||
5d21612c2e | |||
fb9f182edd | |||
bbd3d2a83f
|
|||
e87420dc57 | |||
f1bf02d2b4 | |||
8a35c2e2ee | |||
fbd555e89a
|
|||
66dc027354
|
|||
8863e0a92e
|
|||
db9fef095a
|
|||
1df2342c49 | |||
addbdacee8 | |||
8a684734e7
|
|||
1abaf2acb0 | |||
a0ae1f0d0f | |||
2554da9dd8
|
|||
3e3f20993d
|
|||
997f3cdb09
|
|||
ab5ad7ae14
|
|||
36413f16c3
|
|||
f75b90cb26
|
|||
1956836f88
|
|||
ea4294d12d
|
|||
c73e57ad73
|
|||
5b729e1cb1
|
|||
229af2e4f9
|
|||
e80a6e417b
|
|||
c5989de120
|
|||
fcbc00d0f1
|
|||
722f053f06
|
|||
97b7ff2e43
|
|||
f3e0302f3f
|
|||
4974995ea2
|
|||
f2e1c73f37
|
|||
7e3295c71f | |||
b3d881c675 | |||
47d0334b9e
|
|||
c94653a388
|
|||
cdaca533a0
|
|||
00e62442cc
|
|||
a539febcfe | |||
1eb78d7273 | |||
1e2ca764c1
|
|||
a859b7ea93 | |||
49094ff54a | |||
1d2b6e167f | |||
73c0dd0e9e | |||
8fd9010ea5 | |||
488a0e5f0c | |||
9918cf2d58
|
|||
0c5a06c678
|
|||
cb0ff88318 | |||
be965e8698 | |||
241e605ea6 | |||
fe3d437096 | |||
c1f5f02c41 | |||
13feb3b212 | |||
dc22c94b95 | |||
7cb7897e12 | |||
01f2697b8d | |||
025ee2ea95 | |||
631d65a57f | |||
dde35be9c3 | |||
a59e84b029 | |||
60ada2edce | |||
e6163b2bc3
|
|||
906d1fdab5
|
|||
a1421ea99f
|
|||
cb1ea8c622
|
|||
b985e1c93e | |||
929c9f4f72 | |||
eaeab4ed2b | |||
034e2553bc | |||
a0d0c3840f | |||
b69fb740b1
|
|||
d31021247b | |||
d898f3ffce | |||
25c033be61
|
|||
746ed4f5e5
|
|||
80647147ee
|
|||
a9db133a7b
|
|||
858ade467c
|
|||
a68190f0c6
|
|||
459b91001f
|
|||
19034ac1d8
|
|||
4c2e78ada7
|
|||
bef1d6b4a3 | |||
c48c5875c6
|
|||
ffa94dbe40
|
|||
33051366d4
|
|||
2b42db87dc
|
|||
ffc3a97651 | |||
499417aea5 | |||
91d40d9153 | |||
ec7f59fc03 | |||
83ce3b3e92 | |||
324a350bf1 | |||
27415ce868 | |||
8042edc13c | |||
318a84e04d | |||
d759b9c727
|
|||
0af13b028e | |||
91ba0c983d | |||
78d3c6f1be | |||
19e51cc74c
|
|||
48f5e7d21f | |||
a9fe834978
|
|||
a21637331f
|
|||
63759a940f
|
|||
1cd153fb78
|
|||
0335986326
|
|||
1ecb285687 | |||
a553dc9aab
|
|||
d0830079da
|
|||
2a4b73457b
|
|||
d04011ca07
|
|||
796608b399 | |||
b0ac8ce5af
|
|||
d70a0fa08b | |||
8bec6feb96
|
|||
4db1ff405e
|
|||
841bdb0ebf
|
|||
d9dd8d7317
|
|||
98aad8c4b6
|
|||
ef13833966
|
|||
9853845c9c
|
|||
a42a4ab9bd
|
|||
839b0fc826
|
|||
cc69a3e86b
|
|||
4d734714a8
|
|||
1c19d01b60
|
|||
3df8ee6dc4
|
|||
386d1e44d0
|
|||
907c724047
|
|||
4cf6721e35
|
|||
46e1891386
|
|||
380ad2e2e6
|
|||
cba2bd8260 | |||
ee61d131ec
|
|||
70141fd0e3
|
|||
94c8b571f0 | |||
94a099c30c | |||
3ce6af4c36 | |||
c8e33daf4b | |||
0f635847f2 | |||
d290572ca8 | |||
3c88630edc
|
|||
866b92f7e5
|
|||
e84a93bd0c
|
|||
087ada2250 | |||
4c5dae60a8
|
|||
b9a7530f7a
|
|||
64b8ae3df1
|
|||
|
c9f26f3635 | ||
a943639cf1
|
|||
40e751c783
|
|||
|
6d6aa689d0 | ||
|
03fe9210a9 | ||
|
f3ede8122d | ||
|
801853e60a | ||
|
3927a7f62b | ||
|
1167ff25b1 | ||
|
5bba1aca93 | ||
|
9ded3eb631 | ||
|
bf79e0afdb | ||
|
6bf8789f85 | ||
|
8c37afa3a9 | ||
|
a8c2750ac8 | ||
e45952f28c | |||
|
3de5d29fe8 | ||
|
94046aab81 | ||
|
a3db67fd1e | ||
|
295406d9b7 | ||
|
35174e4241 | ||
|
7580565e08 | ||
|
a992c45720 | ||
|
1789a75216 | ||
|
2b3d7f34fc | ||
|
cbc3ee68b5 | ||
58faac5bca
|
|||
ea10565e17
|
|||
c5ec0e77ff
|
|||
2a303c7ba4
|
|||
e935bc20aa
|
|||
4f2355b313
|
|||
48772efd54
|
|||
331443ae12
|
|||
561d069a3e
|
|||
0133e202d2
|
|||
59147b2217
|
|||
99cdf0ebaf
|
|||
204c28d373
|
|||
adc80d5080
|
|||
f256dda6fe
|
|||
8177a0fcce
|
|||
21e24c60c7
|
|||
71d0785ab4
|
|||
b740a88ae3
|
|||
c56ae08fae
|
|||
c9fe5a393f
|
|||
8e0d144dd1
|
|||
2fe77f2610 |
@@ -69,7 +69,7 @@ phpstan_tests:
|
||||
stage: Tests
|
||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
||||
script:
|
||||
- bin/phpstan
|
||||
- bin/phpstan analyze --memory-limit=2G
|
||||
cache:
|
||||
paths:
|
||||
- .cache/
|
||||
@@ -79,21 +79,37 @@ phpstan_tests:
|
||||
- bin
|
||||
- tests/app/vendor/
|
||||
|
||||
psalm_tests:
|
||||
rector_tests:
|
||||
stage: Tests
|
||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
||||
script:
|
||||
- bin/psalm
|
||||
allow_failure: true
|
||||
- bin/rector --dry-run
|
||||
cache:
|
||||
paths:
|
||||
- .cache/
|
||||
artifacts:
|
||||
expire_in: 30 min
|
||||
paths:
|
||||
- bin
|
||||
- tests/app/vendor/
|
||||
|
||||
# psalm_tests:
|
||||
# stage: Tests
|
||||
# image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
||||
# script:
|
||||
# - bin/psalm
|
||||
# allow_failure: true
|
||||
# artifacts:
|
||||
# expire_in: 30 min
|
||||
# paths:
|
||||
# - bin
|
||||
# - tests/app/vendor/
|
||||
|
||||
unit_tests:
|
||||
stage: Tests
|
||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
||||
# until we fix testes
|
||||
allow_failure: true
|
||||
script:
|
||||
- php tests/app/bin/console doctrine:migrations:migrate -n
|
||||
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev
|
||||
|
@@ -34,6 +34,7 @@
|
||||
"sensio/framework-extra-bundle": "^5.5",
|
||||
"spomky-labs/base64url": "^2.0",
|
||||
"symfony/browser-kit": "^4.4",
|
||||
"symfony/clock": "^6.2",
|
||||
"symfony/css-selector": "^4.4",
|
||||
"symfony/expression-language": "^4.4",
|
||||
"symfony/form": "^4.4",
|
||||
@@ -47,7 +48,6 @@
|
||||
"symfony/monolog-bundle": "^3.5",
|
||||
"symfony/security-bundle": "^4.4",
|
||||
"symfony/serializer": "^5.3",
|
||||
"symfony/swiftmailer-bundle": "^3.5",
|
||||
"symfony/templating": "^4.4",
|
||||
"symfony/translation": "^4.4",
|
||||
"symfony/twig-bundle": "^4.4",
|
||||
@@ -75,6 +75,7 @@
|
||||
"phpunit/phpunit": ">= 7.5",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"psalm/plugin-symfony": "^4.0.2",
|
||||
"rector/rector": "^0.15.23",
|
||||
"symfony/debug-bundle": "^5.1",
|
||||
"symfony/dotenv": "^4.4",
|
||||
"symfony/maker-bundle": "^1.20",
|
||||
|
@@ -90,9 +90,7 @@ class CountPerson implements ExportInterface
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
// we gather all center the user choose.
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->entityManager->createQueryBuilder();
|
||||
|
||||
|
203
docs/source/development/entity-info.rst
Normal file
203
docs/source/development/entity-info.rst
Normal file
@@ -0,0 +1,203 @@
|
||||
|
||||
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||
A copy of the license is included in the section entitled "GNU
|
||||
Free Documentation License".
|
||||
|
||||
.. _entity-info:
|
||||
|
||||
Stats about event on entity in php world
|
||||
########################################
|
||||
|
||||
It is necessary to be able to gather information about events for some entities:
|
||||
|
||||
- when the event has been done;
|
||||
- who did it;
|
||||
- ...
|
||||
|
||||
Those "infos" are not linked with right management, like describe in :ref:`timelines`.
|
||||
|
||||
|
||||
“infos” for some stats and info about an entity
|
||||
-----------------------------------------------
|
||||
|
||||
Building an info means:
|
||||
|
||||
- create an Entity, and map this entity to a SQL view (not a regular table);
|
||||
- use the framework to build this entity dynamically.
|
||||
|
||||
A framework api is built to be able to build multiple “infos” entities
|
||||
through “union” views:
|
||||
|
||||
- use a command ``bin/console chill:db:sync-views`` to synchronize view (create view if it does not exists, or update
|
||||
views when new SQL parts are added in the UNION query. Internally, this command call a new ``ViewEntityInfoManager``,
|
||||
which iterate over available views to build the SQL;
|
||||
- one can create a new “view entity info” by implementing a
|
||||
``ViewEntityInfoProviderInterface``
|
||||
- this implementation of the interface is free to create another
|
||||
interface for building each part of the UNION query. This interface
|
||||
is created for AccompanyingPeriodInfo:
|
||||
``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``
|
||||
|
||||
So, converting new “events” into rows for ``AccompanyingPeriodInfo`` is
|
||||
just implementing this interface!
|
||||
|
||||
Implementation for AccompanyingPeriod (``AccompanyingPeriod/AccompanyingPeriodInfo``)
|
||||
-------------------------------------------------------------------------------------
|
||||
|
||||
A class is created for computing some statistical info for an
|
||||
AccompanyingPeriod: ``AccompanyingPeriod/AccompanyingPeriodInfo``. This
|
||||
contains information about “something happens”, who did it and when.
|
||||
|
||||
Having those info in table answer some questions like:
|
||||
|
||||
- when is the last and the first action (AccompanyingPeriodWork,
|
||||
Activity, AccompanyingPeriodWorkEvaluation, …) on the period;
|
||||
- who is “acting” on the period, and when is the last “action” for each
|
||||
user.
|
||||
|
||||
The AccompanyingPeriod info is mapped to a SQL view, not a table. The
|
||||
sql view is built dynamically (see below), and gather infos from
|
||||
ActivityBundle, PersonBundle, CalendarBundle, … It is possible to create
|
||||
custom bundle and add info on this view.
|
||||
|
||||
.. code:: php
|
||||
|
||||
/**
|
||||
*
|
||||
* @ORM\Entity()
|
||||
* @ORM\Table(name="view_chill_person_accompanying_period_info") <==== THIS IS A VIEW, NOT A TABLE
|
||||
*/
|
||||
class AccompanyingPeriodInfo
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
Why do we need this ?
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For multiple jobs in PHP world:
|
||||
|
||||
- moving the accompanying period to another steps when inactive,
|
||||
automatically;
|
||||
- listing all the users which are intervening on the action on a new
|
||||
“Liste des intervenants” page;
|
||||
- filtering on exports
|
||||
|
||||
Later, we will launch automatic anonymise for accompanying period and
|
||||
all related entities through this information.
|
||||
|
||||
How is built the SQL views which is mapped to “info” entities ?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The AccompanyingPeriodInfo entity is mapped by a SQL view (not a regular
|
||||
table).
|
||||
|
||||
The sql view is built dynamically, it is a SQL view like this, for now (April 2023):
|
||||
|
||||
.. code:: sql
|
||||
|
||||
create view view_chill_person_accompanying_period_info
|
||||
(accompanyingperiod_id, relatedentity, relatedentityid, user_id, infodate, discriminator, metadata) as
|
||||
SELECT w.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||
w.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
w.enddate AS infodate,
|
||||
'accompanying_period_work_end'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work w
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||
WHERE w.enddate IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
e.updatedby_id AS user_id,
|
||||
e.updatedat AS infodate,
|
||||
'accompanying_period_work_evaluation_updated_at'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
WHERE e.updatedat IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
e.maxdate AS infodate,
|
||||
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||
WHERE e.maxdate IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
e.startdate AS infodate,
|
||||
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument'::text AS relatedentity,
|
||||
doc.id AS relatedentityid,
|
||||
doc.updatedby_id AS user_id,
|
||||
doc.updatedat AS infodate,
|
||||
'accompanying_period_work_evaluation_document_updated_at'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation_document doc
|
||||
JOIN chill_person_accompanying_period_work_evaluation e ON doc.accompanyingperiodworkevaluation_id = e.id
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
WHERE doc.updatedat IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
e.maxdate AS infodate,
|
||||
'accompanying_period_work_evaluation_max'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||
WHERE e.maxdate IS NOT NULL
|
||||
UNION
|
||||
SELECT w.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||
w.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
w.startdate AS infodate,
|
||||
'accompanying_period_work_start'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work w
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||
UNION
|
||||
SELECT activity.accompanyingperiod_id,
|
||||
'Chill\ActivityBundle\Entity\Activity'::text AS relatedentity,
|
||||
activity.id AS relatedentityid,
|
||||
au.user_id,
|
||||
activity.date AS infodate,
|
||||
'activity_date'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM activity
|
||||
LEFT JOIN activity_user au ON activity.id = au.activity_id
|
||||
WHERE activity.accompanyingperiod_id IS NOT NULL;
|
||||
|
||||
As you can see, the view gather multiple SELECT queries and bind them
|
||||
with UNION.
|
||||
|
||||
Each SELECT query is built dynamically, through a class implementing an
|
||||
interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``, `like
|
||||
here <https://gitlab.com/Chill-Projet/chill-bundles/-/blob/master/src/Bundle/ChillPersonBundle/Service/EntityInfo/AccompanyingPeriodInfoQueryPart/AccompanyingPeriodWorkEndQueryPartForAccompanyingPeriodInfo.php>`__
|
||||
|
||||
To add new `SELECT` query in different `UNION` parts in the sql view, create a
|
||||
service and implements this interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``.
|
@@ -35,6 +35,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
|
||||
manual/index.rst
|
||||
Assets <assets.rst>
|
||||
Cron Jobs <cronjob.rst>
|
||||
Info about entities <entity-info.rst>
|
||||
|
||||
Layout and UI
|
||||
**************
|
||||
|
@@ -6,6 +6,8 @@
|
||||
A copy of the license is included in the section entitled "GNU
|
||||
Free Documentation License".
|
||||
|
||||
.. _timelines:
|
||||
|
||||
Timelines
|
||||
*********
|
||||
|
||||
|
@@ -151,6 +151,7 @@ This script will :
|
||||
|
||||
# mount into to container
|
||||
./docker-php.sh
|
||||
bin/console chill:db:sync-views
|
||||
# and load fixtures
|
||||
bin/console doctrine:migrations:migrate
|
||||
|
||||
@@ -161,7 +162,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
|
||||
|
||||
# mount into to container
|
||||
./docker-php.sh
|
||||
# and load fixtures
|
||||
# and load fixtures (do not this for production)
|
||||
bin/console doctrine:fixtures:load --purge-with-truncate
|
||||
|
||||
There are several users available:
|
||||
@@ -204,8 +205,10 @@ How to create the database schema (= run migrations) ?
|
||||
# if a container is running
|
||||
./docker-php.sh
|
||||
bin/console doctrine:migrations:migrate
|
||||
bin/console chill:db:sync-views
|
||||
# if not
|
||||
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
|
||||
docker-compose run --user $(id -u) php bin/console chill:db:sync-views
|
||||
|
||||
|
||||
How to read the email sent by the program ?
|
||||
@@ -236,6 +239,23 @@ How to open a terminal in the project
|
||||
# if not
|
||||
docker-compose run --user $(id -u) php /bin/bash
|
||||
|
||||
How to run cron-jobs ?
|
||||
======================
|
||||
|
||||
Some command must be executed in :ref:`cron jobs <cronjob>`. To execute them:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# if a container is running
|
||||
./docker-php.sh
|
||||
bin/console chill:cron-job:execute
|
||||
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||
bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||
# if not
|
||||
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute
|
||||
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||
|
||||
How to run composer ?
|
||||
=====================
|
||||
|
||||
|
@@ -38,6 +38,14 @@ This should be adapted to your needs:
|
||||
|
||||
* Think about how you will backup your database. Some adminsys find easier to store database outside of docker, which might be easier to administrate or replicate.
|
||||
|
||||
Run migrations on each update
|
||||
=============================
|
||||
|
||||
Every time you start a new version, you should apply update the sql schema:
|
||||
|
||||
- running ``bin/console doctrine:migration:migrate`` to run sql migration;
|
||||
- synchonizing sql views to the last state: ``bin/console chill:db:sync-views``
|
||||
|
||||
Cron jobs
|
||||
=========
|
||||
|
||||
|
@@ -41,6 +41,7 @@
|
||||
"@fullcalendar/timegrid": "^6.1.4",
|
||||
"@fullcalendar/vue3": "^6.1.4",
|
||||
"@popperjs/core": "^2.9.2",
|
||||
"@types/leaflet": "^1.9.3",
|
||||
"dropzone": "^5.7.6",
|
||||
"es6-promise": "^4.2.8",
|
||||
"leaflet": "^1.7.1",
|
||||
|
@@ -442,11 +442,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Bundle/ChillMainBundle/Workflow/Validator/StepDestValidValidator.php
|
||||
|
||||
-
|
||||
message: "#^Return type \\(int\\|void\\|null\\) of method Chill\\\\PersonBundle\\\\Command\\\\ImportPeopleFromCSVCommand\\:\\:execute\\(\\) should be covariant with return type \\(int\\) of method Symfony\\\\Component\\\\Console\\\\Command\\\\Command\\:\\:execute\\(\\)$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$query \\(Doctrine\\\\ORM\\\\QueryBuilder\\) of method Chill\\\\PersonBundle\\\\Controller\\\\HouseholdCompositionTypeApiController\\:\\:customizeQuery\\(\\) should be contravariant with parameter \\$query \\(mixed\\) of method Chill\\\\MainBundle\\\\CRUD\\\\Controller\\\\AbstractCRUDController\\:\\:customizeQuery\\(\\)$#"
|
||||
count: 1
|
||||
@@ -788,16 +783,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$thirdParty \\(Chill\\\\ThirdPartyBundle\\\\Entity\\\\ThirdParty\\) of method Chill\\\\ThirdPartyBundle\\\\Serializer\\\\Normalizer\\\\ThirdPartyNormalizer\\:\\:normalize\\(\\) should be contravariant with parameter \\$object \\(mixed\\) of method Symfony\\\\Component\\\\Serializer\\\\Normalizer\\\\NormalizerInterface\\:\\:normalize\\(\\)$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$format \\(string\\) of method Chill\\\\ThirdPartyBundle\\\\Serializer\\\\Normalizer\\\\ThirdPartyNormalizer\\:\\:supportsNormalization\\(\\) should be contravariant with parameter \\$format \\(string\\|null\\) of method Symfony\\\\Component\\\\Serializer\\\\Normalizer\\\\NormalizerInterface\\:\\:supportsNormalization\\(\\)$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$document \\(Chill\\\\DocStoreBundle\\\\Entity\\\\StoredObject\\) of method Chill\\\\WopiBundle\\\\Service\\\\Wopi\\\\ChillDocumentManager\\:\\:getBasename\\(\\) should be contravariant with parameter \\$document \\(ChampsLibres\\\\WopiLib\\\\Contract\\\\Entity\\\\Document\\) of method ChampsLibres\\\\WopiLib\\\\Contract\\\\Service\\\\DocumentManagerInterface\\:\\:getBasename\\(\\)$#"
|
||||
count: 1
|
||||
|
@@ -2631,11 +2631,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php
|
||||
|
||||
-
|
||||
message: "#^Call to method getRoleScopes\\(\\) on an unknown class Chill\\\\MainBundle\\\\Entity\\\\PermissionGroup\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php
|
||||
|
||||
-
|
||||
message: "#^Empty array passed to foreach\\.$#"
|
||||
count: 1
|
||||
@@ -3026,111 +3021,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$force\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$headers\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$helperSet\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$input\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$output\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$person\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$rawHeaders\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$row\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Symfony\\\\Component\\\\EventDispatcher\\\\Event\\:\\:\\$skipPerson\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\ObjectManager\\:\\:createQuery\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Call to method buildForm\\(\\) on an unknown class Chill\\\\CustomFieldsBundle\\\\Service\\\\CustomFieldInterface\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Else branch is unreachable because previous condition is always true\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Elseif branch is unreachable because previous condition is always true\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Instanceof between \\*NEVER\\* and Symfony\\\\Component\\\\Form\\\\ChoiceList\\\\View\\\\ChoiceGroupView will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Instanceof between Symfony\\\\Component\\\\Form\\\\ChoiceList\\\\View\\\\ChoiceView and Symfony\\\\Component\\\\Form\\\\ChoiceList\\\\View\\\\ChoiceView will always evaluate to true\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Method Chill\\\\PersonBundle\\\\Command\\\\ImportPeopleFromCSVCommand\\:\\:processTextType\\(\\) has invalid return type Chill\\\\PersonBundle\\\\Command\\\\type\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Method Symfony\\\\Component\\\\Console\\\\Helper\\\\Table\\:\\:render\\(\\) invoked with 1 parameter, 0 required\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @var above foreach loop does not specify variable name\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\$value of method Chill\\\\PersonBundle\\\\Command\\\\ImportPeopleFromCSVCommand\\:\\:processTextType\\(\\) has invalid type Chill\\\\PersonBundle\\\\Command\\\\type\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Strict comparison using \\=\\=\\= between false and false will always evaluate to true\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @var for property Chill\\\\PersonBundle\\\\Command\\\\ImportSocialWorkMetadata\\:\\:\\$importer with type Psr\\\\Log\\\\LoggerInterface is not subtype of native type Chill\\\\PersonBundle\\\\Service\\\\Import\\\\ChillImporter\\.$#"
|
||||
count: 1
|
||||
|
@@ -425,21 +425,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$mobilenumber of method Chill\\\\PersonBundle\\\\Entity\\\\Person\\:\\:setMobilenumber\\(\\) expects libphonenumber\\\\PhoneNumber\\|null, string given\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$phonenumber of method Chill\\\\PersonBundle\\\\Entity\\\\Person\\:\\:setPhonenumber\\(\\) expects libphonenumber\\\\PhoneNumber\\|null, string given\\.$#"
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#"
|
||||
count: 1
|
||||
|
@@ -310,11 +310,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php
|
||||
|
||||
-
|
||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||
count: 6
|
||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||
|
||||
-
|
||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||
count: 1
|
||||
|
@@ -3,7 +3,7 @@ parameters:
|
||||
paths:
|
||||
- src/
|
||||
tmpDir: .cache/
|
||||
reportUnmatchedIgnoredErrors: true
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
excludePaths:
|
||||
- .php_cs*
|
||||
- docs/
|
||||
|
60
rector.php
Normal file
60
rector.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([
|
||||
__DIR__ . '/docs',
|
||||
__DIR__ . '/src',
|
||||
]);
|
||||
|
||||
//$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
|
||||
//$rectorConfig->cacheDirectory(__DIR__ . '/.cache/rector');
|
||||
|
||||
// register a single rule
|
||||
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
|
||||
$rectorConfig->disableParallel();
|
||||
|
||||
//define sets of rules
|
||||
$rectorConfig->sets([
|
||||
LevelSetList::UP_TO_PHP_74
|
||||
]);
|
||||
|
||||
// skip some path...
|
||||
$rectorConfig->skip([
|
||||
// make rector stuck for some files
|
||||
\Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector::class,
|
||||
|
||||
// we need to discuss this: are we going to have FALSE in tests instead of an error ?
|
||||
\Rector\Php71\Rector\FuncCall\CountOnNullRector::class,
|
||||
|
||||
// must merge MR500 and review a typing of "ArrayCollection" in entities
|
||||
\Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector::class,
|
||||
|
||||
// remove all PHP80 rules, in order to activate them one by one
|
||||
\Rector\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector::class,
|
||||
\Rector\Php80\Rector\Class_\AnnotationToAttributeRector::class,
|
||||
\Rector\Php80\Rector\Switch_\ChangeSwitchToMatchRector::class,
|
||||
\Rector\Php80\Rector\FuncCall\ClassOnObjectRector::class,
|
||||
\Rector\Php80\Rector\ClassConstFetch\ClassOnThisVariableObjectRector::class,
|
||||
\Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector::class,
|
||||
\Rector\Php80\Rector\Class_\DoctrineAnnotationClassToAttributeRector::class,
|
||||
\Rector\Php80\Rector\ClassMethod\FinalPrivateToPrivateVisibilityRector::class,
|
||||
\Rector\Php80\Rector\Ternary\GetDebugTypeRector::class,
|
||||
\Rector\Php80\Rector\FunctionLike\MixedTypeRector::class,
|
||||
\Rector\Php80\Rector\Property\NestedAnnotationToAttributeRector::class,
|
||||
\Rector\Php80\Rector\FuncCall\Php8ResourceReturnToObjectRector::class,
|
||||
\Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector::class,
|
||||
\Rector\Php80\Rector\ClassMethod\SetStateToStaticRector::class,
|
||||
\Rector\Php80\Rector\NotIdentical\StrContainsRector::class,
|
||||
\Rector\Php80\Rector\Identical\StrEndsWithRector::class,
|
||||
\Rector\Php80\Rector\Identical\StrStartsWithRector::class,
|
||||
\Rector\Php80\Rector\Class_\StringableForToStringRector::class,
|
||||
\Rector\Php80\Rector\FuncCall\TokenGetAllToObjectRector::class,
|
||||
\Rector\Php80\Rector\FunctionLike\UnionTypesRector::class
|
||||
]);
|
||||
};
|
@@ -41,7 +41,6 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use function array_key_exists;
|
||||
@@ -213,7 +212,7 @@ final class ActivityController extends AbstractController
|
||||
|
||||
$form = $this->createForm(ActivityType::class, $entity, [
|
||||
'center' => $this->centerResolver->resolveCenters($entity)[0] ?? null,
|
||||
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
|
||||
'role' => 'CHILL_ACTIVITY_UPDATE',
|
||||
'activityType' => $entity->getActivityType(),
|
||||
'accompanyingPeriod' => $accompanyingPeriod,
|
||||
]);
|
||||
@@ -442,7 +441,7 @@ final class ActivityController extends AbstractController
|
||||
|
||||
$form = $this->createForm(ActivityType::class, $entity, [
|
||||
'center' => $this->centerResolver->resolveCenters($entity)[0] ?? null,
|
||||
'role' => new Role('CHILL_ACTIVITY_CREATE'),
|
||||
'role' => 'CHILL_ACTIVITY_CREATE',
|
||||
'activityType' => $entity->getActivityType(),
|
||||
'accompanyingPeriod' => $accompanyingPeriod,
|
||||
]);
|
||||
|
@@ -50,7 +50,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
|
||||
->findAll();
|
||||
|
||||
foreach ($persons as $person) {
|
||||
$activityNbr = mt_rand(0, 3);
|
||||
$activityNbr = random_int(0, 3);
|
||||
|
||||
for ($i = 0; $i < $activityNbr; ++$i) {
|
||||
$activity = $this->newRandomActivity($person);
|
||||
@@ -75,7 +75,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
|
||||
|
||||
// ->setAttendee($this->faker->boolean())
|
||||
|
||||
for ($i = 0; mt_rand(0, 4) > $i; ++$i) {
|
||||
for ($i = 0; random_int(0, 4) > $i; ++$i) {
|
||||
$reason = $this->getRandomActivityReason();
|
||||
|
||||
if (null !== $reason) {
|
||||
|
@@ -26,7 +26,7 @@ class Configuration implements ConfigurationInterface
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_activity');
|
||||
$rootNode = $treeBuilder->getRootNode('chill_activity');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
@@ -59,9 +59,7 @@ class Configuration implements ConfigurationInterface
|
||||
->info('The number of seconds of this duration. Must be an integer.')
|
||||
->cannotBeEmpty()
|
||||
->validate()
|
||||
->ifTrue(static function ($data) {
|
||||
return !is_int($data);
|
||||
})->thenInvalid('The value %s is not a valid integer')
|
||||
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('label')
|
||||
|
@@ -195,7 +195,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||
* @Groups({"docgen:read"})
|
||||
*/
|
||||
private User $user;
|
||||
private ?User $user = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")
|
||||
@@ -494,7 +494,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
return $this->activityType;
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
@@ -681,14 +681,14 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(UserInterface $user): self
|
||||
public function setUser(?User $user): self
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUsers(?Collection $users): self
|
||||
public function setUsers(Collection $users): self
|
||||
{
|
||||
$this->users = $users;
|
||||
|
||||
|
@@ -34,7 +34,7 @@ class ActivityPresence
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
* @Serializer\Groups({"docgen:read"})
|
||||
*/
|
||||
private ?int $id;
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
|
@@ -122,7 +122,7 @@ class ActivityType
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
* @Groups({"docgen:read"})
|
||||
*/
|
||||
private ?int $id;
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
||||
|
@@ -86,9 +86,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
|
||||
|
@@ -87,9 +87,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
|
||||
|
@@ -86,9 +86,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('activity')
|
||||
|
@@ -109,9 +109,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->entityManager->createQueryBuilder();
|
||||
|
||||
|
@@ -87,9 +87,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('activity')
|
||||
|
@@ -87,9 +87,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('activity')
|
||||
|
@@ -137,13 +137,11 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
||||
|
||||
$activity = $activityRepository->find($value);
|
||||
|
||||
return implode(', ', array_map(function (ActivityReason $r) {
|
||||
return '"' .
|
||||
return implode(', ', array_map(fn (ActivityReason $r) => '"' .
|
||||
$this->translatableStringHelper->localize($r->getCategory()->getName())
|
||||
. ' > ' .
|
||||
$this->translatableStringHelper->localize($r->getName())
|
||||
. '"';
|
||||
}, $activity->getReasons()->toArray()));
|
||||
. '"', $activity->getReasons()->toArray()));
|
||||
};
|
||||
|
||||
case 'circle_name':
|
||||
@@ -152,7 +150,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
||||
return 'circle';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize(json_decode($value, true));
|
||||
return $this->translatableStringHelper->localize(json_decode($value, true, 512, JSON_THROW_ON_ERROR));
|
||||
};
|
||||
|
||||
case 'type_name':
|
||||
@@ -161,7 +159,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
||||
return 'activity type';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize(json_decode($value, true));
|
||||
return $this->translatableStringHelper->localize(json_decode($value, true, 512, JSON_THROW_ON_ERROR));
|
||||
};
|
||||
|
||||
default:
|
||||
@@ -197,9 +195,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
// throw an error if any fields are present
|
||||
if (!array_key_exists('fields', $data)) {
|
||||
|
@@ -179,7 +179,7 @@ class ListActivityHelper
|
||||
}
|
||||
}
|
||||
|
||||
$decoded = json_decode($value);
|
||||
$decoded = json_decode($value, null, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
return implode(
|
||||
'|',
|
||||
|
@@ -61,12 +61,9 @@ class ActivityTypeFilter implements FilterInterface
|
||||
$builder->add('accepted_activitytypes', EntityType::class, [
|
||||
'class' => ActivityType::class,
|
||||
'choices' => $this->activityTypeRepository->findAllActive(),
|
||||
'choice_label' => function (ActivityType $aty) {
|
||||
return
|
||||
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
||||
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
||||
.
|
||||
$this->translatableStringHelper->localize($aty->getName());
|
||||
},
|
||||
$this->translatableStringHelper->localize($aty->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
|
@@ -20,13 +20,6 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class LocationFilter implements FilterInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
|
@@ -64,11 +64,9 @@ class UserScopeFilter implements FilterInterface
|
||||
{
|
||||
$builder->add('accepted_userscope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'choice_label' => function (Scope $s) {
|
||||
return $this->translatableStringHelper->localize(
|
||||
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
},
|
||||
),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
|
@@ -61,12 +61,9 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
|
||||
$builder->add('types', EntityType::class, [
|
||||
'choices' => $this->activityTypeRepository->findAllActive(),
|
||||
'class' => ActivityType::class,
|
||||
'choice_label' => function (ActivityType $aty) {
|
||||
return
|
||||
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
||||
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
||||
.
|
||||
$this->translatableStringHelper->localize($aty->getName());
|
||||
},
|
||||
$this->translatableStringHelper->localize($aty->getName()),
|
||||
'group_by' => function (ActivityType $type) {
|
||||
if (!$type->hasCategory()) {
|
||||
return null;
|
||||
|
@@ -32,7 +32,7 @@ class ActivityReasonCategoryType extends AbstractType
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory',
|
||||
'data_class' => \Chill\ActivityBundle\Entity\ActivityReasonCategory::class,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -211,13 +211,9 @@ class ActivityType extends AbstractType
|
||||
'required' => $activityType->isRequired('attendee'),
|
||||
'expanded' => true,
|
||||
'class' => ActivityPresence::class,
|
||||
'choice_label' => function (ActivityPresence $activityPresence) {
|
||||
return $this->translatableStringHelper->localize($activityPresence->getName());
|
||||
},
|
||||
'query_builder' => static function (EntityRepository $er) {
|
||||
return $er->createQueryBuilder('a')
|
||||
->where('a.active = true');
|
||||
},
|
||||
'choice_label' => fn (ActivityPresence $activityPresence) => $this->translatableStringHelper->localize($activityPresence->getName()),
|
||||
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('a')
|
||||
->where('a.active = true'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -225,6 +221,7 @@ class ActivityType extends AbstractType
|
||||
$builder->add('user', PickUserDynamicType::class, [
|
||||
'label' => $activityType->getLabel('user'),
|
||||
'required' => $activityType->isRequired('user'),
|
||||
'multiple' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -356,9 +353,7 @@ class ActivityType extends AbstractType
|
||||
|
||||
return (string) $location->getId();
|
||||
},
|
||||
function (?string $id): ?Location {
|
||||
return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]);
|
||||
}
|
||||
fn (?string $id): ?Location => $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id])
|
||||
));
|
||||
}
|
||||
|
||||
@@ -400,9 +395,7 @@ class ActivityType extends AbstractType
|
||||
// the datetimetransformer will then handle timezone as GMT
|
||||
$timezoneUTC = new DateTimeZone('GMT');
|
||||
/** @var DateTime $data */
|
||||
$data = $formEvent->getData() === null ?
|
||||
DateTime::createFromFormat('U', '300') :
|
||||
$formEvent->getData();
|
||||
$data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300');
|
||||
$seconds = $data->getTimezone()->getOffset($data);
|
||||
$data->setTimeZone($timezoneUTC);
|
||||
$data->add(new DateInterval('PT' . $seconds . 'S'));
|
||||
|
@@ -45,9 +45,7 @@ class ActivityTypeType extends AbstractType
|
||||
])
|
||||
->add('category', EntityType::class, [
|
||||
'class' => ActivityTypeCategory::class,
|
||||
'choice_label' => function (ActivityTypeCategory $activityTypeCategory) {
|
||||
return $this->translatableStringHelper->localize($activityTypeCategory->getName());
|
||||
},
|
||||
'choice_label' => fn (ActivityTypeCategory $activityTypeCategory) => $this->translatableStringHelper->localize($activityTypeCategory->getName()),
|
||||
])
|
||||
->add('ordering', NumberType::class, [
|
||||
'required' => true,
|
||||
|
@@ -45,9 +45,7 @@ class PickActivityReasonType extends AbstractType
|
||||
$resolver->setDefaults(
|
||||
[
|
||||
'class' => ActivityReason::class,
|
||||
'choice_label' => function (ActivityReason $choice) {
|
||||
return $this->reasonRender->renderString($choice, []);
|
||||
},
|
||||
'choice_label' => fn (ActivityReason $choice) => $this->reasonRender->renderString($choice, []),
|
||||
'group_by' => function (ActivityReason $choice): ?string {
|
||||
if (null !== $category = $choice->getCategory()) {
|
||||
return $this->translatableStringHelper->localize($category->getName());
|
||||
|
@@ -38,10 +38,8 @@ class TranslatableActivityReasonCategoryType extends AbstractType
|
||||
$resolver->setDefaults(
|
||||
[
|
||||
'class' => ActivityReasonCategory::class,
|
||||
'choice_label' => function (ActivityReasonCategory $category) {
|
||||
return $this->translatableStringHelper->localize($category->getName())
|
||||
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : '');
|
||||
},
|
||||
'choice_label' => fn (ActivityReasonCategory $category) => $this->translatableStringHelper->localize($category->getName())
|
||||
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : ''),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@@ -39,9 +39,7 @@ class TranslatableActivityType extends AbstractType
|
||||
'class' => ActivityType::class,
|
||||
'active_only' => true,
|
||||
'choices' => $this->activityTypeRepository->findAllActive(),
|
||||
'choice_label' => function (ActivityType $type) {
|
||||
return $this->translatableStringHelper->localize($type->getName());
|
||||
},
|
||||
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@@ -26,12 +26,12 @@ final class PersonMenuBuilder implements LocalMenuBuilderInterface
|
||||
/**
|
||||
* @var AuthorizationCheckerInterface
|
||||
*/
|
||||
protected $authorizationChecker;
|
||||
private $authorizationChecker;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
private $translator;
|
||||
|
||||
public function __construct(
|
||||
AuthorizationCheckerInterface $authorizationChecker,
|
||||
@@ -48,7 +48,7 @@ final class PersonMenuBuilder implements LocalMenuBuilderInterface
|
||||
|
||||
if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
|
||||
$menu->addChild(
|
||||
$this->translator->trans('Activity list'),
|
||||
$this->translator->trans('Activities'),
|
||||
[
|
||||
'route' => 'chill_activity_activity_list',
|
||||
'routeParameters' => ['person_id' => $person->getId()],
|
||||
|
@@ -254,9 +254,7 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte
|
||||
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), ActivityVoter::SEE, $center);
|
||||
// we get the ids for those scopes
|
||||
$reachablesScopesId = array_map(
|
||||
static function (Scope $scope) {
|
||||
return $scope->getId();
|
||||
},
|
||||
static fn (Scope $scope) => $scope->getId(),
|
||||
$reachableScopes
|
||||
);
|
||||
|
||||
|
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if activity.user and t.userVisible %}
|
||||
{% if activity.user is not null and t.userVisible %}
|
||||
<div class="wl-row">
|
||||
<div class="wl-col title"><h3>{{ 'Referrer'|trans }}</h3></div>
|
||||
<div class="wl-col list">
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
Maybe should we think about abstracting this file a bit more ? Moving it to PersonBundle ?
|
||||
#}
|
||||
{% if context == 'calendar_accompanyingCourse' %}
|
||||
{% if context == 'calendar_accompanyingCourse' or context == 'calendar_person' %}
|
||||
{% import "@ChillCalendar/_invite.html.twig" as invite %}
|
||||
{% endif %}
|
||||
|
||||
|
@@ -34,10 +34,12 @@
|
||||
|
||||
<div class="item-row separator">
|
||||
<dl class="chill_view_data">
|
||||
{%- if entity.user is not null %}
|
||||
<dt class="inline">{{ 'Referrer'|trans|capitalize }}</dt>
|
||||
<dd>
|
||||
<span class="badge-user">{{ entity.user|chill_entity_render_box }}</span>
|
||||
</dd>
|
||||
{% endif %}
|
||||
|
||||
{%- if entity.scope -%}
|
||||
<dt class="inline">{{ 'Scope'|trans }}</dt>
|
||||
|
@@ -134,9 +134,7 @@ class ActivityContext implements
|
||||
$builder->add($key, EntityType::class, [
|
||||
'class' => Person::class,
|
||||
'choices' => $persons,
|
||||
'choice_label' => function (Person $p) {
|
||||
return $this->personRender->renderString($p, []);
|
||||
},
|
||||
'choice_label' => fn (Person $p) => $this->personRender->renderString($p, []),
|
||||
'multiple' => false,
|
||||
'required' => false,
|
||||
'expanded' => true,
|
||||
@@ -147,6 +145,32 @@ class ActivityContext implements
|
||||
}
|
||||
}
|
||||
|
||||
public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
$denormalized = [];
|
||||
|
||||
foreach (['mainPerson', 'person1', 'person2'] as $k) {
|
||||
if (null !== ($id = ($data[$k] ?? null))) {
|
||||
$denormalized[$k] = $this->personRepository->find($id);
|
||||
} else {
|
||||
$denormalized[$k] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $denormalized;
|
||||
}
|
||||
|
||||
public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
$normalized = [];
|
||||
|
||||
foreach (['mainPerson', 'person1', 'person2'] as $k) {
|
||||
$normalized[$k] = null === $data[$k] ? null : $data[$k]->getId();
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array
|
||||
{
|
||||
if (!$entity instanceof Activity) {
|
||||
@@ -214,32 +238,6 @@ class ActivityContext implements
|
||||
return $options['mainPerson'] || $options['person1'] || $options['person2'];
|
||||
}
|
||||
|
||||
public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
$normalized = [];
|
||||
|
||||
foreach (['mainPerson', 'person1', 'person2'] as $k) {
|
||||
$normalized[$k] = null === $data[$k] ? null : $data[$k]->getId();
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
$denormalized = [];
|
||||
|
||||
foreach (['mainPerson', 'person1', 'person2'] as $k) {
|
||||
if (null !== ($id = ($data[$k] ?? null))) {
|
||||
$denormalized[$k] = $this->personRepository->find($id);
|
||||
} else {
|
||||
$denormalized[$k] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $denormalized;
|
||||
}
|
||||
|
||||
public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void
|
||||
{
|
||||
$storedObject->setTitle($this->translatableStringHelper->localize($template->getName()));
|
||||
|
@@ -34,10 +34,16 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
|
||||
use DateTime;
|
||||
use libphonenumber\PhoneNumber;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @implements DocGeneratorContextWithPublicFormInterface<AccompanyingPeriod>
|
||||
* @implements DocGeneratorContextWithAdminFormInterface<AccompanyingPeriod>
|
||||
*/
|
||||
class ListActivitiesByAccompanyingPeriodContext implements
|
||||
DocGeneratorContextWithAdminFormInterface,
|
||||
DocGeneratorContextWithPublicFormInterface
|
||||
@@ -69,7 +75,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
|
||||
SocialIssueRepository $socialIssueRepository,
|
||||
ThirdPartyRepository $thirdPartyRepository,
|
||||
TranslatableStringHelperInterface $translatableStringHelper,
|
||||
UserRepository $userRepository
|
||||
UserRepository $userRepository,
|
||||
) {
|
||||
$this->accompanyingPeriodContext = $accompanyingPeriodContext;
|
||||
$this->activityACLAwareRepository = $activityACLAwareRepository;
|
||||
@@ -100,14 +106,81 @@ class ListActivitiesByAccompanyingPeriodContext implements
|
||||
public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void
|
||||
{
|
||||
$this->accompanyingPeriodContext->buildPublicForm($builder, $template, $entity);
|
||||
|
||||
$builder
|
||||
->add('myActivitiesOnly', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'docgen.myActivitiesOnly',
|
||||
])
|
||||
->add('myWorksOnly', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'docgen.myWorksOnly',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array
|
||||
public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
$denormalized = $this->accompanyingPeriodContext->contextGenerationDataDenormalize($template, $entity, $data);
|
||||
|
||||
foreach (['myActivitiesOnly', 'myWorksOnly'] as $k) {
|
||||
$denormalized[$k] = $data[$k];
|
||||
}
|
||||
|
||||
return $denormalized;
|
||||
}
|
||||
|
||||
public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
$normalized = $this->accompanyingPeriodContext->contextGenerationDataNormalize($template, $entity, $data);
|
||||
|
||||
foreach (['myActivitiesOnly', 'myWorksOnly'] as $k) {
|
||||
$normalized[$k] = $data[$k] ?? false;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
private function filterActivitiesByUser(array $activities, User $user): array
|
||||
{
|
||||
return array_filter(
|
||||
$activities,
|
||||
function ($activity) use ($user) {
|
||||
$activityUsernames = array_map(static fn ($user) => $user['username'], $activity['users'] ?? []);
|
||||
return in_array($user->getUsername(), $activityUsernames, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function filterWorksByUser(array $works, User $user): array
|
||||
{
|
||||
return array_filter(
|
||||
$works,
|
||||
function ($work) use ($user) {
|
||||
$workUsernames = array_map(static fn ($user) => $user['username'], $work['referrers'] ?? []);
|
||||
|
||||
return in_array($user->getUsername(), $workUsernames, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function getData(DocGeneratorTemplate $template, object $entity, array $contextGenerationData = []): array
|
||||
{
|
||||
$data = $this->accompanyingPeriodContext->getData($template, $entity, $contextGenerationData);
|
||||
|
||||
$data['activities'] = $this->getActivitiesSimplified($entity);
|
||||
$activities = $this->getActivitiesSimplified($entity);
|
||||
$myActivitiesOnly = $contextGenerationData['myActivitiesOnly'];
|
||||
|
||||
if ($myActivitiesOnly && isset($contextGenerationData['creator'])) {
|
||||
$activities = $this->filterActivitiesByUser($activities, $contextGenerationData['creator']);
|
||||
}
|
||||
|
||||
$data['activities'] = $activities;
|
||||
|
||||
$myWorksOnly = $contextGenerationData['myWorksOnly'];
|
||||
|
||||
if ($myWorksOnly && isset($contextGenerationData['creator'])) {
|
||||
$data['course']['works'] = $this->filterWorksByUser($data['course']['works'], $contextGenerationData['creator']);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -143,17 +216,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
|
||||
|
||||
public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool
|
||||
{
|
||||
return $this->accompanyingPeriodContext->hasPublicForm($template, $entity);
|
||||
}
|
||||
|
||||
public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
return $this->accompanyingPeriodContext->contextGenerationDataNormalize($template, $entity, $data);
|
||||
}
|
||||
|
||||
public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
|
||||
{
|
||||
return $this->accompanyingPeriodContext->contextGenerationDataDenormalize($template, $entity, $data);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void
|
||||
|
@@ -0,0 +1,64 @@
|
||||
<?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\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||
|
||||
class ActivityUsersDateQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||
{
|
||||
public function getAccompanyingPeriodIdColumn(): string
|
||||
{
|
||||
return 'activity.accompanyingperiod_id';
|
||||
}
|
||||
|
||||
public function getRelatedEntityColumn(): string
|
||||
{
|
||||
return Activity::class;
|
||||
}
|
||||
|
||||
public function getRelatedEntityIdColumn(): string
|
||||
{
|
||||
return 'activity.id';
|
||||
}
|
||||
|
||||
public function getUserIdColumn(): string
|
||||
{
|
||||
return 'au.user_id';
|
||||
}
|
||||
|
||||
public function getDateTimeColumn(): string
|
||||
{
|
||||
return 'activity.date';
|
||||
}
|
||||
|
||||
public function getDiscriminator(): string
|
||||
{
|
||||
return 'activity_date';
|
||||
}
|
||||
|
||||
public function getMetadataColumn(): string
|
||||
{
|
||||
return '\'{}\'::jsonb';
|
||||
}
|
||||
|
||||
public function getFromStatement(): string
|
||||
{
|
||||
return 'activity
|
||||
LEFT JOIN activity_user au on activity.id = au.activity_id';
|
||||
}
|
||||
|
||||
public function getWhereClause(): string
|
||||
{
|
||||
return 'activity.accompanyingperiod_id IS NOT NULL';
|
||||
}
|
||||
}
|
@@ -121,14 +121,14 @@ final class ActivityControllerTest extends WebTestCase
|
||||
$client->getResponse()->getStatusCode(),
|
||||
'Unexpected HTTP status code for GET /activity/'
|
||||
);
|
||||
$crawler = $client->click($crawler->selectLink('Ajouter une nouvelle activité')
|
||||
$crawler = $client->click($crawler->selectLink('Ajouter un nouvel échange')
|
||||
->link());
|
||||
|
||||
$reason1 = $this->getRandomActivityReason();
|
||||
$reason2 = $this->getRandomActivityReason([$reason1->getId()]);
|
||||
|
||||
// Fill in the form and submit it
|
||||
$form = $crawler->selectButton('Ajouter une nouvelle activité')->form([
|
||||
$form = $crawler->selectButton('Ajouter un nouvel échange')->form([
|
||||
'chill_activitybundle_activity' => [
|
||||
'date' => '15-01-2015',
|
||||
'durationTime' => 600,
|
||||
@@ -152,9 +152,9 @@ final class ActivityControllerTest extends WebTestCase
|
||||
);
|
||||
|
||||
// Edit the entity
|
||||
$crawler = $client->click($crawler->selectLink("Modifier l'activité")->link());
|
||||
$crawler = $client->click($crawler->selectLink("Modifier l'échange")->link());
|
||||
|
||||
$form = $crawler->selectButton("Sauver l'activité")->form([
|
||||
$form = $crawler->selectButton("Sauver l'échange")->form([
|
||||
'chill_activitybundle_activity' => [
|
||||
'date' => '25-01-2015',
|
||||
// 'remark' => 'Foo'
|
||||
@@ -369,12 +369,8 @@ final class ActivityControllerTest extends WebTestCase
|
||||
$center
|
||||
);
|
||||
$reachableScopesId = array_intersect(
|
||||
array_map(static function ($s) {
|
||||
return $s->getId();
|
||||
}, $reachableScopesDelete),
|
||||
array_map(static function ($s) {
|
||||
return $s->getId();
|
||||
}, $reachableScopesUpdate)
|
||||
array_map(static fn ($s) => $s->getId(), $reachableScopesDelete),
|
||||
array_map(static fn ($s) => $s->getId(), $reachableScopesUpdate)
|
||||
);
|
||||
|
||||
if (count($reachableScopesId) === 0) {
|
||||
|
@@ -188,9 +188,7 @@ final class ActivityTypeTest extends KernelTestCase
|
||||
|
||||
// map all the values in an array
|
||||
$values = array_map(
|
||||
static function ($choice) {
|
||||
return $choice->value;
|
||||
},
|
||||
static fn ($choice) => $choice->value,
|
||||
$view['activity']['durationTime']->vars['choices']
|
||||
);
|
||||
|
||||
|
@@ -79,15 +79,13 @@ final class TranslatableActivityReasonTest extends TypeTestCase
|
||||
$request = $prophet->prophesize();
|
||||
$translator = $prophet->prophesize();
|
||||
|
||||
$request->willExtend('Symfony\Component\HttpFoundation\Request');
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn($fallbackLocale);
|
||||
|
||||
$requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack');
|
||||
$requestStack->getCurrentRequest()->will(static function () use ($request) {
|
||||
return $request;
|
||||
});
|
||||
$requestStack->willExtend(\Symfony\Component\HttpFoundation\RequestStack::class);
|
||||
$requestStack->getCurrentRequest()->will(static fn () => $request);
|
||||
|
||||
$translator->willExtend('Symfony\Component\Translation\Translator');
|
||||
$translator->willExtend(\Symfony\Component\Translation\Translator::class);
|
||||
$translator->getFallbackLocales()->willReturn($locale);
|
||||
|
||||
return new TranslatableStringHelper(
|
||||
|
@@ -160,7 +160,7 @@ final class ActivityVoterTest extends KernelTestCase
|
||||
{
|
||||
$token = $this->prophet->prophesize();
|
||||
$token
|
||||
->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
|
||||
->willImplement('\\' . \Symfony\Component\Security\Core\Authentication\Token\TokenInterface::class);
|
||||
|
||||
if (null === $user) {
|
||||
$token->getUser()->willReturn(null);
|
||||
|
@@ -34,6 +34,7 @@ services:
|
||||
resource: '../Validator/Constraints/'
|
||||
|
||||
Chill\ActivityBundle\Service\DocGenerator\:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
resource: '../Service/DocGenerator/'
|
||||
|
||||
Chill\ActivityBundle\Service\EntityInfo\:
|
||||
resource: '../Service/EntityInfo/'
|
||||
|
@@ -1,41 +1,41 @@
|
||||
#general
|
||||
Show the activity: Voir l'activité
|
||||
Edit the activity: Modifier l'activité
|
||||
Activity: Activité
|
||||
Show the activity: Voir l'échange
|
||||
Edit the activity: Modifier l'échange
|
||||
Activity: Échange
|
||||
Duration time: Durée
|
||||
Duration Time: Durée
|
||||
durationTime: durée
|
||||
Travel time: Durée de déplacement
|
||||
Attendee: Présence de la personne
|
||||
attendee: présence de la personne
|
||||
Attendee: Présence de l'usager
|
||||
attendee: présence de l'usager
|
||||
list_reasons: liste des sujets
|
||||
user_username: nom de l'utilisateur
|
||||
circle_name: nom du cercle
|
||||
Remark: Commentaire
|
||||
No comments: Aucun commentaire
|
||||
Add a new activity: Ajouter une nouvelle activité
|
||||
Activity list: Liste des activités
|
||||
Add a new activity: Ajouter une nouvel échange
|
||||
Activity list: Liste des échanges
|
||||
present: présent
|
||||
not present: absent
|
||||
Delete: Supprimer
|
||||
Update: Mettre à jour
|
||||
Update activity: Modifier l'activité
|
||||
Update activity: Modifier l'échange
|
||||
Scope: Cercle
|
||||
Activity data: Données de l'activité
|
||||
Activity location: Localisation de l'activité
|
||||
Activity data: Données de l'échange
|
||||
Activity location: Localisation de l'échange
|
||||
No reason associated: Aucun sujet
|
||||
No social issues associated: Aucune problématique sociale
|
||||
No social actions associated: Aucune action d'accompagnement
|
||||
There isn't any activities.: Aucune activité enregistrée.
|
||||
type_name: type de l'activité
|
||||
There isn't any activities.: Aucun échange enregistré.
|
||||
type_name: type de l'échange
|
||||
person_firstname: prénom
|
||||
person_lastname: nom de famille
|
||||
person_id: identifiant de la personne
|
||||
person_id: identifiant de l'usager
|
||||
Type: Type
|
||||
Invisible: Invisible
|
||||
Optional: Optionnel
|
||||
Required: Obligatoire
|
||||
Persons: Personnes
|
||||
Persons: Usagers
|
||||
Users: Utilisateurs
|
||||
Emergency: Urgent
|
||||
Sent received: Entrant / Sortant
|
||||
@@ -50,10 +50,10 @@ received: Reçu
|
||||
|
||||
|
||||
#forms
|
||||
Activity creation: Nouvelle activité
|
||||
Activity creation: Nouvel échange
|
||||
Create: Créer
|
||||
Back to the list: Retour à la liste
|
||||
Save activity: Sauver l'activité
|
||||
Save activity: Sauver l'échange
|
||||
Reset form: Remise à zéro du formulaire
|
||||
Choose the duration: Choisir la durée
|
||||
Choose a type: Choisir un type
|
||||
@@ -90,47 +90,50 @@ activity:
|
||||
No documents: Aucun document
|
||||
|
||||
#timeline
|
||||
'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"'
|
||||
'%user% has done an %activity_type%': '%user% a effectué un échange de type "%activity_type%"'
|
||||
|
||||
#controller
|
||||
'Success : activity created!': L'activité a été créée.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'activité n'a pas été créée.
|
||||
'Success : activity updated!': L'activité a été mise à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'activité n'a pas été mise à jour.
|
||||
'Success : activity created!': L'échange a été créé.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'échange n'a pas été créé.
|
||||
'Success : activity updated!': L'échange a été mis à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'échange n'a pas été mise à jour.
|
||||
|
||||
# ROLES
|
||||
CHILL_ACTIVITY_CREATE: Créer une activité
|
||||
CHILL_ACTIVITY_UPDATE: Modifier une activité
|
||||
CHILL_ACTIVITY_SEE: Voir une activité
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des activités
|
||||
CHILL_ACTIVITY_DELETE: Supprimer une activité
|
||||
CHILL_ACTIVITY_STATS: Statistique des activités
|
||||
CHILL_ACTIVITY_LIST: Liste des activités
|
||||
CHILL_ACTIVITY_CREATE: Créer un échange
|
||||
CHILL_ACTIVITY_UPDATE: Modifier un échange
|
||||
CHILL_ACTIVITY_SEE: Voir un échange
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des échanges
|
||||
CHILL_ACTIVITY_DELETE: Supprimer un échange
|
||||
CHILL_ACTIVITY_STATS: Statistique des échanges
|
||||
CHILL_ACTIVITY_LIST: Liste des échanges
|
||||
CHILL_ACTIVITY_CREATE_PERSON: Créer un échange lié à un usager
|
||||
CHILL_ACTIVITY_CREATE_ACCOMPANYING_COURSE: Créer un échange lié à un parcours
|
||||
CHILL_ACTIVITY_FULL: Voir les détails, créer, supprimer et mettre à jour un échange
|
||||
|
||||
# admin
|
||||
Activities: Activités
|
||||
Activity configuration: Configuration des activités
|
||||
Activity configuration menu: Configuration des activités
|
||||
Activity types: Types d'activité
|
||||
Activity type configuration: Configuration des categories d'activités
|
||||
Activity Reasons: Sujets d'une activité
|
||||
Activity Reasons Category: Catégories de sujet d'activités
|
||||
Activity Types Categories: Catégories des types d'activité
|
||||
Activity Presences: Presences aux activités
|
||||
Activities: Échanges
|
||||
Activity configuration: Configuration des échanges
|
||||
Activity configuration menu: Configuration des échanges
|
||||
Activity types: Types d'échange
|
||||
Activity type configuration: Configuration des catégories d'échanges
|
||||
Activity Reasons: Sujets d'un échange
|
||||
Activity Reasons Category: Catégories de sujet d'échanges
|
||||
Activity Types Categories: Catégories des types d'échange
|
||||
Activity Presences: Présences aux échanges
|
||||
Associated activity reason category is inactive: La catégorie de sujet attachée est inactive
|
||||
|
||||
|
||||
# Crud
|
||||
crud:
|
||||
activity_type:
|
||||
title_new: Nouveau type d'activité
|
||||
title_edit: Edition d'un type d'activité
|
||||
title_new: Nouveau type d'échange
|
||||
title_edit: Édition d'un type d'échange
|
||||
activity_type_category:
|
||||
title_new: Nouvelle catégorie de type d'activité
|
||||
title_edit: Edition d'une catégorie de type d'activité
|
||||
title_new: Nouvelle catégorie de type d'échange
|
||||
title_edit: Édition d'une catégorie de type d'échange
|
||||
activity_presence:
|
||||
title_new: Nouvelle Présence aux activités
|
||||
title_edit: Edition d'une Présence aux activités
|
||||
title_new: Nouvelle présence aux échanges
|
||||
title_edit: Édition d'une présence aux échanges
|
||||
|
||||
# activity reason admin
|
||||
ActivityReason list: Liste des sujets
|
||||
@@ -139,7 +142,7 @@ Active: Actif
|
||||
Category: Catégorie
|
||||
ActivityReason creation: Nouveau sujet
|
||||
ActivityReason edit: Modification d'un sujet
|
||||
ActivityReason: Sujet d'activité
|
||||
ActivityReason: Sujet d'échange
|
||||
The entity is inactive and won't be proposed: Le sujet est inactif et ne sera pas proposé
|
||||
The entity is active and will be proposed: Le sujet est actif et sera proposé
|
||||
|
||||
@@ -148,19 +151,19 @@ ActivityReasonCategory list: Catégories de sujets
|
||||
Create a new activity category reason: Créer une nouvelle catégorie
|
||||
ActivityReasonCategory creation: Nouvelle catégorie de sujet
|
||||
ActivityReasonCategory edit: Modification d'une catégorie de sujet
|
||||
ActivityReasonCategory: Catégorie de sujet d'activité
|
||||
ActivityReasonCategory: Catégorie de sujet d'échange
|
||||
ActivityReasonCategory is active and will be proposed: La catégorie est active et sera proposée
|
||||
ActivityReasonCategory is inactive and won't be proposed: La catégorie est inactive et ne sera pas proposée
|
||||
|
||||
#activity presence admin
|
||||
ActivityPresence list: Liste des Présences aux activités
|
||||
Create a new activity presence: Créer une nouvelle "Présence aux activités"
|
||||
ActivityPresence list: Liste des présences aux échanges
|
||||
Create a new activity presence: Créer une nouvelle "Présence aux échanges"
|
||||
|
||||
# activity type type admin
|
||||
ActivityType list: Types d'activités
|
||||
Create a new activity type: Créer un nouveau type d'activité
|
||||
Persons visible: Visibilité du champ Personnes
|
||||
Persons label: Libellé du champ Personnes
|
||||
ActivityType list: Types d'échanges
|
||||
Create a new activity type: Créer un nouveau type d'échange
|
||||
Persons visible: Visibilité du champ Usagers
|
||||
Persons label: Libellé du champ Usagers
|
||||
User visible: Visibilité du champ Utilisateur
|
||||
User label: Libellé du champ Utilisateur
|
||||
Date visible: Visibilité du champ Date
|
||||
@@ -183,8 +186,8 @@ Private comment visible: Visibilité du champ Commentaire Privé
|
||||
Private comment label: Libellé du champ Commentaire Privé
|
||||
Emergency visible: Visibilité du champ Urgent
|
||||
Emergency label: Libellé du champ Urgent
|
||||
Accompanying period visible: Visibilité du champ Période d'accompagnement
|
||||
Accompanying period label: Libellé du champ Période d'accompagnement
|
||||
Accompanying period visible: Visibilité du champ parcours d'accompagnement
|
||||
Accompanying period label: Libellé du champ parcours d'accompagnement
|
||||
Social issues visible: Visibilité du champ Problématiques sociales
|
||||
Social issues label: Libellé du champ Problématiques sociales
|
||||
Social actions visible: Visibilité du champ Action sociale
|
||||
@@ -197,138 +200,140 @@ Documents visible: Visibilité du champ Documents
|
||||
Documents label: Libellé du champ Documents
|
||||
|
||||
# activity type category admin
|
||||
ActivityTypeCategory list: Liste des catégories des types d'activité
|
||||
Create a new activity type category: Créer une nouvelle catégorie de type d'activité
|
||||
ActivityTypeCategory list: Liste des catégories des types d'échange
|
||||
Create a new activity type category: Créer une nouvelle catégorie de type d'échange
|
||||
|
||||
# activity delete
|
||||
Remove activity: Supprimer une activité
|
||||
Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité qui concerne "%name%" ?
|
||||
The activity has been successfully removed.: L'activité a été supprimée.
|
||||
Remove activity: Supprimer un échange
|
||||
Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer un échange qui concerne "%name%" ?
|
||||
The activity has been successfully removed.: L'échange a été supprimé.
|
||||
|
||||
# exports
|
||||
Exports of activities linked to a person: Exports des activités liées à une personne
|
||||
Number of activities linked to a person: Nombre d'activités liées à une personne
|
||||
Count activities linked to a person: Nombre d'activités
|
||||
Count activities linked to a person by various parameters.: Compte le nombre d'activités enregistrées et liées à une personne en fonction de différents paramètres.
|
||||
Sum activity linked to a person duration: Durée des activités
|
||||
Sum activities linked to a person duration: Durée des activités liés à un usager
|
||||
Sum activities linked to a person duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
List activity linked to a person: Liste les activités
|
||||
List activities linked to a person: Liste des activités liés à un usager
|
||||
List activities linked to a person description: Crée la liste des activités en fonction de différents paramètres.
|
||||
Exports of activities linked to a person: Exports des échanges liés à un usager
|
||||
Number of activities linked to a person: Nombre d'échanges liés à un usager
|
||||
Count activities linked to a person: Nombre d'échanges
|
||||
Count activities linked to a person by various parameters.: Compte le nombre d'échanges enregistrés et liés à un usager en fonction de différents paramètres.
|
||||
Sum activity linked to a person duration: Durée des échanges
|
||||
Sum activities linked to a person duration: Durée des échanges liés à un usager
|
||||
Sum activities linked to a person duration by various parameters.: Additionne la durée des échanges en fonction de différents paramètres.
|
||||
List activity linked to a person: Liste les échanges
|
||||
List activities linked to a person: Liste des échanges liés à un usager
|
||||
List activities linked to a person description: Crée la liste des échanges en fonction de différents paramètres.
|
||||
|
||||
Exports of activities linked to an accompanying period: Exports des activités liées à un parcours
|
||||
Number of activities linked to an accompanying period: Nombre d'activités liées à un parcours
|
||||
Count activities linked to an accompanying period: Nombre d'activités
|
||||
Count activities linked to an accompanying period by various parameters.: Compte le nombre d'activités enregistrées et liées à un parcours en fonction de différents paramètres.
|
||||
Sum activity linked to an accompanying period duration: Somme de la durée des activités
|
||||
Sum activities linked to an accompanying period duration: Somme de la durée des activités liées à un parcours
|
||||
Sum activities linked to an accompanying period duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
Sum activity linked to an accompanying period visit duration: Somme de la durée de déplacement des activités
|
||||
Sum activities linked to an accompanying period visit duration: Somme de la durée de déplacement des activités liées à un parcours
|
||||
Sum activities linked to an accompanying period visit duration by various parameters.: Additionne la durée de déplacement des activités en fonction de différents paramètres.
|
||||
Average activity linked to an accompanying period duration: Moyenne de la durée des activités
|
||||
Average activities linked to an accompanying period duration: Moyenne de la durée des activités liées à un parcours
|
||||
Average activities linked to an accompanying period duration by various parameters.: Moyenne de la durée des activités en fonction de différents paramètres.
|
||||
Average activity linked to an accompanying period visit duration: Moyenne de la durée de déplacement des activités
|
||||
Average activities linked to an accompanying period visit duration: Moyenne de la durée de déplacement des activités liées à un parcours
|
||||
Average activities linked to an accompanying period visit duration by various parameters.: Moyenne de la durée de déplacement des activités en fonction de différents paramètres.
|
||||
Exports of activities linked to an accompanying period: Exports des échanges liés à un parcours
|
||||
Number of activities linked to an accompanying period: Nombre d'échanges liés à un parcours
|
||||
Count activities linked to an accompanying period: Nombre d'échanges
|
||||
Count activities linked to an accompanying period by various parameters.: Compte le nombre d'échanges enregistrés et liées à un parcours en fonction de différents paramètres.
|
||||
Sum activity linked to an accompanying period duration: Somme de la durée des échanges
|
||||
Sum activities linked to an accompanying period duration: Somme de la durée des échanges liés à un parcours
|
||||
Sum activities linked to an accompanying period duration by various parameters.: Additionne la durée des échanges en fonction de différents paramètres.
|
||||
Sum activity linked to an accompanying period visit duration: Somme de la durée de déplacement des échanges
|
||||
Sum activities linked to an accompanying period visit duration: Somme de la durée de déplacement des échanges liés à un parcours
|
||||
Sum activities linked to an accompanying period visit duration by various parameters.: Additionne la durée de déplacement des échanges en fonction de différents paramètres.
|
||||
Average activity linked to an accompanying period duration: Moyenne de la durée des échanges
|
||||
Average activities linked to an accompanying period duration: Moyenne de la durée des échanges liés à un parcours
|
||||
Average activities linked to an accompanying period duration by various parameters.: Moyenne de la durée des échanges en fonction de différents paramètres.
|
||||
Average activity linked to an accompanying period visit duration: Moyenne de la durée de déplacement des échanges
|
||||
Average activities linked to an accompanying period visit duration: Moyenne de la durée de déplacement des échanges liés à un parcours
|
||||
Average activities linked to an accompanying period visit duration by various parameters.: Moyenne de la durée de déplacement des échanges en fonction de différents paramètres.
|
||||
|
||||
#filters
|
||||
Filter by reason: Filtrer les activités par sujet
|
||||
Filter by reason: Filtrer les échanges par sujet
|
||||
'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%'
|
||||
'Filtered by activity type: only %list%': "Filtré par type d'activité: uniquement %list%"
|
||||
Filtered by date activity: Filtrer les activités par date
|
||||
Activities after this date: Activités après cette date
|
||||
Activities before this date: Activités avant cette date
|
||||
"Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'activité: uniquement entre %date_from% et %date_to%"
|
||||
This date should be after the date given in "Implied in an activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités après cette date"
|
||||
'Filtered by activity type: only %list%': "Filtré par type d'échange: uniquement %list%"
|
||||
Filtered by date activity: Filtrer les échanges par date
|
||||
Activities after this date: Échanges après cette date
|
||||
Activities before this date: Échanges avant cette date
|
||||
"Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'échange: uniquement entre %date_from% et %date_to%"
|
||||
This date should be after the date given in "Implied in an activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "échanges après cette date"
|
||||
|
||||
Filtered by person having an activity in a period: Uniquement les personnes ayant eu une activité dans la période donnée
|
||||
Implied in an activity after this date: Impliqué dans une activité après cette date
|
||||
Implied in an activity before this date: Impliqué dans une activité avant cette date
|
||||
Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par personnes associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name%
|
||||
Activity reasons for those activities: Sujets de ces activités
|
||||
Filtered by person having an activity in a period: Uniquement les usagers ayant eu un échange dans la période donnée
|
||||
Implied in an activity after this date: Impliqué dans un échange après cette date
|
||||
Implied in an activity before this date: Impliqué dans un échange avant cette date
|
||||
Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par usager associées à un échange entre %date_from% et %date_to% avec les sujets %reasons_name%
|
||||
Activity reasons for those activities: Sujets de ces échanges
|
||||
|
||||
Filter by activity type: Filtrer les activités par type
|
||||
Filter by activity type: Filtrer les échanges par type
|
||||
|
||||
Filter activity by location: Filtrer les activités par localisation
|
||||
Filter activity by location: Filtrer les échanges par localisation
|
||||
'Filtered activity by location: only %locations%': "Filtré par localisation: uniquement %locations%"
|
||||
Filter activity by locationtype: Filtrer les activités par type de localisation
|
||||
Filter activity by locationtype: Filtrer les échanges par type de localisation
|
||||
'Filtered activity by locationtype: only %types%': "Filtré par type de localisation: uniquement %types%"
|
||||
Accepted locationtype: Types de localisation
|
||||
Accepted users: TMS(s)
|
||||
Filter activity by emergency: Filtrer les activités par urgence
|
||||
Filter activity by emergency: Filtrer les échanges par urgence
|
||||
'Filtered activity by emergency: only %emergency%': "Filtré par urgence: uniquement si %emergency%"
|
||||
activity is emergency: l'activité est urgente
|
||||
activity is not emergency: l'activité n'est pas urgente
|
||||
Filter activity by sentreceived: Filtrer les activités par envoyé/reçu
|
||||
activity is emergency: l'échange est urgent
|
||||
activity is not emergency: l'échange n'est pas urgent
|
||||
Filter activity by sentreceived: Filtrer les échanges par envoyé/reçu
|
||||
'Filtered activity by sentreceived: only %sentreceived%': "Filtré par envoyé/reçu: uniquement %sentreceived%"
|
||||
Accepted sentreceived: ''
|
||||
Filter activity by linked socialaction: Filtrer les activités par action liée
|
||||
Filter activity by linked socialaction: Filtrer les échanges par action liée
|
||||
'Filtered activity by linked socialaction: only %actions%': "Filtré par action liée: uniquement %actions%"
|
||||
Filter activity by linked socialissue: Filtrer les activités par problématique liée
|
||||
Filter activity by linked socialissue: Filtrer les échanges par problématique liée
|
||||
'Filtered activity by linked socialissue: only %issues%': "Filtré par problématique liée: uniquement %issues%"
|
||||
Filter activity by user: Filtrer les activités par créateur
|
||||
Filter activity by users: Filtrer les activités par utilisateur participant
|
||||
Filter activity by creator: Filtrer les activités par créateur de l'échange
|
||||
Filter activity by user: Filtrer les échanges par créateur
|
||||
Filter activity by users: Filtrer les échanges par utilisateur participant
|
||||
Filter activity by creator: Filtrer les échanges par créateur de l'échange
|
||||
'Filtered activity by user: only %users%': "Filtré par référent: uniquement %users%"
|
||||
'Filtered activity by users: only %users%': "Filtré par utilisateurs participants: uniquement %users%"
|
||||
'Filtered activity by creator: only %users%': "Filtré par créateur: uniquement %users%"
|
||||
Creators: Créateurs
|
||||
Filter activity by userscope: Filtrer les activités par service du créateur
|
||||
Filter activity by userscope: Filtrer les échanges par service du créateur
|
||||
'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
|
||||
Accepted userscope: Services
|
||||
|
||||
Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activité
|
||||
Filtered acp which has no activities: Filtrer les parcours sans activité associée
|
||||
Group acp by activity number: Grouper les parcours par nombre d’activité
|
||||
Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’échange
|
||||
Filtered acp which has no activities: Filtrer les parcours sans échange associé
|
||||
Group acp by activity number: Grouper les parcours par nombre d’échange
|
||||
|
||||
#aggregators
|
||||
Activity type: Type d'activité
|
||||
Activity user: Utilisateur lié à l'activité
|
||||
Activity type: Type d'échange
|
||||
Activity user: Utilisateur lié à l'échange
|
||||
By reason: Par sujet
|
||||
By category of reason: Par catégorie de sujet
|
||||
Reason's level: Niveau du sujet
|
||||
Group by reasons: Sujet d'activité
|
||||
Aggregate by activity user: Grouper les activités par référent
|
||||
Aggregate by activity users: Grouper les activités par utilisateurs participants
|
||||
Aggregate by activity type: Grouper les activités par type
|
||||
Aggregate by activity reason: Grouper les activités par sujet
|
||||
Aggregate by users scope: Grouper les activités par service principal de l'utilisateur
|
||||
Users 's scope: Service principal des utilisateurs participants à l'activité
|
||||
Aggregate by users job: Grouper les activités par métier des utilisateurs participants
|
||||
Users 's job: Métier des utilisateurs participants à l'activité
|
||||
Group by reasons: Sujet d'échange
|
||||
Aggregate by activity user: Grouper les échanges par référent
|
||||
Aggregate by activity users: Grouper les échanges par utilisateurs participants
|
||||
Aggregate by activity type: Grouper les échanges par type
|
||||
Aggregate by activity reason: Grouper les échanges par sujet
|
||||
Aggregate by users scope: Grouper les échanges par service principal de l'utilisateur
|
||||
Users 's scope: Service principal des utilisateurs participants à l'échange
|
||||
Aggregate by users job: Grouper les échanges par métier des utilisateurs participants
|
||||
Users 's job: Métier des utilisateurs participants à l'échange
|
||||
|
||||
Group activity by locationtype: Grouper les activités par type de localisation
|
||||
Group activity by date: Grouper les activités par date
|
||||
Group activity by locationtype: Grouper les échanges par type de localisation
|
||||
Group activity by date: Grouper les échanges par date
|
||||
Frequency: Fréquence
|
||||
by month: Par mois
|
||||
by week: Par semaine
|
||||
for week: Semaine
|
||||
by year: Par année
|
||||
in year: En
|
||||
Group activity by creator: Grouper les activités par créateur de l'échange
|
||||
Group activity by creator scope: Grouper les activités par service du créateur de l'échange
|
||||
Group activity by linked thirdparties: Grouper les activités par tiers impliqué
|
||||
Group activity by creator: Grouper les échanges par créateur de l'échange
|
||||
Group activity by creator scope: Grouper les échanges par service du créateur de l'échange
|
||||
Group activity by linked thirdparties: Grouper les échanges par tiers impliqué
|
||||
Accepted thirdparty: Tiers impliqué
|
||||
Group activity by linked socialaction: Grouper les activités par action liée
|
||||
Group activity by linked socialissue: Grouper les activités par problématique liée
|
||||
Group activity by userscope: Grouper les activités par service du créateur
|
||||
Group activity by linked socialaction: Grouper les échanges par action liée
|
||||
Group activity by linked socialissue: Grouper les échanges par problématique liée
|
||||
Group activity by userscope: Grouper les échanges par service du créateur
|
||||
|
||||
Last activities: Les dernières activités
|
||||
Last activities: Les derniers échanges
|
||||
|
||||
See activity in accompanying course context: Voir l'activité dans le contexte du parcours d'accompagnement
|
||||
See activity in accompanying course context: Voir l'échange dans le contexte du parcours d'accompagnement
|
||||
|
||||
You get notified of an activity which does not exists any more: Cette notification ne correspond pas à une activité valide.
|
||||
you are not allowed to see it details: La notification fait référence à une activité à laquelle vous n'avez pas accès.
|
||||
This is the minimal activity data: Activité n°
|
||||
You get notified of an activity which does not exists any more: Cette notification ne correspond pas à un échange valide.
|
||||
you are not allowed to see it details: La notification fait référence à un échange auquel vous n'avez pas accès.
|
||||
This is the minimal activity data: Échange n°
|
||||
|
||||
docgen:
|
||||
Activity basic: Echange
|
||||
A basic context for activity: Contexte pour les activités
|
||||
Accompanying period with a list of activities: Parcours d'accompagnement avec liste des activités
|
||||
Accompanying period with a list of activities description: Ce contexte reprend les informations du parcours, et tous les activités pour un parcours. Les activités ne sont pas filtrés.
|
||||
Activity basic: Échange
|
||||
A basic context for activity: Contexte pour les échanges
|
||||
Accompanying period with a list of activities: Parcours d'accompagnement avec liste des échanges
|
||||
Accompanying period with a list of activities description: Ce contexte reprend les informations du parcours, et tous les échanges pour un parcours. Les échanges ne sont pas filtrés.
|
||||
myActivitiesOnly: Prendre en compte uniquement les échanges dans lesquels je suis intervenu
|
||||
myWorksOnly: Prendre en compte uniquement les actions d'accompagnement dont je suis référent
|
||||
|
||||
export:
|
||||
list:
|
||||
@@ -336,10 +341,10 @@ export:
|
||||
users name: Nom des utilisateurs
|
||||
users ids: Identifiant des utilisateurs
|
||||
third parties ids: Identifiant des tiers
|
||||
persons ids: Identifiant des personnes
|
||||
persons name: Nom des personnes
|
||||
persons ids: Identifiant des usagers
|
||||
persons name: Nom des usagers
|
||||
thirds parties: Tiers
|
||||
date: Date de l'activité
|
||||
date: Date de l'échange
|
||||
locationName: Localisation
|
||||
sent received: Envoyé ou reçu
|
||||
emergency: Urgence
|
||||
@@ -348,17 +353,17 @@ export:
|
||||
travelTime: Durée de déplacement
|
||||
durationTime: Durée
|
||||
id: Identifiant
|
||||
List activities linked to an accompanying course: Liste les activités liées à un parcours en fonction de différents filtres.
|
||||
List activity linked to a course: Liste des activités liées à un parcours
|
||||
List activities linked to an accompanying course: Liste les échanges liés à un parcours en fonction de différents filtres.
|
||||
List activity linked to a course: Liste des échanges liés à un parcours
|
||||
|
||||
|
||||
filter:
|
||||
activity:
|
||||
by_usersjob:
|
||||
Filter by users job: Filtrer les activités par métier d'au moins un utilisateur participant
|
||||
Filter by users job: Filtrer les échanges par métier d'au moins un utilisateur participant
|
||||
'Filtered activity by users job: only %jobs%': 'Filtré par métier d''au moins un utilisateur participant: seulement %jobs%'
|
||||
by_usersscope:
|
||||
Filter by users scope: Filtrer les activités par services d'au moins un utilisateur participant
|
||||
Filter by users scope: Filtrer les échanges par services d'au moins un utilisateur participant
|
||||
'Filtered activity by users scope: only %scopes%': 'Filtré par service d''au moins un utilisateur participant: seulement %scopes%'
|
||||
aggregator:
|
||||
activity:
|
||||
@@ -366,4 +371,4 @@ export:
|
||||
Sent or received: Envoyé ou reçu
|
||||
is sent: envoyé
|
||||
is received: reçu
|
||||
Group activity by sentreceived: Grouper les activités par envoyé / reçu
|
||||
Group activity by sentreceived: Grouper les échanges par envoyé / reçu
|
||||
|
@@ -47,10 +47,10 @@ Reasons: Onderwerpen
|
||||
|
||||
|
||||
#forms
|
||||
Activity creation: Nouvelle activité
|
||||
Activity creation: Nouvel échange
|
||||
Create: Créer
|
||||
Back to the list: Retour à la liste
|
||||
Save activity: Sauver l'activité
|
||||
Save activity: Sauver l'échange
|
||||
Reset form: Remise à zéro du formulaire
|
||||
Choose the duration: Choisir la durée
|
||||
Choose a type: Choisir un type
|
||||
@@ -79,43 +79,43 @@ activity:
|
||||
No documents: Aucun document
|
||||
|
||||
#timeline
|
||||
'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"'
|
||||
'%user% has done an %activity_type%': '%user% a effectué un échange de type "%activity_type%"'
|
||||
|
||||
#controller
|
||||
'Success : activity created!': L'activité a été créée.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'activité n'a pas été créée.
|
||||
'Success : activity updated!': L'activité a été mise à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'activité n'a pas été mise à jour.
|
||||
'Success : activity created!': L'échange a été créé.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'échange n'a pas été créé.
|
||||
'Success : activity updated!': L'échange a été mis à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'échange n'a pas été mis à jour.
|
||||
|
||||
# ROLES
|
||||
CHILL_ACTIVITY_CREATE: Créer une activité
|
||||
CHILL_ACTIVITY_UPDATE: Modifier une activité
|
||||
CHILL_ACTIVITY_SEE: Voir une activité
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des activités
|
||||
CHILL_ACTIVITY_DELETE: Supprimer une activité
|
||||
CHILL_ACTIVITY_STATS: Statistique des activités
|
||||
CHILL_ACTIVITY_LIST: Liste des activités
|
||||
CHILL_ACTIVITY_CREATE: Créer un échange
|
||||
CHILL_ACTIVITY_UPDATE: Modifier un échange
|
||||
CHILL_ACTIVITY_SEE: Voir un échange
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des échanges
|
||||
CHILL_ACTIVITY_DELETE: Supprimer un échange
|
||||
CHILL_ACTIVITY_STATS: Statistique des échanges
|
||||
CHILL_ACTIVITY_LIST: Liste des échanges
|
||||
|
||||
# admin
|
||||
Activities: Activités
|
||||
Activity configuration: Configuration des activités
|
||||
Activity configuration menu: Configuration des activités
|
||||
Activity types: Types d'activité
|
||||
Activity type configuration: Configuration des categories d'activités
|
||||
Activity Reasons: Sujets d'une activité
|
||||
Activity Reasons Category: Catégories de sujet d'activités
|
||||
Activity Types Categories: Catégories des types d'activité
|
||||
Activity Presences: Presences des activités
|
||||
Activities: Échanges
|
||||
Activity configuration: Configuration des échanges
|
||||
Activity configuration menu: Configuration des échanges
|
||||
Activity types: Types d'échange
|
||||
Activity type configuration: Configuration des categories d'échanges
|
||||
Activity Reasons: Sujets d'un échange
|
||||
Activity Reasons Category: Catégories de sujet d'échanges
|
||||
Activity Types Categories: Catégories des types d'échanges
|
||||
Activity Presences: Presences des échanges
|
||||
|
||||
|
||||
# Crud
|
||||
crud:
|
||||
activity_type:
|
||||
title_new: Nouveau type d'activité
|
||||
title_edit: Edition d'un type d'activité
|
||||
title_new: Nouveau type d'échange
|
||||
title_edit: Edition d'un type d'échange
|
||||
activity_type_category:
|
||||
title_new: Nouvelle catégorie de type d'activité
|
||||
title_edit: Edition d'une catégorie de type d'activité
|
||||
title_new: Nouvelle catégorie de type d'échange
|
||||
title_edit: Edition d'une catégorie de type d'échange
|
||||
|
||||
# activity reason admin
|
||||
ActivityReason list: Liste des sujets
|
||||
@@ -124,7 +124,7 @@ Active: Actif
|
||||
Category: Catégorie
|
||||
ActivityReason creation: Nouveau sujet
|
||||
ActivityReason edit: Modification d'un sujet
|
||||
ActivityReason: Sujet d'activité
|
||||
ActivityReason: Sujet d'échange
|
||||
The entity is inactive and won't be proposed: Le sujet est inactif et ne sera pas proposé
|
||||
The entity is active and will be proposed: Le sujet est actif et sera proposé
|
||||
|
||||
@@ -133,13 +133,13 @@ ActivityReasonCategory list: Catégories de sujets
|
||||
Create a new activity category reason: Créer une nouvelle catégorie
|
||||
ActivityReasonCategory creation: Nouvelle catégorie de sujet
|
||||
ActivityReasonCategory edit: Modification d'une catégorie de sujet
|
||||
ActivityReasonCategory: Catégorie de sujet d'activité
|
||||
ActivityReasonCategory: Catégorie de sujet d'échange
|
||||
ActivityReasonCategory is active and will be proposed: La catégorie est active et sera proposée
|
||||
ActivityReasonCategory is inactive and won't be proposed: La catégorie est inactive et ne sera pas proposée
|
||||
|
||||
# activity type type admin
|
||||
ActivityType list: Types d'activités
|
||||
Create a new activity type: Créer un nouveau type d'activité
|
||||
ActivityType list: Types d'échanges
|
||||
Create a new activity type: Créer un nouveau type d'échange
|
||||
Persons visible: Visibilité du champ Personnes
|
||||
Persons label: Libellé du champ Personnes
|
||||
User visible: Visibilité du champ Utilisateur
|
||||
@@ -177,20 +177,20 @@ Documents label: Libellé du champ Documents
|
||||
|
||||
# activity type category admin
|
||||
ActivityTypeCategory list: Liste des catégories des types d'activité
|
||||
Create a new activity type category: Créer une nouvelle catégorie de type d'activité
|
||||
Create a new activity type category: Créer une nouvelle catégorie de type d'échange
|
||||
|
||||
# activity delete
|
||||
Remove activity: Supprimer une activité
|
||||
Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité qui concerne "%name%" ?
|
||||
The activity has been successfully removed.: L'activité a été supprimée.
|
||||
Remove activity: Supprimer un échange
|
||||
Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer un échange qui concerne "%name%" ?
|
||||
The activity has been successfully removed.: L'échange a été supprimée.
|
||||
|
||||
# exports
|
||||
Count activities: Nombre d'activités
|
||||
Count activities by various parameters.: Compte le nombre d'activités enregistrées en fonction de différents paramètres.
|
||||
Sum activity duration: Total de la durée des activités
|
||||
Sum activities duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
List activities: Liste les activités
|
||||
Number of activities: Nombre d'activités
|
||||
Count activities: Nombre d'échanges
|
||||
Count activities by various parameters.: Compte le nombre d'échanges enregistrées en fonction de différents paramètres.
|
||||
Sum activity duration: Total de la durée des échanges
|
||||
Sum activities duration by various parameters.: Additionne la durée des échanges en fonction de différents paramètres.
|
||||
List activities: Liste les échanges
|
||||
Number of activities: Nombre d'échanges
|
||||
|
||||
#filters
|
||||
Filter by reason: Filtrer par sujet d'activité
|
||||
|
@@ -1,22 +1,22 @@
|
||||
The reasons's level should not be empty: Le niveau du sujet ne peut pas être vide
|
||||
At least one reason must be choosen: Au moins un sujet doit être choisi
|
||||
For this type of activity, you must add at least one person: Pour ce type d'activité, vous devez ajouter au moins un usager
|
||||
For this type of activity, you must add at least one user: Pour ce type d'activité, vous devez ajouter au moins un utilisateur
|
||||
For this type of activity, you must add at least one third party: Pour ce type d'activité, vous devez ajouter au moins un tiers
|
||||
For this type of activity, user is required: Pour ce type d'activité, l'utilisateur est requis
|
||||
For this type of activity, date is required: Pour ce type d'activité, la date est requise
|
||||
For this type of activity, location is required: Pour ce type d'activité, la localisation est requise
|
||||
For this type of activity, attendee is required: Pour ce type d'activité, le champ "Présence de la personne" est requis
|
||||
For this type of activity, duration time is required: Pour ce type d'activité, la durée est requise
|
||||
For this type of activity, travel time is required: Pour ce type d'activité, la durée du trajet est requise
|
||||
For this type of activity, reasons is required: Pour ce type d'activité, le champ "sujet" est requis
|
||||
For this type of activity, comment is required: Pour ce type d'activité, un commentaire est requis
|
||||
For this type of activity, sent/received is required: Pour ce type d'activité, le champ Entrant/Sortant est requis
|
||||
For this type of activity, document is required: Pour ce type d'activité, un document est requis
|
||||
For this type of activity, emergency is required: Pour ce type d'activité, le champ "Urgent" est requis
|
||||
For this type of activity, accompanying period is required: Pour ce type d'activité, le parcours d'accompagnement est requis
|
||||
For this type of activity, you must add at least one social issue: Pour ce type d'activité, vous devez ajouter au moins une problématique sociale
|
||||
For this type of activity, you must add at least one social action: Pour ce type d'activité, vous devez indiquer au moins une action sociale
|
||||
For this type of activity, you must add at least one person: Pour ce type d'échange, vous devez ajouter au moins un usager
|
||||
For this type of activity, you must add at least one user: Pour ce type d'échange, vous devez ajouter au moins un utilisateur
|
||||
For this type of activity, you must add at least one third party: Pour ce type d'échange, vous devez ajouter au moins un tiers
|
||||
For this type of activity, user is required: Pour ce type d'échange, l'utilisateur est requis
|
||||
For this type of activity, date is required: Pour ce type d'échange, la date est requise
|
||||
For this type of activity, location is required: Pour ce type d'échange, la localisation est requise
|
||||
For this type of activity, attendee is required: Pour ce type d'échange, le champ "Présence de l'usager" est requis
|
||||
For this type of activity, duration time is required: Pour ce type d'échange, la durée est requise
|
||||
For this type of activity, travel time is required: Pour ce type d'échange, la durée du trajet est requise
|
||||
For this type of activity, reasons is required: Pour ce type d'échange, le champ "sujet" est requis
|
||||
For this type of activity, comment is required: Pour ce type d'échange, un commentaire est requis
|
||||
For this type of activity, sent/received is required: Pour ce type d'échange, le champ Entrant/Sortant est requis
|
||||
For this type of activity, document is required: Pour ce type d'échange, un document est requis
|
||||
For this type of activity, emergency is required: Pour ce type d'échange, le champ "Urgent" est requis
|
||||
For this type of activity, accompanying period is required: Pour ce type d'échange, le parcours d'accompagnement est requis
|
||||
For this type of activity, you must add at least one social issue: Pour ce type d'échange, vous devez ajouter au moins une problématique sociale
|
||||
For this type of activity, you must add at least one social action: Pour ce type d'échange, vous devez indiquer au moins une action sociale
|
||||
|
||||
# admin
|
||||
This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales"
|
||||
|
@@ -22,7 +22,7 @@ class Configuration implements ConfigurationInterface
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_aside_activity');
|
||||
|
||||
$treeBuilder->getRootNode('chill_aside_activity')
|
||||
$treeBuilder->getRootNode()
|
||||
->children()
|
||||
->arrayNode('form')
|
||||
->canBeEnabled()
|
||||
@@ -132,9 +132,7 @@ class Configuration implements ConfigurationInterface
|
||||
->info('The number of seconds of this duration. Must be an integer.')
|
||||
->cannotBeEmpty()
|
||||
->validate()
|
||||
->ifTrue(static function ($data) {
|
||||
return !is_int($data);
|
||||
})->thenInvalid('The value %s is not a valid integer')
|
||||
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('label')
|
||||
|
@@ -57,7 +57,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private ?int $id;
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=100, nullable=true)
|
||||
|
@@ -59,9 +59,7 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
return static fn ($value) => $labels[$value];
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
|
@@ -160,8 +160,8 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
||||
return 'export.aside_activity.main_center';
|
||||
}
|
||||
|
||||
/** @var Center $c */
|
||||
if (null === $value || '' === $value || null === $c = $this->centerRepository->find($value)) {
|
||||
/** @var Center $c */
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -190,10 +190,6 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $query
|
||||
* @param array $data
|
||||
*/
|
||||
public function getResult($query, $data): array
|
||||
{
|
||||
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
@@ -28,22 +28,17 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
use function in_array;
|
||||
|
||||
final class AsideActivityFormType extends AbstractType
|
||||
{
|
||||
private TokenStorageInterface $storage;
|
||||
|
||||
private array $timeChoices;
|
||||
|
||||
public function __construct(
|
||||
ParameterBagInterface $parameterBag,
|
||||
TokenStorageInterface $storage
|
||||
) {
|
||||
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
@@ -100,9 +95,7 @@ final class AsideActivityFormType extends AbstractType
|
||||
// the datetimetransformer will then handle timezone as GMT
|
||||
$timezoneUTC = new DateTimeZone('GMT');
|
||||
/** @var DateTimeImmutable $data */
|
||||
$data = $formEvent->getData() === null ?
|
||||
DateTime::createFromFormat('U', '300') :
|
||||
$formEvent->getData();
|
||||
$data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300');
|
||||
$seconds = $data->getTimezone()->getOffset($data);
|
||||
$data->setTimeZone($timezoneUTC);
|
||||
$data->add(new DateInterval('PT' . $seconds . 'S'));
|
||||
|
@@ -44,17 +44,6 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
|
||||
'order' => 11,
|
||||
'icons' => ['plus'],
|
||||
]);
|
||||
$menu->addChild($this->translator->trans('Phonecall'), [
|
||||
'route' => 'chill_crud_aside_activity_new',
|
||||
'routeParameters' => [
|
||||
'type' => 1,
|
||||
'duration' => 900,
|
||||
],
|
||||
])
|
||||
->setExtras([
|
||||
'order' => 12,
|
||||
'icons' => ['plus'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ Type: Type
|
||||
Invisible: Invisible
|
||||
Optional: Optionnel
|
||||
Required: Obligatoire
|
||||
Persons: Personnes
|
||||
Persons: Usagers
|
||||
Users: Utilisateurs
|
||||
Emergency: Urgent
|
||||
by: "Par "
|
||||
@@ -50,7 +50,7 @@ For agent: Pour l'utilisateur
|
||||
date: Date
|
||||
Duration: Durée
|
||||
Note: Note
|
||||
Choose the agent for whom this activity is created: Choisissez l'agent pour qui l'activité est créée
|
||||
Choose the agent for whom this activity is created: Choisissez l'agent pour qui l'échange est créé
|
||||
Choose the activity category: Choisir la catégorie
|
||||
|
||||
#Duration
|
||||
|
@@ -11,12 +11,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\BudgetBundle\Calculator;
|
||||
|
||||
use Chill\BudgetBundle\Entity\AbstractElement;
|
||||
use Chill\BudgetBundle\Entity\Charge;
|
||||
use Chill\BudgetBundle\Entity\Resource;
|
||||
|
||||
interface CalculatorInterface
|
||||
{
|
||||
/**
|
||||
* @param AbstractElement[] $elements
|
||||
* @param array<Charge|Resource> $elements
|
||||
*/
|
||||
public function calculate(array $elements): ?CalculatorResult;
|
||||
|
||||
|
@@ -12,6 +12,8 @@ declare(strict_types=1);
|
||||
namespace Chill\BudgetBundle\Calculator;
|
||||
|
||||
use Chill\BudgetBundle\Entity\AbstractElement;
|
||||
use Chill\BudgetBundle\Entity\Charge;
|
||||
use Chill\BudgetBundle\Entity\Resource;
|
||||
use OutOfBoundsException;
|
||||
|
||||
use function array_key_exists;
|
||||
@@ -21,11 +23,14 @@ use function implode;
|
||||
class CalculatorManager
|
||||
{
|
||||
/**
|
||||
* @var CalculatorInterface[]
|
||||
* @var array<string, CalculatorInterface>
|
||||
*/
|
||||
protected $calculators = [];
|
||||
private array $calculators = [];
|
||||
|
||||
protected $defaultCalculator = [];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private array $defaultCalculator = [];
|
||||
|
||||
public function addCalculator(CalculatorInterface $calculator, bool $default)
|
||||
{
|
||||
@@ -37,7 +42,7 @@ class CalculatorManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractElement[] $elements
|
||||
* @param array<Resource|Charge> $elements
|
||||
*
|
||||
* @return CalculatorResult[]
|
||||
*/
|
||||
@@ -46,23 +51,17 @@ class CalculatorManager
|
||||
$results = [];
|
||||
|
||||
foreach ($this->defaultCalculator as $alias) {
|
||||
$calculator = $this->calculators[$alias];
|
||||
$result = $calculator->calculate($elements);
|
||||
$result = $this->getCalculator($alias)->calculate($elements);
|
||||
|
||||
if (null !== $result) {
|
||||
$results[$calculator->getAlias()] = $result;
|
||||
$results[$alias] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $alias
|
||||
*
|
||||
* @return CalculatorInterface
|
||||
*/
|
||||
public function getCalculator($alias)
|
||||
public function getCalculator(string $alias): CalculatorInterface
|
||||
{
|
||||
if (false === array_key_exists($alias, $this->calculators)) {
|
||||
throw new OutOfBoundsException("The calculator with alias '{$alias}' does "
|
||||
|
@@ -116,7 +116,7 @@ abstract class AbstractElementController extends AbstractController
|
||||
$indexPage = 'chill_budget_elements_household_index';
|
||||
}
|
||||
|
||||
$entity = null !== $element->getPerson() ? $element->getPerson() : $element->getHousehold();
|
||||
$entity = $element->getPerson() ?? $element->getHousehold();
|
||||
|
||||
$form = $this->createForm($this->getType(), $element);
|
||||
$form->add('submit', SubmitType::class);
|
||||
|
@@ -14,6 +14,8 @@ namespace Chill\BudgetBundle\Controller;
|
||||
use Chill\BudgetBundle\Calculator\CalculatorManager;
|
||||
use Chill\BudgetBundle\Entity\Charge;
|
||||
use Chill\BudgetBundle\Entity\Resource;
|
||||
use Chill\BudgetBundle\Repository\ChargeRepository;
|
||||
use Chill\BudgetBundle\Repository\ResourceRepository;
|
||||
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
@@ -29,24 +31,20 @@ use function count;
|
||||
|
||||
class ElementController extends AbstractController
|
||||
{
|
||||
protected CalculatorManager $calculator;
|
||||
private CalculatorManager $calculator;
|
||||
|
||||
protected LoggerInterface $chillMainLogger;
|
||||
private ResourceRepository $resourceRepository;
|
||||
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
protected TranslatorInterface $translator;
|
||||
private ChargeRepository $chargeRepository;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
TranslatorInterface $translator,
|
||||
LoggerInterface $chillMainLogger,
|
||||
CalculatorManager $calculator
|
||||
CalculatorManager $calculator,
|
||||
ResourceRepository $resourceRepository,
|
||||
ChargeRepository $chargeRepository,
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->translator = $translator;
|
||||
$this->chillMainLogger = $chillMainLogger;
|
||||
$this->calculator = $calculator;
|
||||
$this->resourceRepository = $resourceRepository;
|
||||
$this->chargeRepository = $chargeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,24 +57,10 @@ class ElementController extends AbstractController
|
||||
{
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::SEE, $person);
|
||||
|
||||
$charges = $this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByPerson($person);
|
||||
$charges = $this->chargeRepository->findAllByEntity($person);
|
||||
$resources = $this->resourceRepository->findAllByEntity($person);
|
||||
|
||||
$ressources = $this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByPerson($person);
|
||||
|
||||
$now = new DateTime('now');
|
||||
|
||||
$actualCharges = $this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByEntityAndDate($person, $now);
|
||||
$actualResources = $this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByEntityAndDate($person, $now);
|
||||
|
||||
$elements = array_merge($actualCharges, $actualResources);
|
||||
$elements = array_merge($charges, $resources);
|
||||
|
||||
if (count($elements) > 0) {
|
||||
$results = $this->calculator->calculateDefault($elements);
|
||||
@@ -85,7 +69,7 @@ class ElementController extends AbstractController
|
||||
return $this->render('ChillBudgetBundle:Person:index.html.twig', [
|
||||
'person' => $person,
|
||||
'charges' => $charges,
|
||||
'resources' => $ressources,
|
||||
'resources' => $resources,
|
||||
'results' => $results ?? [],
|
||||
]);
|
||||
}
|
||||
@@ -100,60 +84,19 @@ class ElementController extends AbstractController
|
||||
{
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::SEE, $household);
|
||||
|
||||
$charges = $this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByHousehold($household);
|
||||
$charges = $this->chargeRepository->findAllByEntity($household);
|
||||
$resources = $this->resourceRepository->findAllByEntity($household);
|
||||
|
||||
$ressources = $this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByHousehold($household);
|
||||
|
||||
$now = new DateTime('now');
|
||||
|
||||
$actualCharges = $this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByEntityAndDate($household, $now);
|
||||
$actualResources = $this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByEntityAndDate($household, $now);
|
||||
|
||||
$elements = array_merge($actualCharges, $actualResources);
|
||||
$elements = array_merge($charges, $resources);
|
||||
|
||||
if (count($elements) > 0) {
|
||||
$results = $this->calculator->calculateDefault($elements);
|
||||
}
|
||||
|
||||
// quick solution to calculate the sum, difference and amount from
|
||||
// controller. This should be done from the calculators
|
||||
// TODO replace this by calculators
|
||||
$wholeCharges = $actualCharges;
|
||||
$wholeResources = $actualResources;
|
||||
|
||||
foreach ($household->getCurrentPersons() as $person) {
|
||||
$wholeCharges = array_merge(
|
||||
$wholeCharges,
|
||||
$this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByEntityAndDate($person, $now)
|
||||
);
|
||||
$wholeResources = array_merge(
|
||||
$wholeResources,
|
||||
$this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByEntityAndDate($person, $now)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->render('ChillBudgetBundle:Household:index.html.twig', [
|
||||
'household' => $household,
|
||||
'charges' => $charges,
|
||||
'resources' => $ressources,
|
||||
'wholeResources' => array_filter($wholeResources, static function (Resource $r) use ($now) {
|
||||
return $r->getStartDate() <= $now && ($r->getEndDate() === null || $r->getEndDate() >= $now);
|
||||
}),
|
||||
'wholeCharges' => array_filter($wholeCharges, static function (Charge $c) use ($now) {
|
||||
return $c->getStartDate() <= $now && ($c->getEndDate() === null || $c->getEndDate() >= $now);
|
||||
}),
|
||||
'resources' => $resources,
|
||||
'results' => $results ?? [],
|
||||
]);
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ class CalculatorCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$manager = $container->getDefinition('Chill\BudgetBundle\Calculator\CalculatorManager');
|
||||
$manager = $container->getDefinition(\Chill\BudgetBundle\Calculator\CalculatorManager::class);
|
||||
|
||||
foreach ($container->findTaggedServiceIds('chill_budget.calculator') as $id => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
|
@@ -19,7 +19,7 @@ class Configuration implements ConfigurationInterface
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_budget');
|
||||
$rootNode = $treeBuilder->getRootNode('chill_budget');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
|
@@ -41,7 +41,7 @@ abstract class AbstractElement
|
||||
/**
|
||||
* @ORM\Column(name="comment", type="text", nullable=true)
|
||||
*/
|
||||
private ?string $comment;
|
||||
private ?string $comment = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="endDate", type="datetime_immutable", nullable=true)
|
||||
@@ -50,7 +50,7 @@ abstract class AbstractElement
|
||||
* message="The budget element's end date must be after the start date"
|
||||
* )
|
||||
*/
|
||||
private ?DateTimeImmutable $endDate;
|
||||
private ?DateTimeImmutable $endDate = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(
|
||||
|
@@ -52,9 +52,7 @@ class ChargeType extends AbstractType
|
||||
'label' => 'Charge type',
|
||||
'required' => true,
|
||||
'placeholder' => $this->translator->trans('admin.form.Choose the type of charge'),
|
||||
'choice_label' => function (ChargeKind $resource) {
|
||||
return $this->translatableStringHelper->localize($resource->getName());
|
||||
},
|
||||
'choice_label' => fn (ChargeKind $resource) => $this->translatableStringHelper->localize($resource->getName()),
|
||||
'attr' => ['class' => 'select2'],
|
||||
])
|
||||
->add('amount', MoneyType::class)
|
||||
|
@@ -51,9 +51,7 @@ class ResourceType extends AbstractType
|
||||
'label' => 'Resource type',
|
||||
'required' => true,
|
||||
'placeholder' => $this->translator->trans('admin.form.Choose the type of resource'),
|
||||
'choice_label' => function (ResourceKind $resource) {
|
||||
return $this->translatableStringHelper->localize($resource->getName());
|
||||
},
|
||||
'choice_label' => fn (ResourceKind $resource) => $this->translatableStringHelper->localize($resource->getName()),
|
||||
'attr' => ['class' => 'select2'],
|
||||
])
|
||||
->add('amount', MoneyType::class)
|
||||
|
@@ -30,7 +30,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
@@ -38,7 +38,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllActive(): array
|
||||
{
|
||||
@@ -53,7 +53,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array
|
||||
{
|
||||
@@ -64,7 +64,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
*
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
|
@@ -19,25 +19,25 @@ interface ChargeKindRepositoryInterface extends ObjectRepository
|
||||
public function find($id): ?ChargeKind;
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAll(): array;
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllActive(): array;
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array;
|
||||
|
||||
/**
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
*
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array;
|
||||
|
||||
|
@@ -11,9 +11,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\BudgetBundle\Repository;
|
||||
|
||||
use Chill\BudgetBundle\Entity\Charge;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* ChargeRepository.
|
||||
@@ -21,24 +24,44 @@ use Doctrine\ORM\EntityRepository;
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class ChargeRepository extends EntityRepository
|
||||
class ChargeRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Charge::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Charge[]
|
||||
*/
|
||||
public function findAllByEntity(Person|Household $entity): array
|
||||
{
|
||||
$qb = $this->createQueryBuilder('c');
|
||||
|
||||
$property = $entity instanceof Person ? 'person' : 'household';
|
||||
|
||||
$qb->where("c.{$property} = :entity")
|
||||
->setParameter('entity', $entity);
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function findByEntityAndDate($entity, DateTime $date, $sort = null)
|
||||
{
|
||||
$qb = $this->createQueryBuilder('c');
|
||||
|
||||
$entityStr = $entity instanceof Person ? 'person' : 'household';
|
||||
|
||||
$qb->where("c.{$entityStr} = :{$entityStr}")
|
||||
->andWhere('c.startDate < :date')
|
||||
->andWhere('c.startDate < :date OR c.startDate IS NULL');
|
||||
$qb->where("c.{$entityStr} = :entity")
|
||||
->andWhere('c.startDate <= :date')
|
||||
->andWhere('c.endDate > :date OR c.endDate IS NULL');
|
||||
|
||||
if (null !== $sort) {
|
||||
$qb->orderBy($sort);
|
||||
}
|
||||
|
||||
$qb->setParameters([
|
||||
$entityStr => $entity,
|
||||
'entity' => $entity,
|
||||
'date' => $date,
|
||||
]);
|
||||
|
||||
|
@@ -30,7 +30,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
@@ -38,7 +38,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllActive(): array
|
||||
{
|
||||
@@ -58,7 +58,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array
|
||||
{
|
||||
@@ -69,7 +69,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
*
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
|
@@ -19,25 +19,25 @@ interface ResourceKindRepositoryInterface extends ObjectRepository
|
||||
public function find($id): ?ResourceKind;
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAll(): array;
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllActive(): array;
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array;
|
||||
|
||||
/**
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
*
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array;
|
||||
|
||||
|
@@ -11,9 +11,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\BudgetBundle\Repository;
|
||||
|
||||
use Chill\BudgetBundle\Entity\Resource;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use DateTime;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* ResourceRepository.
|
||||
@@ -21,28 +25,45 @@ use Doctrine\ORM\EntityRepository;
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class ResourceRepository extends EntityRepository
|
||||
class ResourceRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function findByEntityAndDate($entity, DateTime $date, $sort = null)
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Resource::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Resource[]
|
||||
*/
|
||||
public function findAllByEntity(Person|Household $entity): array
|
||||
{
|
||||
$qb = $this->createQueryBuilder('r');
|
||||
|
||||
$property = $entity instanceof Person ? 'person' : 'household';
|
||||
|
||||
$qb->where("r.{$property} = :entity")
|
||||
->setParameter('entity', $entity);
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function findByEntityAndDate(Person|Household $entity, DateTime $date, $sort = null)
|
||||
{
|
||||
$qb = $this->createQueryBuilder('c');
|
||||
|
||||
$entityStr = $entity instanceof Person ? 'person' : 'household';
|
||||
|
||||
$qb->where("c.{$entityStr} = :{$entityStr}")
|
||||
// TODO: in controller, the budget and charges asked are also for future and actual
|
||||
//->andWhere('c.startDate < :date')
|
||||
// TODO: there is a misconception here, the end date must be lower or null. startDate are never null
|
||||
//->andWhere('c.startDate < :date OR c.startDate IS NULL');
|
||||
;
|
||||
$qb->where("c.{$entityStr} = :entity")
|
||||
->andWhere('c.startDate <= :date')
|
||||
->andWhere('c.endDate > :date OR c.endDate IS NULL');
|
||||
|
||||
if (null !== $sort) {
|
||||
$qb->orderBy($sort);
|
||||
}
|
||||
|
||||
$qb->setParameters([
|
||||
$entityStr => $entity,
|
||||
//'date' => $date,
|
||||
'entity' => $entity,
|
||||
'date' => $date,
|
||||
]);
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
|
@@ -1,39 +1,42 @@
|
||||
.subtitle {
|
||||
h3.subtitle {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 1rem;
|
||||
&::before {
|
||||
font: normal normal normal 20px/1 ForkAwesome;
|
||||
margin-right: 0.5em;
|
||||
content: "\f061";
|
||||
}
|
||||
.family-title {
|
||||
}
|
||||
|
||||
$col_charge: #e03851d7;
|
||||
$col_resource: #6d9e63d8;
|
||||
|
||||
h4.family-title {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem !important;
|
||||
padding-left: 0.7em;
|
||||
i {
|
||||
margin-right: 0.4em;
|
||||
}
|
||||
&.charge i { color: $col_charge; }
|
||||
&.resource i { color: $col_resource; }
|
||||
}
|
||||
.budget-table th {
|
||||
th {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.budget-table {
|
||||
th.charge {
|
||||
background-color: #e03851d7;
|
||||
}
|
||||
}
|
||||
.budget-table {
|
||||
th.resource {
|
||||
background-color: #6d9e63d8;
|
||||
}
|
||||
}
|
||||
.budget-table {
|
||||
|
||||
table.budget-table {
|
||||
th, td {
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
td.column-wide {
|
||||
width: 20%;
|
||||
}
|
||||
td.column-small {
|
||||
width: 15%;
|
||||
&.right {
|
||||
align-items: right;
|
||||
}
|
||||
th.charge { background-color: $col_charge; }
|
||||
th.resource { background-color: $col_resource; }
|
||||
td.column-fixed {
|
||||
width: 9.5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -32,28 +32,21 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<h3 class="subtitle">{{ 'Actual budget'|trans }}</h3>
|
||||
|
||||
{% if actualCharges|length > 0 or actualResources|length > 0 %}
|
||||
{% include 'ChillBudgetBundle:Budget:_current_budget.html.twig' with {
|
||||
{% include '@ChillBudget/Budget/_current_budget.html.twig' with {
|
||||
'actualResources': actualResources,
|
||||
'actualCharges': actualCharges,
|
||||
'results': results,
|
||||
'entity': entity
|
||||
} %}
|
||||
{% else %}
|
||||
<div class="flex-table">
|
||||
<div class="item-bloc">
|
||||
<p><span class="chill-no-data-statement">{{ "There isn't any element recorded"|trans }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if pastCharges|length > 0 or pastResources|length > 0 %}
|
||||
<h2 class="subtitle">{{ 'Past budget'|trans }}</h2>
|
||||
|
||||
{% include 'ChillBudgetBundle:Budget:_past_budget.html.twig' with {
|
||||
<h3 class="subtitle">{{ 'Past budget'|trans }}</h3>
|
||||
{% include '@ChillBudget/Budget/_past_budget.html.twig' with {
|
||||
'pastCharges': pastCharges,
|
||||
'pastResources': pastResources,
|
||||
'entity': entity
|
||||
@@ -61,9 +54,8 @@
|
||||
{% endif %}
|
||||
|
||||
{% if futureCharges|length > 0 or futureResources|length > 0 %}
|
||||
<h2 class="subtitle">{{ 'Future budget'|trans }}</h2>
|
||||
|
||||
{% include 'ChillBudgetBundle:Budget:_future_budget.html.twig' with {
|
||||
<h3 class="subtitle">{{ 'Future budget'|trans }}</h3>
|
||||
{% include '@ChillBudget/Budget/_future_budget.html.twig' with {
|
||||
'futureResources': futureResources,
|
||||
'futureCharges': futureCharges,
|
||||
'entity': entity
|
||||
|
@@ -1,30 +1,17 @@
|
||||
{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %}
|
||||
|
||||
{# <h2 class="subtitle">{{ 'Actual budget'|trans }}</h2> #}
|
||||
|
||||
<div class="flex-table">
|
||||
<h4 class="family-title">{{ 'Actual resources'|trans }}</h4>
|
||||
{% from '@ChillBudget/Budget/_macros.html.twig' import table_elements, table_results %}
|
||||
|
||||
<div class="my-4">
|
||||
<h4 class="family-title resource"><i class="fa fa-fw fa-plus-square"></i>{{ 'Actual resources'|trans }}</h4>
|
||||
{% if actualResources|length > 0 %}
|
||||
<div class="item-bloc">
|
||||
{{ table_elements(actualResources, 'resource') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="item-bloc">
|
||||
<span class="chill-no-data-statement">{{ 'No resources registered'|trans }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex-table">
|
||||
<h4 class="family-title">{{ 'Actual charges'|trans }}</h4>
|
||||
<h4 class="family-title charge"><i class="fa fa-fw fa-minus-square"></i>{{ 'Actual charges'|trans }}</h4>
|
||||
{% if actualCharges|length > 0 %}
|
||||
<div class="item-bloc">
|
||||
{{ table_elements(actualCharges, 'charge') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="item-bloc">
|
||||
<span class="chill-no-data-statement">{{ 'No charges registered'|trans }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@@ -20,30 +20,21 @@
|
||||
aria-labelledby="heading_future_{{ entity.id }}"
|
||||
data-bs-parent="#future_{{ entity.id }}">
|
||||
|
||||
<div class="flex-table">
|
||||
<h3 class="family-title">{{ 'Future resources'|trans }}</h3>
|
||||
<div class="my-4">
|
||||
<h4 class="family-title resource"><i class="fa fa-fw fa-plus-square"></i>{{ 'Future resources'|trans }}</h4>
|
||||
|
||||
{% if futureResources|length > 0 %}
|
||||
<div class="item-bloc">
|
||||
{{ table_elements(futureResources, 'resource') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="item-bloc">
|
||||
<span class="chill-no-data-statement">{{ 'No future resources registered'|trans }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex-table">
|
||||
<h3 class="family-title">{{ 'Future charges'|trans }}</h3>
|
||||
|
||||
<h4 class="family-title charge"><i class="fa fa-fw fa-minus-square"></i>{{ 'Future charges'|trans }}</h4>
|
||||
|
||||
{% if futureCharges|length > 0 %}
|
||||
<div class="item-bloc">
|
||||
{{ table_elements(futureCharges, 'charge') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="item-bloc">
|
||||
<span class="chill-no-data-statement">{{ 'No future charges registered'|trans }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{% macro table_elements(elements, family) %}
|
||||
<table class="budget-table">
|
||||
<table class="table table-bordered border-dark budget-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="{{ family }} el-type">{{ 'Budget element type'|trans }}</th>
|
||||
@@ -13,25 +13,28 @@
|
||||
{% for f in elements %}
|
||||
{% set total = total + f.amount %}
|
||||
<tr>
|
||||
<td class="column-wide el-type">
|
||||
<span class="badge-title">
|
||||
<span class="title_label title_label_{{ family }}"></span>
|
||||
<td class="el-type">
|
||||
{% if f.isResource %}
|
||||
<span class="title_action">{{ f.resource.name|localize_translatable_string }}<span>
|
||||
{% else %}
|
||||
<span class="title_action">{{ f.charge.name|localize_translatable_string }}<span>
|
||||
{{ f.resource.name|localize_translatable_string }}
|
||||
{% if f.resource.getKind is same as 'other' %}
|
||||
: {{ f.getComment }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ f.charge.name|localize_translatable_string }}
|
||||
{% if f.charge.getKind is same as 'other' %}
|
||||
: {{ f.getComment }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td class="column-small">{{ f.amount|format_currency('EUR') }}</td>
|
||||
<td class="column-wide">
|
||||
<td>{{ f.amount|format_currency('EUR') }}</td>
|
||||
<td>
|
||||
{% if f.endDate is not null %}
|
||||
{{ f.startDate|format_date('short') ~ ' - ' ~ f.endDate|format_date('short') }}
|
||||
{% else %}
|
||||
{{ f.startDate|format_date('short') ~ ' - ...' }}
|
||||
{{ 'depuis le ' ~ f.startDate|format_date('short') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="column-small">
|
||||
<td class="column-fixed">
|
||||
<ul class="record_actions">
|
||||
{% if is_granted('CHILL_BUDGET_ELEMENT_SEE', f) %}
|
||||
<li>
|
||||
@@ -80,10 +83,9 @@
|
||||
|
||||
{% set result = (totalResources - totalCharges) %}
|
||||
|
||||
<table>
|
||||
<table class="table table-bordered border-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th> </th>
|
||||
<th>{{ 'Budget calculator result'|trans }}</th>
|
||||
</tr>
|
||||
@@ -91,7 +93,6 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ 'The balance'|trans }}</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
{{ result|format_currency('EUR') }}
|
||||
</td>
|
||||
|
@@ -20,31 +20,21 @@
|
||||
aria-labelledby="heading_past_{{ entity.id }}"
|
||||
data-bs-parent="#past_{{ entity.id }}">
|
||||
|
||||
<div class="flex-table">
|
||||
<h3 class="family-title">{{ 'Past resources'|trans }}</h3>
|
||||
<div class="my-4">
|
||||
<h4 class="family-title resource"><i class="fa fa-fw fa-plus-square"></i>{{ 'Past resources'|trans }}</h4>
|
||||
|
||||
{% if pastResources|length > 0 %}
|
||||
<div class="item-bloc">
|
||||
{{ table_elements(pastResources, 'resource') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="item-bloc">
|
||||
<span class="chill-no-data-statement">{{ 'No past resources registered'|trans }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex-table">
|
||||
<h3 class="family-title">{{ 'Past charges'|trans }}</h3>
|
||||
<h4 class="family-title charge"><i class="fa fa-fw fa-minus-square"></i>{{ 'Past charges'|trans }}</h4>
|
||||
|
||||
{% if pastCharges|length > 0 %}
|
||||
<div class="item-bloc">
|
||||
{{ table_elements(pastCharges, 'charge') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="item-bloc">
|
||||
<span class="chill-no-data-statement">{{ 'No past charges registered'|trans }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -24,16 +24,14 @@
|
||||
} %}
|
||||
|
||||
{#
|
||||
<div class="flex-table">
|
||||
<h3 class="family-title">{{ 'Budget calculator'|trans }}</h3>
|
||||
<div class="item-bloc">
|
||||
<div class="my-4">
|
||||
<h4 class="family-title">{{ 'Budget calculator'|trans }}</h4>
|
||||
{{ table_results(wholeCharges, wholeResources) }}
|
||||
</div>
|
||||
</div>
|
||||
#}
|
||||
|
||||
{% if household.getCurrentMembers|length > 0 %}
|
||||
<h2 class="subtitle">{{ 'Current budget household members'|trans }}</h2>
|
||||
<h1 class="my-5">{{ 'Budget household members'|trans }}</h1>
|
||||
|
||||
{% for hm in household.getCurrentMembers %}
|
||||
{% set member = hm.person %}
|
||||
@@ -57,6 +55,8 @@
|
||||
aria-labelledby="heading_{{ member.id }}"
|
||||
data-bs-parent="#nonCurrent">
|
||||
|
||||
<h2 class="mt-4">{{ 'Budget for %name%'|trans({'%name%': member.firstName ~ " " ~ member.lastName }) }}</h2>
|
||||
|
||||
{% include 'ChillBudgetBundle:Budget:_budget.html.twig' with {
|
||||
'resources': member.getBudgetResources,
|
||||
'charges': member.getBudgetCharges,
|
||||
|
@@ -17,18 +17,16 @@
|
||||
{% block content %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{% include 'ChillBudgetBundle:Budget:_budget.html.twig' with {
|
||||
{% include '@ChillBudget/Budget/_budget.html.twig' with {
|
||||
'resources': resources,
|
||||
'charges': charges,
|
||||
'person': person
|
||||
} %}
|
||||
|
||||
<div class="flex-table">
|
||||
<h3 class="family-title">{{ 'Budget calculator'|trans }}</h2>
|
||||
<div class="item-bloc">
|
||||
<div class="mt-5">
|
||||
<h3 class="subtitle">{{ 'Budget calculator'|trans }}</h3>
|
||||
{{ table_results(charges, resources) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if is_granted('CHILL_BUDGET_ELEMENT_CREATE', person) %}
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
|
@@ -9,7 +9,7 @@
|
||||
{% set indexPage = 'chill_budget_elements_household_index' %}
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set household = element.household %}
|
||||
{% set confirm_question = 'Are you sure you want to remove the ressource "%type%" associated to household "%household%" ?'|trans({ '%household%' : household.id, '%type%': element.resource.getName | localize_translatable_string} ) %}
|
||||
{% set confirm_question = 'Are you sure you want to remove the resource "%type%" associated to household "%household%" ?'|trans({ '%household%' : household.id, '%type%': element.resource.getName | localize_translatable_string} ) %}
|
||||
{% endif %}
|
||||
|
||||
{% extends template %}
|
||||
|
@@ -66,9 +66,7 @@ final class SummaryBudget implements SummaryBudgetInterface
|
||||
];
|
||||
}
|
||||
|
||||
$personIds = $household->getCurrentPersons()->map(static function (Person $p) {
|
||||
return $p->getId();
|
||||
});
|
||||
$personIds = $household->getCurrentPersons()->map(static fn (Person $p) => $p->getId());
|
||||
$ids = implode(', ', array_fill(0, count($personIds), '?'));
|
||||
|
||||
$parameters = [...$personIds, $household->getId()];
|
||||
@@ -127,18 +125,14 @@ final class SummaryBudget implements SummaryBudgetInterface
|
||||
{
|
||||
$keys = array_map(static fn (ChargeKind $kind) => $kind->getKind(), $this->chargeKindRepository->findAll());
|
||||
|
||||
return array_combine($keys, array_map(function ($kind) {
|
||||
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''];
|
||||
}, $keys));
|
||||
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
|
||||
}
|
||||
|
||||
private function getEmptyResourceArray(): array
|
||||
{
|
||||
$keys = array_map(static fn (ResourceKind $kind) => $kind->getKind(), $this->resourceKindRepository->findAll());
|
||||
|
||||
return array_combine($keys, array_map(function ($kind) {
|
||||
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''];
|
||||
}, $keys));
|
||||
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
|
||||
}
|
||||
|
||||
private function rowToArray(array $rows, string $kind): array
|
||||
|
@@ -50,9 +50,7 @@ final class SummaryBudgetTest extends TestCase
|
||||
],
|
||||
]);
|
||||
$queryCharges->setParameters(Argument::type('array'))
|
||||
->will(static function ($args, $query) {
|
||||
return $query;
|
||||
});
|
||||
->will(static fn ($args, $query) => $query);
|
||||
|
||||
$queryResources = $this->prophesize(AbstractQuery::class);
|
||||
$queryResources->getResult()->willReturn([
|
||||
@@ -63,9 +61,7 @@ final class SummaryBudgetTest extends TestCase
|
||||
],
|
||||
]);
|
||||
$queryResources->setParameters(Argument::type('array'))
|
||||
->will(static function ($args, $query) {
|
||||
return $query;
|
||||
});
|
||||
->will(static fn ($args, $query) => $query);
|
||||
|
||||
$em = $this->prophesize(EntityManagerInterface::class);
|
||||
$em->createNativeQuery(Argument::type('string'), Argument::type(Query\ResultSetMapping::class))
|
||||
@@ -100,9 +96,7 @@ final class SummaryBudgetTest extends TestCase
|
||||
$resourceRepository->findOneByKind('misc')->willReturn($misc);
|
||||
|
||||
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
||||
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($arg) {
|
||||
return $arg[0]['fr'];
|
||||
});
|
||||
$translatableStringHelper->localize(Argument::type('array'))->will(static fn ($arg) => $arg[0]['fr']);
|
||||
|
||||
$person = new Person();
|
||||
$personReflection = new ReflectionClass($person);
|
||||
|
@@ -0,0 +1,56 @@
|
||||
<?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\Budget;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230328155010 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'budget elements: restore the previous type to resource/charge kind if applicable';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
WITH type_to_id AS (
|
||||
SELECT DISTINCT charge.charge_id AS id, charge.type
|
||||
FROM chill_budget.charge
|
||||
WHERE type <> ''
|
||||
)
|
||||
UPDATE chill_budget.charge_type
|
||||
SET kind = type_to_id.type
|
||||
FROM type_to_id
|
||||
WHERE type_to_id.type <> '' AND type_to_id.id = charge_type.id
|
||||
SQL);
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
WITH type_to_id AS (
|
||||
SELECT DISTINCT resource.resource_id AS id, resource.type
|
||||
FROM chill_budget. resource
|
||||
WHERE type <> ''
|
||||
)
|
||||
UPDATE chill_budget.resource_type
|
||||
SET kind = type_to_id.type
|
||||
FROM type_to_id
|
||||
WHERE type_to_id.type <> '' AND type_to_id.id = resource_type.id
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("UPDATE chill_budget.resource_type SET kind=md5(random()::text) WHERE kind = ''");
|
||||
$this->addSql("UPDATE chill_budget.charge_type SET kind=md5(random()::text) WHERE kind = ''");
|
||||
}
|
||||
}
|
@@ -3,23 +3,23 @@ Resource: Ressource
|
||||
Charge: Charge
|
||||
Budget for %name%: Budget de %name%
|
||||
Budget for household %household%: Budget du ménage
|
||||
Current budget household members: Budget actuel des membres du ménage
|
||||
Budget household members: Budget des membres du ménage
|
||||
Show budget of %name%: Montrer budget de %name%
|
||||
See complete budget: Voir budget complet
|
||||
Hide budget: Masquer
|
||||
Hide budget of %name%: Masquer budget de %name%
|
||||
Resource element type: Nature de la ressource
|
||||
Actual budget: Éléments actuels du budget
|
||||
Actual budget: Éléments actuels
|
||||
Actual resources: Ressources actuelles
|
||||
Actual resources for %name%: Ressources actuelles de %name%
|
||||
Actual charges for %name%: Charges actuelles de %name%
|
||||
Actual charges: Charges actuelles
|
||||
Past budget: Éléments du budget passé
|
||||
Past budget: Éléments passés
|
||||
Show past budget: Montrer budget passé
|
||||
Show future budget: Montrer budget future
|
||||
Past resources: Ressources passées
|
||||
Past charges: Charges passées
|
||||
Future budget: Futurs éléments du budget
|
||||
Future budget: Éléments futurs
|
||||
Future resources: Ressources futures
|
||||
Future charges: Charges futures
|
||||
Budget element type: Nature
|
||||
@@ -29,7 +29,7 @@ End of validity period: Fin de la période de validité
|
||||
Total: Total
|
||||
Create new resource: Créer une nouvelle ressource
|
||||
Create new charge: Créer une nouvelle charge
|
||||
See person: Voir personne
|
||||
See person: Voir usagers
|
||||
|
||||
There isn't any element recorded: Aucun élément enregistré
|
||||
No resources registered: Aucune ressource enregistrée
|
||||
@@ -49,6 +49,8 @@ Remove resource: Supprimer la ressource
|
||||
Remove charge: Supprimer la charge
|
||||
Are you sure you want to remove the ressource "%type%" associated to "%name%" ?: Êtes-vous sûr·e de vouloir supprimer la ressource de nature "%type%" associée à %name% ?
|
||||
Are you sure you want to remove the charge "%type%" associated to "%name%" ?: Êtes-vous sûr·e de vouloir supprimer la charge de nature "%type%" associée à %name% ?
|
||||
Are you sure you want to remove the charge "%type%" associated to household "%household%" ?: Êtes-vous sur·e de vouloir supprimer la charge "%type%" associée au ménage ?
|
||||
Are you sure you want to remove the resource "%type%" associated to household "%household%" ?: Êtes-vous sur·e de vouloir supprimer la ressource "%type%" associée au ménage ?
|
||||
Resource deleted: Ressource supprimée
|
||||
Charge deleted: Charge supprimée
|
||||
Charge created: Charge créée
|
||||
|
@@ -60,7 +60,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->logger->info(__CLASS__ . ' execute command');
|
||||
$this->logger->info(self::class . ' execute command');
|
||||
|
||||
$limit = 50;
|
||||
$offset = 0;
|
||||
@@ -71,12 +71,12 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
$created = 0;
|
||||
$renewed = 0;
|
||||
|
||||
$this->logger->info(__CLASS__ . ' the number of user to get - renew', [
|
||||
$this->logger->info(self::class . ' the number of user to get - renew', [
|
||||
'total' => $total,
|
||||
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
|
||||
]);
|
||||
|
||||
while ($offset < ($total - 1)) {
|
||||
while ($offset < $total) {
|
||||
$users = $this->userRepository->findByMostOldSubscriptionOrWithoutSubscriptionOrData(
|
||||
$interval,
|
||||
$limit,
|
||||
@@ -92,7 +92,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
// we first try to renew an existing subscription, if any.
|
||||
// if not, or if it fails, we try to create a new one
|
||||
if ($this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||
$this->logger->debug(__CLASS__ . ' renew a subscription for', [
|
||||
$this->logger->debug(self::class . ' renew a subscription for', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -104,7 +104,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
if (0 !== $expirationTs) {
|
||||
++$renewed;
|
||||
} else {
|
||||
$this->logger->warning(__CLASS__ . ' could not renew subscription for a user', [
|
||||
$this->logger->warning(self::class . ' could not renew subscription for a user', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -112,7 +112,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
}
|
||||
|
||||
if (!$this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||
$this->logger->debug(__CLASS__ . ' create a subscription for', [
|
||||
$this->logger->debug(self::class . ' create a subscription for', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -124,7 +124,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
if (0 !== $expirationTs) {
|
||||
++$created;
|
||||
} else {
|
||||
$this->logger->warning(__CLASS__ . ' could not create subscription for a user', [
|
||||
$this->logger->warning(self::class . ' could not create subscription for a user', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -139,7 +139,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
||||
$this->em->clear();
|
||||
}
|
||||
|
||||
$this->logger->warning(__CLASS__ . ' process executed', [
|
||||
$this->logger->warning(self::class . ' process executed', [
|
||||
'created' => $created,
|
||||
'renewed' => $renewed,
|
||||
]);
|
||||
|
@@ -207,6 +207,7 @@ class CalendarController extends AbstractController
|
||||
'entityClassName' => Calendar::class,
|
||||
'entityId' => $entity->getId(),
|
||||
'template' => $template->getId(),
|
||||
'returnPath' => $request->getRequestUri(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -377,7 +378,9 @@ class CalendarController extends AbstractController
|
||||
$this->addFlash('success', $this->translator->trans('Success : calendar item created!'));
|
||||
|
||||
if ($form->get('save_and_upload_doc')->isClicked()) {
|
||||
return $this->redirectToRoute('chill_calendar_calendardoc_new', ['id' => $entity->getId()]);
|
||||
return $this->redirectToRoute('chill_calendar_calendardoc_new', [
|
||||
'id' => $entity->getId()
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($templates as $template) {
|
||||
@@ -386,6 +389,7 @@ class CalendarController extends AbstractController
|
||||
'entityClassName' => Calendar::class,
|
||||
'entityId' => $entity->getId(),
|
||||
'template' => $template->getId(),
|
||||
'returnPath' => $this->generateUrl('chill_calendar_calendar_edit', ['id' => $entity->getId()]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -526,14 +530,20 @@ class CalendarController extends AbstractController
|
||||
'comment' => $calendar->getComment()->getComment(),
|
||||
];
|
||||
|
||||
return $this->redirectToRoute(
|
||||
'chill_activity_activity_new',
|
||||
[
|
||||
'accompanying_period_id' => $calendar->getAccompanyingPeriod()->getId(),
|
||||
$routeParams = [
|
||||
'activityData' => $activityData,
|
||||
'returnPath' => $request->query->get('returnPath', null),
|
||||
]
|
||||
);
|
||||
];
|
||||
|
||||
if ($calendar->getContext() === 'accompanying_period') {
|
||||
$routeParams['accompanying_period_id'] = $calendar->getAccompanyingPeriod()->getId();
|
||||
} elseif ($calendar->getContext() === 'person') {
|
||||
$routeParams['person_id'] = $calendar->getPerson()->getId();
|
||||
} else {
|
||||
throw new RuntimeException('context not found for this calendar');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('chill_activity_activity_new', $routeParams);
|
||||
}
|
||||
|
||||
private function buildListFilterOrder(): FilterOrderHelper
|
||||
@@ -544,21 +554,6 @@ class CalendarController extends AbstractController
|
||||
return $filterOrder->build();
|
||||
}
|
||||
|
||||
private function buildParamsToUrl(?User $user, ?AccompanyingPeriod $accompanyingPeriod): array
|
||||
{
|
||||
$params = [];
|
||||
|
||||
if (null !== $user) {
|
||||
$params['user_id'] = $user->getId();
|
||||
}
|
||||
|
||||
if (null !== $accompanyingPeriod) {
|
||||
$params['id'] = $accompanyingPeriod->getId();
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form to delete a Calendar entity by id.
|
||||
*/
|
||||
|
@@ -24,7 +24,7 @@ class Configuration implements ConfigurationInterface
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_calendar');
|
||||
$rootNode = $treeBuilder->getRootNode('chill_calendar');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
|
@@ -29,6 +29,7 @@ use DateTimeImmutable;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\ReadableCollection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use LogicException;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
@@ -92,6 +93,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", inversedBy="calendars")
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
private ?AccompanyingPeriod $accompanyingPeriod = null;
|
||||
|
||||
@@ -507,14 +509,12 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|User[]
|
||||
* @return ReadableCollection<(int|string), User>
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
public function getUsers(): Collection
|
||||
public function getUsers(): ReadableCollection
|
||||
{
|
||||
return $this->getInvites()->map(static function (Invite $i) {
|
||||
return $i->getUser();
|
||||
});
|
||||
return $this->getInvites()->map(static fn (Invite $i) => $i->getUser());
|
||||
}
|
||||
|
||||
public function hasCalendarRange(): bool
|
||||
@@ -599,9 +599,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
}
|
||||
|
||||
$invite = $this->invites
|
||||
->filter(static function (Invite $invite) use ($user) {
|
||||
return $invite->getUser() === $user;
|
||||
})
|
||||
->filter(static fn (Invite $invite) => $invite->getUser() === $user)
|
||||
->first();
|
||||
$this->removeInvite($invite);
|
||||
|
||||
|
@@ -63,7 +63,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
* @Groups({"read", "write", "calendar:read"})
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
private ?Location $location;
|
||||
private ?Location $location = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||
|
@@ -52,7 +52,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
||||
return 'Exports of calendar';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
@@ -61,9 +61,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
return static fn ($value) => $labels[$value];
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
@@ -91,9 +89,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
||||
*/
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
|
@@ -61,9 +61,7 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
return static fn ($value) => $labels[$value];
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
|
@@ -61,9 +61,7 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
return static fn ($value) => $labels[$value];
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
|
@@ -58,9 +58,7 @@ class AgentFilter implements FilterInterface
|
||||
{
|
||||
$builder->add('accepted_agents', EntityType::class, [
|
||||
'class' => User::class,
|
||||
'choice_label' => function (User $u) {
|
||||
return $this->userRender->renderString($u, []);
|
||||
},
|
||||
'choice_label' => fn (User $u) => $this->userRender->renderString($u, []),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
|
@@ -69,11 +69,9 @@ class JobFilter implements FilterInterface
|
||||
{
|
||||
$builder->add('job', EntityType::class, [
|
||||
'class' => UserJob::class,
|
||||
'choice_label' => function (UserJob $j) {
|
||||
return $this->translatableStringHelper->localize(
|
||||
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
);
|
||||
},
|
||||
),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user