mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-15 11:14:59 +00:00
Compare commits
371 Commits
fix-calend
...
694-save-e
Author | SHA1 | Date | |
---|---|---|---|
214bfd198e | |||
f9b151e4db | |||
2c360e979b
|
|||
459df26fef
|
|||
e36d2a5eec
|
|||
0301641290
|
|||
5c413edb32
|
|||
06238c8355
|
|||
6b90a7d2a7
|
|||
de5f818c5a | |||
c4eb45edcc | |||
99482edf0d
|
|||
e87f0bf348
|
|||
bd324753f3
|
|||
7915aae86f
|
|||
4fec18f3aa
|
|||
583d7b24ba
|
|||
4a56c4c945
|
|||
239a978adb
|
|||
b2dec3e587
|
|||
6bba6f68b3
|
|||
164beb3ca9
|
|||
25dd65fbd8
|
|||
e99fb75ebd
|
|||
08ddbee6af
|
|||
a2b2cafbce
|
|||
a913d2820d
|
|||
01790fa0cf
|
|||
582983f5ef
|
|||
1f48900434
|
|||
91494c07d5
|
|||
c05d153029
|
|||
5fea61c450
|
|||
e7ac8aafe1
|
|||
34296e7841
|
|||
a34c102c4b
|
|||
c1c92dc296
|
|||
99455ca685
|
|||
e542ebe531
|
|||
77e4b1d4ff
|
|||
b23019cb3a
|
|||
1fad0f88a4
|
|||
bbd2599e7e
|
|||
5aa59aa0ff
|
|||
351df930a1
|
|||
c8127a1d9d
|
|||
f12f640cb4
|
|||
4da9b6587d
|
|||
0fec753118 | |||
4d3d9db1b3
|
|||
ce17f5f5c0
|
|||
6a14c2b9b3
|
|||
ad94c7bcb7
|
|||
3ca2811494
|
|||
1bc7221315
|
|||
7a1cc9b076
|
|||
f7fa9c31f3 | |||
fa237bf27b
|
|||
64e65d08fe
|
|||
1f58acd871
|
|||
b06a76784a
|
|||
1585a73974
|
|||
2deed644b6 | |||
5211d092e3 | |||
ac084a1309 | |||
2ca3cced2e | |||
f17c08f530 | |||
2a9ebe436e | |||
6ab5e708ec | |||
ba261ddeb9
|
|||
58ede06dfe
|
|||
2dec6a017d | |||
fb42cb1baf | |||
ae1df1f47a | |||
f2cbd7f4a3 | |||
7abecdea02 | |||
2be8aefb38 | |||
ff930e94f6 | |||
38ff46f03f | |||
d41dc7035c
|
|||
23d7d1c8f0
|
|||
acfa3d6849
|
|||
0bfb5c617e
|
|||
17461aa21e
|
|||
7d469df62a
|
|||
204ebd4415
|
|||
b789250b8d
|
|||
1ebdcd1530
|
|||
e93458f943
|
|||
ceee5e7eea
|
|||
9f00754eb7 | |||
0f7d4ce5ee | |||
1eb1e2ec24 | |||
52512e45fc | |||
49380f5f61 | |||
e0c9e12008
|
|||
4fcfe3f5d2
|
|||
333e524136
|
|||
3c85b5ca92
|
|||
ff7f5a5dd3 | |||
fb8f74119f | |||
34602d0a56 | |||
43a4576ed4 | |||
a32d20e320 | |||
7e6ef3dafe | |||
7e06d7beed | |||
8e65b3851a | |||
aca81122d5
|
|||
5a93e21758 | |||
368846e09b | |||
efe494d61f
|
|||
c050c42a27
|
|||
6309877a14
|
|||
8d19e8d7af
|
|||
34c97769a6
|
|||
a10aae2100
|
|||
516e4e5f47
|
|||
531b49a536
|
|||
5328bee262
|
|||
060d5d5ca3
|
|||
368136ea57
|
|||
d080dfda9a
|
|||
88fb48e2be
|
|||
feb760a97b
|
|||
e97a04ab54
|
|||
c16454214d
|
|||
be5f87348b
|
|||
e71bb5d77b
|
|||
6cac298724
|
|||
39f410dc8f
|
|||
fc15b85d11
|
|||
74673380aa
|
|||
72ae6fb2cd | |||
a73dca5efe
|
|||
8cbfe16c24
|
|||
9b32ce53c8
|
|||
788b1e9eeb
|
|||
57e1786b99
|
|||
6eb23c6073
|
|||
b6e3baa5dc
|
|||
02a7074218
|
|||
593caec851
|
|||
9913938c1b | |||
7c8ac8cfcb | |||
3ebf3ae148 | |||
24833be681 | |||
6777cf7225 | |||
3b9e6d2742 | |||
390da7c641 | |||
d3e784de15
|
|||
d35dacf562
|
|||
cd54fdd13f
|
|||
448d93cd02
|
|||
8894491dac | |||
999e9e8553
|
|||
3ca46efd2c | |||
e90782500b | |||
0f159281ba
|
|||
15c304b1d1
|
|||
53980dd757 | |||
c1261f63e7 | |||
80f6b7d330 | |||
56a7833858 | |||
318d6b6d4e
|
|||
d0e1f31ec7
|
|||
15871db7fd
|
|||
00bf7bf299
|
|||
dafd715efd
|
|||
928869666c | |||
9623a35e6f | |||
d58aad4624 | |||
a39f547907 | |||
0e661784b0
|
|||
fc607d6a0e | |||
2f765a3aa5 | |||
9ad3bbc1b4 | |||
f144663877 | |||
434ef075da
|
|||
2db778c4a4 | |||
2178485e5e | |||
e767557216 | |||
68bfb082fc | |||
1f3dd00d81 | |||
f633fabf79
|
|||
cf6430ae9b
|
|||
d3ba11f521
|
|||
f3401faea1
|
|||
ec9555ec84 | |||
a68422e0e8
|
|||
400770123a
|
|||
91e3588e76
|
|||
61f44396c5
|
|||
8e44f20535
|
|||
a7c44830d2
|
|||
a942a24596
|
|||
826a975fbe
|
|||
c1df8084a6
|
|||
c22135f101 | |||
a2e1228c09 | |||
11f0cac86e | |||
9dba5965f6 | |||
be38251a13 | |||
43791badd5 | |||
79e9906a05 | |||
aec4c52567 | |||
ccb2cd0295 | |||
8aeeab9e6b | |||
48da6d0a92 | |||
50db96ffbc | |||
86be95ac43 | |||
8159f91e25 | |||
0756bec580 | |||
4e3c93cdd3 | |||
c7f740d5d7 | |||
5489178e4b | |||
3b96ac3ef3 | |||
df4f5e7cf8 | |||
82d9ab8ca6 | |||
c05637bc72 | |||
d450f06286 | |||
3b68997c69 | |||
17e8e1964d | |||
bf5ecd25de | |||
9fa3a72cb4 | |||
f10a448ae9 | |||
9bfc184f70 | |||
2e60b6735a | |||
2ee362bfd5 | |||
b42e1a9a05 | |||
055acbf43c | |||
5655f953d7 | |||
e6553e71ee | |||
7f9e8c5a7b | |||
f3a3cab801 | |||
d6b358cfa1 | |||
abd79df8cd | |||
dc38e5927c | |||
18406e83a1 | |||
6687742e23 | |||
2767075be7 | |||
371a7dc05c | |||
63129a3b8c | |||
8ea29e8ec4 | |||
2bdc06397e | |||
edd9aaa475 | |||
5695564723 | |||
fc9689e881 | |||
75f69859e6 | |||
b5a9dac62e | |||
bf58c5d59c | |||
8a395bf108 | |||
1ed367e079 | |||
e3801d54b4 | |||
4c9cdb7b8c | |||
2096e175d4 | |||
781253a854 | |||
c396635163 | |||
eeb84d5cfb | |||
fc2f8d33e1 | |||
a69965345f | |||
226f172970 | |||
6d0622aa38 | |||
0e553594a0 | |||
f714c7206c | |||
42012dbad2 | |||
bc41910a39 | |||
a18870c91e | |||
68ebf8303c | |||
9e89302aa4 | |||
2e52729806 | |||
afb5ebc077 | |||
f751d2e9ab | |||
13d6e4587a | |||
6fd75a175f | |||
03e765f811 | |||
d3f03fb27c | |||
481be32997 | |||
4524240ad8 | |||
0255f12fa9 | |||
4ca10ce38d | |||
f0b2ec1348 | |||
2d40c38c88 | |||
d8104c4443 | |||
63d38e35f7 | |||
9c3533d106 | |||
e07d2ab467 | |||
cda25d3459 | |||
1bf7f9945c | |||
9cf06c147f | |||
60f93f7f12 | |||
c872ca7204 | |||
51ac4e0938 | |||
24873f0cc2 | |||
84e5be6a60 | |||
5acf2a1986 | |||
094a912e42 | |||
f40aa89d08 | |||
50e2f4a147 | |||
be215bd135 | |||
be75cdce55 | |||
e46b285d3e | |||
17a7b053cf | |||
32cdf56fbd | |||
749facb9b0 | |||
edd1557f35 | |||
3059935305 | |||
355436aa82 | |||
8d4ec5d675 | |||
c20b561de5 | |||
acc9523ff5 | |||
afa6dfd77c | |||
c331f94201 | |||
6ffe99a2be | |||
d75ec92417 | |||
4e55f1ede7 | |||
cf7d0c1bdb | |||
f4c3997e55 | |||
f434cc5c02 | |||
333c305eef | |||
4af261a366 | |||
1228a0323c | |||
dc149c7fd5 | |||
7dc34cb357 | |||
ed04c276c2 | |||
f8b5078997 | |||
68b9c171a6 | |||
791ea25e4f | |||
e3846829e1 | |||
d48474bbc9 | |||
05f9a83bed | |||
441c5c8da7 | |||
a0fc9d4de5 | |||
8527c19073 | |||
fe120086c7 | |||
f1fb77187f | |||
43d9ba1ba5 | |||
77a6e92f69 | |||
e1b6fb2db1 | |||
2a4a4a80b1 | |||
2e44689549 | |||
eb404404f9 | |||
a26029999f | |||
dbf3780593 | |||
b20a75c2ee | |||
71db287ded | |||
5f0a6f37b0 | |||
fa1b5c4a02 | |||
4388331b2f | |||
9d1c38e978 | |||
a95f0c538d | |||
ffd1145cd0 | |||
d1b9400257 | |||
fdd537b18e | |||
1786fa838f | |||
7fe8d0837f | |||
753d6ea481 | |||
8cf25415ab | |||
743e0b9403 | |||
97d6f35605 | |||
5af492b2db | |||
70c631b612 | |||
e550d64fd4 | |||
4aaf75a1a4 | |||
9db43f1de3 | |||
674629e2bf | |||
e42d6c2d77 | |||
3782cf35ff | |||
68c1833584 | |||
191b8ecf81 | |||
e7ba42de1f | |||
8b145ebc11 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,6 +3,7 @@ composer
|
|||||||
composer.phar
|
composer.phar
|
||||||
composer.lock
|
composer.lock
|
||||||
docs/build/
|
docs/build/
|
||||||
|
node_modules/*
|
||||||
.php_cs.cache
|
.php_cs.cache
|
||||||
|
|
||||||
###> symfony/framework-bundle ###
|
###> symfony/framework-bundle ###
|
||||||
@@ -24,3 +25,5 @@ docs/build/
|
|||||||
/.php-cs-fixer.cache
|
/.php-cs-fixer.cache
|
||||||
/.idea/
|
/.idea/
|
||||||
/.psalm/
|
/.psalm/
|
||||||
|
|
||||||
|
node_modules/*
|
||||||
|
@@ -9,18 +9,22 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.4",
|
"php": "^7.4",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-redis": "*",
|
||||||
"champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290",
|
"champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290",
|
||||||
"champs-libres/wopi-bundle": "dev-master#6dd8e0a14e00131eb4b889ecc30270ee4a0e5224",
|
"champs-libres/wopi-bundle": "dev-master@dev",
|
||||||
"champs-libres/wopi-lib": "dev-master#8615f4a45a39fc2b6a98765ea835fcfd39618787",
|
"champs-libres/wopi-lib": "dev-master@dev",
|
||||||
"doctrine/doctrine-bundle": "^2.1",
|
"doctrine/doctrine-bundle": "^2.1",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||||
"doctrine/orm": "^2.7",
|
"doctrine/orm": "^2.13.0",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
"graylog2/gelf-php": "^1.5",
|
"graylog2/gelf-php": "^1.5",
|
||||||
"knplabs/knp-menu-bundle": "^3.0",
|
"knplabs/knp-menu-bundle": "^3.0",
|
||||||
"knplabs/knp-time-bundle": "^1.12",
|
"knplabs/knp-time-bundle": "^1.12",
|
||||||
"knpuniversity/oauth2-client-bundle": "^2.10",
|
"knpuniversity/oauth2-client-bundle": "^2.10",
|
||||||
"league/csv": "^9.7.1",
|
"league/csv": "^9.7.1",
|
||||||
|
"lexik/jwt-authentication-bundle": "^2.16",
|
||||||
"nyholm/psr7": "^1.4",
|
"nyholm/psr7": "^1.4",
|
||||||
"ocramius/package-versions": "^1.10 || ^2",
|
"ocramius/package-versions": "^1.10 || ^2",
|
||||||
"odolbeau/phone-number-bundle": "^3.6",
|
"odolbeau/phone-number-bundle": "^3.6",
|
||||||
@@ -29,12 +33,12 @@
|
|||||||
"ramsey/uuid-doctrine": "^1.7",
|
"ramsey/uuid-doctrine": "^1.7",
|
||||||
"sensio/framework-extra-bundle": "^5.5",
|
"sensio/framework-extra-bundle": "^5.5",
|
||||||
"spomky-labs/base64url": "^2.0",
|
"spomky-labs/base64url": "^2.0",
|
||||||
"symfony/asset": "^4.4",
|
|
||||||
"symfony/browser-kit": "^4.4",
|
"symfony/browser-kit": "^4.4",
|
||||||
"symfony/css-selector": "^4.4",
|
"symfony/css-selector": "^4.4",
|
||||||
"symfony/expression-language": "^4.4",
|
"symfony/expression-language": "^4.4",
|
||||||
"symfony/form": "^4.4",
|
"symfony/form": "^4.4",
|
||||||
"symfony/framework-bundle": "^4.4",
|
"symfony/framework-bundle": "^4.4",
|
||||||
|
"symfony/http-client": "^4.4 || ^5",
|
||||||
"symfony/http-foundation": "^4.4",
|
"symfony/http-foundation": "^4.4",
|
||||||
"symfony/intl": "^4.4",
|
"symfony/intl": "^4.4",
|
||||||
"symfony/mailer": "^5.4",
|
"symfony/mailer": "^5.4",
|
||||||
@@ -48,7 +52,6 @@
|
|||||||
"symfony/translation": "^4.4",
|
"symfony/translation": "^4.4",
|
||||||
"symfony/twig-bundle": "^4.4",
|
"symfony/twig-bundle": "^4.4",
|
||||||
"symfony/validator": "^4.4",
|
"symfony/validator": "^4.4",
|
||||||
"symfony/web-link": "*",
|
|
||||||
"symfony/webpack-encore-bundle": "^1.11",
|
"symfony/webpack-encore-bundle": "^1.11",
|
||||||
"symfony/workflow": "^4.4",
|
"symfony/workflow": "^4.4",
|
||||||
"symfony/yaml": "^4.4",
|
"symfony/yaml": "^4.4",
|
||||||
@@ -72,8 +75,7 @@
|
|||||||
"symfony/maker-bundle": "^1.20",
|
"symfony/maker-bundle": "^1.20",
|
||||||
"symfony/phpunit-bridge": "^4.4",
|
"symfony/phpunit-bridge": "^4.4",
|
||||||
"symfony/stopwatch": "^4.4",
|
"symfony/stopwatch": "^4.4",
|
||||||
"symfony/var-dumper": "^4.4",
|
"symfony/var-dumper": "^4.4"
|
||||||
"symfony/web-profiler-bundle": "^4.4"
|
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"symfony/symfony": "*"
|
"symfony/symfony": "*"
|
||||||
|
93
docs/source/development/cronjob.rst
Normal file
93
docs/source/development/cronjob.rst
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
.. Copyright (C) 2014-2023 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".
|
||||||
|
|
||||||
|
.. _cronjob:
|
||||||
|
|
||||||
|
Cron jobs
|
||||||
|
*********
|
||||||
|
|
||||||
|
Some tasks must be executed regularly: refresh some materialized views, remove old data, ...
|
||||||
|
|
||||||
|
For this purpose, one can programmatically implements a "cron job", which will be scheduled by a specific command.
|
||||||
|
|
||||||
|
The command :code:`chill:cron-job:execute`
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
The command :code:`chill:cron-job:execute` will schedule a task, one by one. In a classical implementation, it should
|
||||||
|
be executed every 15 minutes (more or less), to ensure that every task can be executed.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This command should not be executed in parallel. The installer should ensure that two job are executed concurrently.
|
||||||
|
|
||||||
|
How to implements a cron job ?
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Implements a :code:`Chill\MainBundle\Cron\CronJobInterface`. Here is an example:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Service\Something;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Cron\CronJobInterface;
|
||||||
|
use Chill\MainBundle\Entity\CronJobExecution;
|
||||||
|
use DateInterval;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
|
||||||
|
class MyCronJob implements CronJobInterface
|
||||||
|
{
|
||||||
|
public function canRun(?CronJobExecution $cronJobExecution): bool
|
||||||
|
{
|
||||||
|
// the parameter $cronJobExecution contains data about the last execution of the cronjob
|
||||||
|
// if it is null, it should be executed immediatly
|
||||||
|
if (null === $cronJobExecution) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cronJobExecution->getKey() !== $this->getKey()) {
|
||||||
|
throw new UnexpectedValueException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this cron job should be executed if the last execution is greater than one day, but only during the night
|
||||||
|
|
||||||
|
$now = new DateTimeImmutable('now');
|
||||||
|
|
||||||
|
return $cronJobExecution->getLastStart() < $now->sub(new DateInterval('P1D'))
|
||||||
|
&& in_array($now->format('H'), self::ACCEPTED_HOURS, true)
|
||||||
|
// introduce a random component to ensure a roll of task execution when multiple instances are hosted on same machines
|
||||||
|
&& mt_rand(0, 5) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey(): string
|
||||||
|
{
|
||||||
|
return 'arbitrary-and-unique-key';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// here, we execute the command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
How are cron job scheduled ?
|
||||||
|
============================
|
||||||
|
|
||||||
|
If the command :code:`chill:cron-job:execute` is run with one or more :code:`job` argument, those jobs are run, **without checking that the job can run** (the method :code:`canRun` is not executed).
|
||||||
|
|
||||||
|
If any :code:`job` argument is given, the :code:`CronManager` schedule job with those steps:
|
||||||
|
|
||||||
|
* the tasks are ordered, with:
|
||||||
|
* a priority is given for tasks that weren't never executed;
|
||||||
|
* then, the tasks are ordered, the last executed are the first in the list
|
||||||
|
* then, for each tasks, and in the given order, the first task where :code:`canRun` return :code:`TRUE` will be executed.
|
||||||
|
|
||||||
|
The command :code:`chill:cron-job:execute` execute **only one** task.
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -34,6 +34,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
|
|||||||
Useful snippets <useful-snippets.rst>
|
Useful snippets <useful-snippets.rst>
|
||||||
manual/index.rst
|
manual/index.rst
|
||||||
Assets <assets.rst>
|
Assets <assets.rst>
|
||||||
|
Cron Jobs <cronjob.rst>
|
||||||
|
|
||||||
Layout and UI
|
Layout and UI
|
||||||
**************
|
**************
|
||||||
|
@@ -18,6 +18,7 @@ Installation & Usage
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
prod.rst
|
prod.rst
|
||||||
|
load-addresses.rst
|
||||||
prod-calendar-sms-sending.rst
|
prod-calendar-sms-sending.rst
|
||||||
msgraph-configure.rst
|
msgraph-configure.rst
|
||||||
|
|
||||||
@@ -170,7 +171,7 @@ There are several users available:
|
|||||||
|
|
||||||
The password is always ``password``.
|
The password is always ``password``.
|
||||||
|
|
||||||
Now, read `Operations` below.
|
Now, read `Operations` below. For running in production, read `prod_`.
|
||||||
|
|
||||||
|
|
||||||
Operations
|
Operations
|
||||||
|
50
docs/source/installation/load-addresses.rst
Normal file
50
docs/source/installation/load-addresses.rst
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
.. _addresses:
|
||||||
|
|
||||||
|
Addresses
|
||||||
|
*********
|
||||||
|
|
||||||
|
Chill can store a list of geolocated address references, which are used to suggest address and ensure that the data is correctly stored.
|
||||||
|
|
||||||
|
Those addresses may be load from a dedicated source.
|
||||||
|
|
||||||
|
In France
|
||||||
|
=========
|
||||||
|
|
||||||
|
The address are loaded from the `BANO <https://bano.openstreetmap.fr/>`_. The postal codes are loaded from `the official list of
|
||||||
|
postal codes <https://datanova.laposte.fr/explore/dataset/laposte_hexasmal/information/>`_
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# first, load postal codes
|
||||||
|
bin/console chill:main:postal-code:load:FR
|
||||||
|
# then, load all addresses, by departement (multiple departement can be loaded by repeating the departement code
|
||||||
|
bin/console chill:main:address-ref-from-bano 57 54 51
|
||||||
|
|
||||||
|
In Belgium
|
||||||
|
==========
|
||||||
|
|
||||||
|
Addresses are prepared from the `BeST Address data <https://www.geo.be/catalog/details/ca0fd5c0-8146-11e9-9012-482ae30f98d9>`_.
|
||||||
|
|
||||||
|
Postal code are loaded from this database. There is no need to load postal codes from another source (actually, this is strongly discouraged).
|
||||||
|
|
||||||
|
The data are prepared for Chill (`See this repository <https://gitea.champs-libres.be/Chill-project/belgian-bestaddresses-transform/releases>`_).
|
||||||
|
One can select postal code by his first number (:code:`1xxx` for postal codes from 1000 to 1999), or a limited list for development purpose.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# load postal code from 1000 to 3999:
|
||||||
|
bin/console chill:main:address-ref-from-best-addresse 1xxx 2xxx 3xxx
|
||||||
|
|
||||||
|
# load only an extract (for dev purposes)
|
||||||
|
bin/console chill:main:address-ref-from-best-addresse extract
|
||||||
|
|
||||||
|
# load full addresses (discouraged)
|
||||||
|
bin/console chill:main:address-ref-from-best-addresse full
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
There is a possibility to load the full list of addresses is discouraged: the loading is optimized with smaller extracts.
|
||||||
|
|
||||||
|
Once you load the full list, it is not possible to load smaller extract: each extract loaded **after** will not
|
||||||
|
delete the addresses loaded with the full extract (and some addresses will be present twice).
|
@@ -1,10 +1,12 @@
|
|||||||
.. Copyright (C) 2014-2019 Champs Libres Cooperative SCRLFS
|
.. Copyright (C) 2014-2019 Champs Libres Cooperative SCRLFS
|
||||||
Permission is granted to copy, distribute and/or modify this document
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
under the terms of the GNU Free Documentation License, Version 1.3
|
under the terms of the GNU Free Documentation License, Version 1.3
|
||||||
or any later version published by the Free Software Foundation;
|
or any later version published by the Free Software Foundation;
|
||||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
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
|
A copy of the license is included in the section entitled "GNU
|
||||||
Free Documentation License".
|
Free Documentation License".
|
||||||
|
|
||||||
|
.. _prod:
|
||||||
|
|
||||||
Installation for production
|
Installation for production
|
||||||
###########################
|
###########################
|
||||||
@@ -36,6 +38,19 @@ 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.
|
* 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.
|
||||||
|
|
||||||
|
Cron jobs
|
||||||
|
=========
|
||||||
|
|
||||||
|
The command :code:`chill:cron-job:execute` should be executed every 15 minutes (more or less).
|
||||||
|
|
||||||
|
This command should never be executed concurrently. It should be not have more than one process for a single instance.
|
||||||
|
|
||||||
|
Post-install tasks
|
||||||
|
==================
|
||||||
|
|
||||||
|
- import addresses. See :ref:`addresses`.
|
||||||
|
|
||||||
|
|
||||||
Tweak symfony messenger
|
Tweak symfony messenger
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ Add condition with distinct alias on each export join clauses (Indicators + Filt
|
|||||||
These are alias conventions :
|
These are alias conventions :
|
||||||
|
|
||||||
| Entity | Join | Attribute | Alias |
|
| Entity | Join | Attribute | Alias |
|
||||||
|:----------------------------------------|:----------------------------------------|:-------------------------------------------|:----------------------------------|
|
|:----------------------------------------|:----------------------------------------|:-------------------------------------------|:---------------------------------------|
|
||||||
| AccompanyingPeriod::class | | | acp |
|
| AccompanyingPeriod::class | | | acp |
|
||||||
| | AccompanyingPeriodWork::class | acp.works | acpw |
|
| | AccompanyingPeriodWork::class | acp.works | acpw |
|
||||||
| | AccompanyingPeriodParticipation::class | acp.participations | acppart |
|
| | AccompanyingPeriodParticipation::class | acp.participations | acppart |
|
||||||
@@ -36,6 +36,7 @@ These are alias conventions :
|
|||||||
| | MaritalStatus::class | person.maritalStatus | personmarital |
|
| | MaritalStatus::class | person.maritalStatus | personmarital |
|
||||||
| | VendeePerson::class | | vp |
|
| | VendeePerson::class | | vp |
|
||||||
| | VendeePersonMineur::class | | vpm |
|
| | VendeePersonMineur::class | | vpm |
|
||||||
|
| | CurrentPersonAddress::class | person.currentPersonAddress | currentPersonAddress (on a given date) |
|
||||||
| ResidentialAddress::class | | | resaddr |
|
| ResidentialAddress::class | | | resaddr |
|
||||||
| | ThirdParty::class | resaddr.hostThirdParty | tparty |
|
| | ThirdParty::class | resaddr.hostThirdParty | tparty |
|
||||||
| ThirdParty::class | | | tparty |
|
| ThirdParty::class | | | tparty |
|
||||||
|
67
package.json
Normal file
67
package.json
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"name": "chill",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@alexlafroscia/yaml-merge": "^4.0.0",
|
||||||
|
"@apidevtools/swagger-cli": "^4.0.4",
|
||||||
|
"@babel/core": "^7.20.5",
|
||||||
|
"@babel/preset-env": "^7.20.2",
|
||||||
|
"@ckeditor/ckeditor5-build-classic": "^35.3.2",
|
||||||
|
"@ckeditor/ckeditor5-dev-utils": "^31.1.13",
|
||||||
|
"@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13",
|
||||||
|
"@ckeditor/ckeditor5-markdown-gfm": "^35.3.2",
|
||||||
|
"@ckeditor/ckeditor5-theme-lark": "^35.3.2",
|
||||||
|
"@ckeditor/ckeditor5-vue": "^4.0.1",
|
||||||
|
"@symfony/webpack-encore": "^4.1.0",
|
||||||
|
"@tsconfig/node14": "^1.0.1",
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"bootstrap": "^5.0.1",
|
||||||
|
"chokidar": "^3.5.1",
|
||||||
|
"fork-awesome": "^1.1.7",
|
||||||
|
"jquery": "^3.6.0",
|
||||||
|
"node-sass": "^8.0.0",
|
||||||
|
"popper.js": "^1.16.1",
|
||||||
|
"postcss-loader": "^7.0.2",
|
||||||
|
"raw-loader": "^4.0.2",
|
||||||
|
"sass-loader": "^13.0.0",
|
||||||
|
"select2": "^4.0.13",
|
||||||
|
"select2-bootstrap-theme": "0.1.0-beta.10",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"ts-loader": "^9.3.1",
|
||||||
|
"typescript": "^4.7.2",
|
||||||
|
"vue-loader": "^17.0.0",
|
||||||
|
"webpack": "^5.75.0",
|
||||||
|
"webpack-cli": "^5.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fullcalendar/core": "^5.11.0",
|
||||||
|
"@fullcalendar/daygrid": "^5.11.0",
|
||||||
|
"@fullcalendar/interaction": "^5.11.0",
|
||||||
|
"@fullcalendar/list": "^5.11.0",
|
||||||
|
"@fullcalendar/timegrid": "^5.11.0",
|
||||||
|
"@fullcalendar/vue3": "^5.11.1",
|
||||||
|
"@popperjs/core": "^2.9.2",
|
||||||
|
"dropzone": "^5.7.6",
|
||||||
|
"es6-promise": "^4.2.8",
|
||||||
|
"leaflet": "^1.7.1",
|
||||||
|
"masonry-layout": "^4.2.2",
|
||||||
|
"mime": "^3.0.0",
|
||||||
|
"swagger-ui": "^4.15.5",
|
||||||
|
"vis-network": "^9.1.0",
|
||||||
|
"vue": "^3.2.37",
|
||||||
|
"vue-i18n": "^9.1.6",
|
||||||
|
"vue-multiselect": "3.0.0-alpha.2",
|
||||||
|
"vue-toast-notification": "^2.0",
|
||||||
|
"vuex": "^4.0.0"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"Firefox ESR"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev-server": "encore dev-server",
|
||||||
|
"dev": "encore dev",
|
||||||
|
"watch": "encore dev --watch",
|
||||||
|
"build": "encore production --progress"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
@@ -5,11 +5,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
|
path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\Household\\\\PersonHouseholdAddress\\:\\:\\$relation\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\AccompanyingPeriod\\:\\:\\$work\\.$#"
|
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\AccompanyingPeriod\\:\\:\\$work\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -30,11 +25,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php
|
path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Undefined variable\\: \\$choiceSlug$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Undefined variable\\: \\$choiceSlug$#"
|
message: "#^Undefined variable\\: \\$choiceSlug$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
@@ -10,16 +10,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php
|
path: src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:getDescription\\(\\) should return string but return statement is missing\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:getTitle\\(\\) should return string but return statement is missing\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -330,21 +320,6 @@ parameters:
|
|||||||
count: 6
|
count: 6
|
||||||
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
|
||||||
count: 2
|
|
||||||
path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
@@ -43,6 +43,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Security\Core\Role\Role;
|
use Symfony\Component\Security\Core\Role\Role;
|
||||||
use Symfony\Component\Serializer\SerializerInterface;
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
use function array_key_exists;
|
use function array_key_exists;
|
||||||
|
|
||||||
final class ActivityController extends AbstractController
|
final class ActivityController extends AbstractController
|
||||||
@@ -73,6 +74,8 @@ final class ActivityController extends AbstractController
|
|||||||
|
|
||||||
private ThirdPartyRepository $thirdPartyRepository;
|
private ThirdPartyRepository $thirdPartyRepository;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
private UserRepositoryInterface $userRepository;
|
private UserRepositoryInterface $userRepository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -89,7 +92,8 @@ final class ActivityController extends AbstractController
|
|||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
SerializerInterface $serializer,
|
SerializerInterface $serializer,
|
||||||
UserRepositoryInterface $userRepository,
|
UserRepositoryInterface $userRepository,
|
||||||
CenterResolverManagerInterface $centerResolver
|
CenterResolverManagerInterface $centerResolver,
|
||||||
|
TranslatorInterface $translator
|
||||||
) {
|
) {
|
||||||
$this->activityACLAwareRepository = $activityACLAwareRepository;
|
$this->activityACLAwareRepository = $activityACLAwareRepository;
|
||||||
$this->activityTypeRepository = $activityTypeRepository;
|
$this->activityTypeRepository = $activityTypeRepository;
|
||||||
@@ -105,6 +109,7 @@ final class ActivityController extends AbstractController
|
|||||||
$this->serializer = $serializer;
|
$this->serializer = $serializer;
|
||||||
$this->userRepository = $userRepository;
|
$this->userRepository = $userRepository;
|
||||||
$this->centerResolver = $centerResolver;
|
$this->centerResolver = $centerResolver;
|
||||||
|
$this->translator = $translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,7 +165,7 @@ final class ActivityController extends AbstractController
|
|||||||
$this->entityManager->remove($activity);
|
$this->entityManager->remove($activity);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
$this->addFlash('success', $this->get('translator')
|
$this->addFlash('success', $this->translator
|
||||||
->trans('The activity has been successfully removed.'));
|
->trans('The activity has been successfully removed.'));
|
||||||
|
|
||||||
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
||||||
@@ -245,7 +250,7 @@ final class ActivityController extends AbstractController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addFlash('success', $this->get('translator')->trans('Success : activity updated!'));
|
$this->addFlash('success', $this->translator->trans('Success : activity updated!'));
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_activity_activity_show', $params);
|
return $this->redirectToRoute('chill_activity_activity_show', $params);
|
||||||
}
|
}
|
||||||
@@ -363,6 +368,7 @@ final class ActivityController extends AbstractController
|
|||||||
|
|
||||||
if ($person instanceof Person) {
|
if ($person instanceof Person) {
|
||||||
$entity->setPerson($person);
|
$entity->setPerson($person);
|
||||||
|
$entity->getPersons()->add($person);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
@@ -472,7 +478,7 @@ final class ActivityController extends AbstractController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!'));
|
$this->addFlash('success', $this->translator->trans('Success : activity created!'));
|
||||||
|
|
||||||
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
||||||
|
|
||||||
|
@@ -13,15 +13,24 @@ namespace Chill\ActivityBundle\Controller;
|
|||||||
|
|
||||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||||
use Chill\ActivityBundle\Form\ActivityReasonType;
|
use Chill\ActivityBundle\Form\ActivityReasonType;
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityReason controller.
|
* ActivityReason controller.
|
||||||
*/
|
*/
|
||||||
class ActivityReasonController extends AbstractController
|
class ActivityReasonController extends AbstractController
|
||||||
{
|
{
|
||||||
|
private ActivityReasonRepository $activityReasonRepository;
|
||||||
|
|
||||||
|
public function __construct(ActivityReasonRepository $activityReasonRepository)
|
||||||
|
{
|
||||||
|
$this->activityReasonRepository = $activityReasonRepository;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new ActivityReason entity.
|
* Creates a new ActivityReason entity.
|
||||||
*/
|
*/
|
||||||
@@ -56,8 +65,8 @@ class ActivityReasonController extends AbstractController
|
|||||||
|
|
||||||
$entity = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityReason::class)->find($id);
|
$entity = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityReason::class)->find($id);
|
||||||
|
|
||||||
if (!$entity) {
|
if (null === $entity) {
|
||||||
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
|
throw new NotFoundHttpException('Unable to find ActivityReason entity.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$editForm = $this->createEditForm($entity);
|
$editForm = $this->createEditForm($entity);
|
||||||
@@ -75,7 +84,7 @@ class ActivityReasonController extends AbstractController
|
|||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$entities = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityReason::class)->findAll();
|
$entities = $this->activityReasonRepository->findAll();
|
||||||
|
|
||||||
return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', [
|
return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', [
|
||||||
'entities' => $entities,
|
'entities' => $entities,
|
||||||
|
@@ -63,10 +63,8 @@ class ActivityReason
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get category.
|
* Get category.
|
||||||
*
|
|
||||||
* @return ActivityReasonCategory
|
|
||||||
*/
|
*/
|
||||||
public function getCategory()
|
public function getCategory(): ?ActivityReasonCategory
|
||||||
{
|
{
|
||||||
return $this->category;
|
return $this->category;
|
||||||
}
|
}
|
||||||
@@ -107,6 +105,11 @@ class ActivityReason
|
|||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isActiveAndParentActive(): bool
|
||||||
|
{
|
||||||
|
return $this->active && null !== $this->getCategory() && $this->getCategory()->getActive();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set active.
|
* Set active.
|
||||||
*
|
*
|
||||||
|
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\MainBundle\Export\AggregatorInterface;
|
||||||
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class ByActivityNumberAggregator implements AggregatorInterface
|
||||||
|
{
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data): void
|
||||||
|
{
|
||||||
|
$qb
|
||||||
|
->addSelect('(SELECT COUNT(activity.id) FROM ' . Activity::class . ' activity WHERE activity.accompanyingPeriod = acp) AS activity_by_number_aggregator')
|
||||||
|
->addGroupBy('activity_by_number_aggregator');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ACP_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
// No form needed
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
return static function ($value) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['activity_by_number_aggregator'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'Group acp by activity number';
|
||||||
|
}
|
||||||
|
}
|
@@ -60,7 +60,7 @@ class ByCreatorAggregator implements AggregatorInterface
|
|||||||
return 'Created by';
|
return 'Created by';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@ class BySocialActionAggregator implements AggregatorInterface
|
|||||||
return 'Social action';
|
return 'Social action';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@ class BySocialIssueAggregator implements AggregatorInterface
|
|||||||
return 'Social issues';
|
return 'Social issues';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@ class ByThirdpartyAggregator implements AggregatorInterface
|
|||||||
return 'Accepted thirdparty';
|
return 'Accepted thirdparty';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@ class CreatorScopeAggregator implements AggregatorInterface
|
|||||||
return 'Scope';
|
return 'Scope';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,11 +65,13 @@ class LocationTypeAggregator implements AggregatorInterface
|
|||||||
return 'Accepted locationtype';
|
return 'Accepted locationtype';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$lt = $this->locationTypeRepository->find($value);
|
if (null === $lt = $this->locationTypeRepository->find($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize(
|
return $this->translatableStringHelper->localize(
|
||||||
$lt->getTitle()
|
$lt->getTitle()
|
||||||
|
@@ -44,7 +44,7 @@ class ActivityTypeAggregator implements AggregatorInterface
|
|||||||
public function alterQuery(QueryBuilder $qb, $data)
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
{
|
{
|
||||||
if (!in_array('acttype', $qb->getAllAliases(), true)) {
|
if (!in_array('acttype', $qb->getAllAliases(), true)) {
|
||||||
$qb->join('activity.activityType', 'acttype');
|
$qb->leftJoin('activity.activityType', 'acttype');
|
||||||
}
|
}
|
||||||
|
|
||||||
$qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY));
|
$qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY));
|
||||||
@@ -71,7 +71,7 @@ class ActivityTypeAggregator implements AggregatorInterface
|
|||||||
return 'Activity type';
|
return 'Activity type';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -66,7 +66,7 @@ class ActivityUserAggregator implements AggregatorInterface
|
|||||||
return 'Activity user';
|
return 'Activity user';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ class ActivityUsersAggregator implements AggregatorInterface
|
|||||||
return 'Activity users';
|
return 'Activity users';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ class ActivityUsersJobAggregator implements \Chill\MainBundle\Export\AggregatorI
|
|||||||
return 'Users \'s job';
|
return 'Users \'s job';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ class ActivityUsersScopeAggregator implements \Chill\MainBundle\Export\Aggregato
|
|||||||
return 'Users \'s scope';
|
return 'Users \'s scope';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -134,6 +134,10 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
|
|||||||
return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason';
|
return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null === $value || '' === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
switch ($data['level']) {
|
switch ($data['level']) {
|
||||||
case 'reasons':
|
case 'reasons':
|
||||||
$r = $this->activityReasonRepository->find($value);
|
$r = $this->activityReasonRepository->find($value);
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Export\Aggregator;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Export\Declarations;
|
||||||
|
use Chill\MainBundle\Export\AggregatorInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use LogicException;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
class SentReceivedAggregator implements AggregatorInterface
|
||||||
|
{
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
public function __construct(TranslatorInterface $translator)
|
||||||
|
{
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data): void
|
||||||
|
{
|
||||||
|
$qb->addSelect('activity.sentReceived AS activity_sentreceived_aggregator')
|
||||||
|
->addGroupBy('activity_sentreceived_aggregator');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ACTIVITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
// No form needed
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data): callable
|
||||||
|
{
|
||||||
|
return function (?string $value): string {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'export.aggregator.activity.by_sent_received.Sent or received';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($value) {
|
||||||
|
case null:
|
||||||
|
case '':
|
||||||
|
return '';
|
||||||
|
|
||||||
|
case 'sent':
|
||||||
|
return $this->translator->trans('export.aggregator.activity.by_sent_received.is sent');
|
||||||
|
|
||||||
|
case 'received':
|
||||||
|
return $this->translator->trans('export.aggregator.activity.by_sent_received.is received');
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new LogicException(sprintf('The value %s is not valid', $value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['activity_sentreceived_aggregator'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.aggregator.activity.by_sent_received.Group activity by sentreceived';
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\ActivityBundle\Export\Export\ListActivityHelper;
|
||||||
|
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||||
|
use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper;
|
||||||
|
use Chill\MainBundle\Export\ListInterface;
|
||||||
|
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class ListActivity implements ListInterface, GroupedExportInterface
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
private ListActivityHelper $helper;
|
||||||
|
|
||||||
|
private TranslatableStringExportLabelHelper $translatableStringExportLabelHelper;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ListActivityHelper $helper,
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
TranslatableStringExportLabelHelper $translatableStringExportLabelHelper
|
||||||
|
) {
|
||||||
|
$this->helper = $helper;
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->translatableStringExportLabelHelper = $translatableStringExportLabelHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$this->helper->buildForm($builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowedFormattersTypes()
|
||||||
|
{
|
||||||
|
return $this->helper->getAllowedFormattersTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return ListActivityHelper::MSG_KEY . 'List activities linked to an accompanying course';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGroup(): string
|
||||||
|
{
|
||||||
|
return 'Exports of activities linked to an accompanying period';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'acpId':
|
||||||
|
return static function ($value) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return ListActivityHelper::MSG_KEY . 'accompanying course id';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value ?? '';
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'scopesNames':
|
||||||
|
return $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY . 'course circles');
|
||||||
|
|
||||||
|
default:
|
||||||
|
return $this->helper->getLabels($key, $values, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
array_merge(
|
||||||
|
$this->helper->getQueryKeys($data),
|
||||||
|
[
|
||||||
|
'acpId',
|
||||||
|
'scopesNames',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult($query, $data)
|
||||||
|
{
|
||||||
|
return $this->helper->getResult($query, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return ListActivityHelper::MSG_KEY . 'List activity linked to a course';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->helper->getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
|
{
|
||||||
|
$centers = array_map(static function ($el) {
|
||||||
|
return $el['center'];
|
||||||
|
}, $acl);
|
||||||
|
|
||||||
|
$qb = $this->entityManager->createQueryBuilder();
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->distinct()
|
||||||
|
->from(Activity::class, 'activity')
|
||||||
|
->join('activity.accompanyingPeriod', 'acp')
|
||||||
|
->leftJoin('acp.participations', 'acppart')
|
||||||
|
->leftJoin('acppart.person', 'person')
|
||||||
|
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL')
|
||||||
|
->andWhere(
|
||||||
|
$qb->expr()->exists(
|
||||||
|
'SELECT 1
|
||||||
|
FROM ' . PersonCenterHistory::class . ' acl_count_person_history
|
||||||
|
WHERE acl_count_person_history.person = person
|
||||||
|
AND acl_count_person_history.center IN (:authorized_centers)
|
||||||
|
'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// some grouping are necessary
|
||||||
|
->addGroupBy('acp.id')
|
||||||
|
->addOrderBy('activity.date')
|
||||||
|
->addOrderBy('activity.id')
|
||||||
|
->setParameter('authorized_centers', $centers);
|
||||||
|
|
||||||
|
$this->helper->addSelect($qb);
|
||||||
|
|
||||||
|
// add select for this step
|
||||||
|
$qb
|
||||||
|
->addSelect('acp.id AS acpId')
|
||||||
|
->addSelect('(SELECT AGGREGATE(acpScope.name) FROM ' . Scope::class . ' acpScope WHERE acpScope MEMBER OF acp.scopes) AS scopesNames')
|
||||||
|
->addGroupBy('scopesNames');
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiredRole(): string
|
||||||
|
{
|
||||||
|
return ActivityStatsVoter::LISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsModifiers()
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
$this->helper->supportsModifiers(),
|
||||||
|
[
|
||||||
|
\Chill\PersonBundle\Export\Declarations::ACP_TYPE,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -124,7 +124,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
return 'attendee';
|
return 'attendee';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value ? 1 : 0;
|
return $value ? 'X' : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'list_reasons':
|
case 'list_reasons':
|
||||||
@@ -210,10 +210,20 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
|
|
||||||
$qb
|
$qb
|
||||||
->from('ChillActivityBundle:Activity', 'activity')
|
->from('ChillActivityBundle:Activity', 'activity')
|
||||||
->join('activity.person', 'person')
|
->join('activity.person', 'actperson')
|
||||||
->join('actperson.center', 'actcenter')
|
->join('actperson.centerHistory', 'centerHistory');
|
||||||
->andWhere('actcenter IN (:authorized_centers)')
|
|
||||||
->setParameter('authorized_centers', $centers);
|
$qb->where(
|
||||||
|
$qb->expr()->andX(
|
||||||
|
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
|
||||||
|
$qb->expr()->orX(
|
||||||
|
$qb->expr()->isNull('centerHistory.endDate'),
|
||||||
|
$qb->expr()->gt('centerHistory.endDate', 'activity.date')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
|
||||||
|
->setParameter('centers', $centers);
|
||||||
|
|
||||||
foreach ($this->fields as $f) {
|
foreach ($this->fields as $f) {
|
||||||
if (in_array($f, $data['fields'], true)) {
|
if (in_array($f, $data['fields'], true)) {
|
||||||
@@ -224,17 +234,17 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'person_firstname':
|
case 'person_firstname':
|
||||||
$qb->addSelect('person.firstName AS person_firstname');
|
$qb->addSelect('actperson.firstName AS person_firstname');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'person_lastname':
|
case 'person_lastname':
|
||||||
$qb->addSelect('person.lastName AS person_lastname');
|
$qb->addSelect('actperson.lastName AS person_lastname');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'person_id':
|
case 'person_id':
|
||||||
$qb->addSelect('person.id AS person_id');
|
$qb->addSelect('actperson.id AS person_id');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -251,7 +261,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'type_name':
|
case 'type_name':
|
||||||
$qb->join('activity.type', 'type');
|
$qb->join('activity.activityType', 'type');
|
||||||
$qb->addSelect('type.name AS type_name');
|
$qb->addSelect('type.name AS type_name');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -263,6 +273,11 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'attendee':
|
||||||
|
$qb->addSelect('IDENTITY(activity.attendee) AS attendee');
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$qb->addSelect(sprintf('activity.%s as %s', $f, $f));
|
$qb->addSelect(sprintf('activity.%s as %s', $f, $f));
|
||||||
|
|
||||||
|
@@ -0,0 +1,269 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Export\Export;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Export\Declarations;
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityPresenceRepositoryInterface;
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
|
||||||
|
use Chill\MainBundle\Export\FormatterInterface;
|
||||||
|
use Chill\MainBundle\Export\Helper\DateTimeHelper;
|
||||||
|
use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper;
|
||||||
|
use Chill\MainBundle\Export\Helper\UserHelper;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
|
||||||
|
use Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper;
|
||||||
|
use Doctrine\ORM\AbstractQuery;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use LogicException;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use const SORT_NUMERIC;
|
||||||
|
|
||||||
|
class ListActivityHelper
|
||||||
|
{
|
||||||
|
public const MSG_KEY = 'export.list.activity.';
|
||||||
|
|
||||||
|
private ActivityPresenceRepositoryInterface $activityPresenceRepository;
|
||||||
|
|
||||||
|
private ActivityTypeRepositoryInterface $activityTypeRepository;
|
||||||
|
|
||||||
|
private DateTimeHelper $dateTimeHelper;
|
||||||
|
|
||||||
|
private LabelPersonHelper $labelPersonHelper;
|
||||||
|
|
||||||
|
private LabelThirdPartyHelper $labelThirdPartyHelper;
|
||||||
|
|
||||||
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
private TranslatableStringExportLabelHelper $translatableStringLabelHelper;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
private UserHelper $userHelper;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ActivityPresenceRepositoryInterface $activityPresenceRepository,
|
||||||
|
ActivityTypeRepositoryInterface $activityTypeRepository,
|
||||||
|
DateTimeHelper $dateTimeHelper,
|
||||||
|
LabelPersonHelper $labelPersonHelper,
|
||||||
|
LabelThirdPartyHelper $labelThirdPartyHelper,
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
TranslatableStringHelperInterface $translatableStringHelper,
|
||||||
|
TranslatableStringExportLabelHelper $translatableStringLabelHelper,
|
||||||
|
UserHelper $userHelper
|
||||||
|
) {
|
||||||
|
$this->activityPresenceRepository = $activityPresenceRepository;
|
||||||
|
$this->activityTypeRepository = $activityTypeRepository;
|
||||||
|
$this->dateTimeHelper = $dateTimeHelper;
|
||||||
|
$this->labelPersonHelper = $labelPersonHelper;
|
||||||
|
$this->labelThirdPartyHelper = $labelThirdPartyHelper;
|
||||||
|
$this->translator = $translator;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
$this->translatableStringLabelHelper = $translatableStringLabelHelper;
|
||||||
|
$this->userHelper = $userHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSelect(QueryBuilder $qb): void
|
||||||
|
{
|
||||||
|
$qb
|
||||||
|
->addSelect('activity.id AS id')
|
||||||
|
->addSelect('activity.date')
|
||||||
|
->addSelect('IDENTITY(activity.activityType) AS typeName')
|
||||||
|
->leftJoin('activity.reasons', 'reasons')
|
||||||
|
->addSelect('AGGREGATE(reasons.name) AS listReasons')
|
||||||
|
->leftJoin('activity.persons', 'actPerson')
|
||||||
|
->addSelect('AGGREGATE(actPerson.id) AS personsIds')
|
||||||
|
->addSelect('AGGREGATE(actPerson.id) AS personsNames')
|
||||||
|
->leftJoin('activity.users', 'users_u')
|
||||||
|
->addSelect('AGGREGATE(users_u.id) AS usersIds')
|
||||||
|
->addSelect('AGGREGATE(users_u.id) AS usersNames')
|
||||||
|
->leftJoin('activity.thirdParties', 'thirdparty')
|
||||||
|
->addSelect('AGGREGATE(thirdparty.id) AS thirdPartiesIds')
|
||||||
|
->addSelect('AGGREGATE(thirdparty.id) AS thirdPartiesNames')
|
||||||
|
->addSelect('IDENTITY(activity.attendee) AS attendeeName')
|
||||||
|
->addSelect('activity.durationTime')
|
||||||
|
->addSelect('activity.travelTime')
|
||||||
|
->addSelect('activity.emergency')
|
||||||
|
->leftJoin('activity.location', 'location')
|
||||||
|
->addSelect('location.name AS locationName')
|
||||||
|
->addSelect('activity.sentReceived')
|
||||||
|
->addSelect('IDENTITY(activity.createdBy) AS createdBy')
|
||||||
|
->addSelect('activity.createdAt')
|
||||||
|
->addSelect('IDENTITY(activity.updatedBy) AS updatedBy')
|
||||||
|
->addSelect('activity.updatedAt')
|
||||||
|
->addGroupBy('activity.id')
|
||||||
|
->addGroupBy('location.id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowedFormattersTypes()
|
||||||
|
{
|
||||||
|
return [FormatterInterface::TYPE_LIST];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'createdAt':
|
||||||
|
case 'updatedAt':
|
||||||
|
return $this->dateTimeHelper->getLabel($key);
|
||||||
|
|
||||||
|
case 'createdBy':
|
||||||
|
case 'updatedBy':
|
||||||
|
return $this->userHelper->getLabel($key, $values, $key);
|
||||||
|
|
||||||
|
case 'date':
|
||||||
|
return $this->dateTimeHelper->getLabel(self::MSG_KEY . $key);
|
||||||
|
|
||||||
|
case 'attendeeName':
|
||||||
|
return function ($value) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'Attendee';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value || null === $presence = $this->activityPresenceRepository->find($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->translatableStringHelper->localize($presence->getName());
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'listReasons':
|
||||||
|
return $this->translatableStringLabelHelper->getLabelMulti($key, $values, 'Activity Reasons');
|
||||||
|
|
||||||
|
case 'typeName':
|
||||||
|
return function ($value) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'Activity type';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value || null === $type = $this->activityTypeRepository->find($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->translatableStringHelper->localize($type->getName());
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'usersNames':
|
||||||
|
return $this->userHelper->getLabelMulti($key, $values, self::MSG_KEY . 'users name');
|
||||||
|
|
||||||
|
case 'usersIds':
|
||||||
|
case 'thirdPartiesIds':
|
||||||
|
case 'personsIds':
|
||||||
|
return static function ($value) use ($key) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
switch ($key) {
|
||||||
|
case 'usersIds':
|
||||||
|
return self::MSG_KEY . 'users ids';
|
||||||
|
|
||||||
|
case 'thirdPartiesIds':
|
||||||
|
return self::MSG_KEY . 'third parties ids';
|
||||||
|
|
||||||
|
case 'personsIds':
|
||||||
|
return self::MSG_KEY . 'persons ids';
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new LogicException('key not supported');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode($value);
|
||||||
|
|
||||||
|
return implode(
|
||||||
|
'|',
|
||||||
|
array_unique(
|
||||||
|
array_filter($decoded, static fn (?int $id) => null !== $id),
|
||||||
|
SORT_NUMERIC
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'personsNames':
|
||||||
|
return $this->labelPersonHelper->getLabelMulti($key, $values, self::MSG_KEY . 'persons name');
|
||||||
|
|
||||||
|
case 'thirdPartiesNames':
|
||||||
|
return $this->labelThirdPartyHelper->getLabelMulti($key, $values, self::MSG_KEY . 'thirds parties');
|
||||||
|
|
||||||
|
case 'sentReceived':
|
||||||
|
return function ($value) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return self::MSG_KEY . 'sent received';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->translator->trans($value);
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return function ($value) use ($key) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return self::MSG_KEY . $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->translator->trans($value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id',
|
||||||
|
'date',
|
||||||
|
'typeName',
|
||||||
|
'listReasons',
|
||||||
|
'attendeeName',
|
||||||
|
'durationTime',
|
||||||
|
'travelTime',
|
||||||
|
'emergency',
|
||||||
|
'locationName',
|
||||||
|
'sentReceived',
|
||||||
|
'personsIds',
|
||||||
|
'personsNames',
|
||||||
|
'usersIds',
|
||||||
|
'usersNames',
|
||||||
|
'thirdPartiesIds',
|
||||||
|
'thirdPartiesNames',
|
||||||
|
'createdBy',
|
||||||
|
'createdAt',
|
||||||
|
'updatedBy',
|
||||||
|
'updatedAt',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult($query, $data)
|
||||||
|
{
|
||||||
|
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): string
|
||||||
|
{
|
||||||
|
return Declarations::ACTIVITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsModifiers()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Declarations::ACTIVITY,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -17,11 +17,9 @@ use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
|
|||||||
use Chill\MainBundle\Export\FilterInterface;
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
use Doctrine\ORM\Query\Expr;
|
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use function in_array;
|
|
||||||
|
|
||||||
class ActivityTypeFilter implements FilterInterface
|
class ActivityTypeFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
@@ -44,14 +42,13 @@ class ActivityTypeFilter implements FilterInterface
|
|||||||
|
|
||||||
public function alterQuery(QueryBuilder $qb, $data)
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
{
|
{
|
||||||
if (!in_array('activity', $qb->getAllAliases(), true)) {
|
$qb->andWhere(
|
||||||
$qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp');
|
$qb->expr()->exists(
|
||||||
}
|
'SELECT 1 FROM ' . Activity::class . ' act_type_filter_activity
|
||||||
|
WHERE act_type_filter_activity.activityType IN (:act_type_filter_activity_types) AND act_type_filter_activity.accompanyingPeriod = acp'
|
||||||
$clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
|
)
|
||||||
|
);
|
||||||
$qb->andWhere($clause);
|
$qb->setParameter('act_type_filter_activity_types', $data['accepted_activitytypes']);
|
||||||
$qb->setParameter('selected_activity_types', $data['types']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyOn()
|
public function applyOn()
|
||||||
|
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class HasNoActivityFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
|
{
|
||||||
|
$qb
|
||||||
|
->andWhere('
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1 FROM ' . Activity::class . ' activity
|
||||||
|
WHERE activity.accompanyingPeriod = acp
|
||||||
|
)
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ACP_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
//no form needed
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAction($data, $format = 'string'): array
|
||||||
|
{
|
||||||
|
return ['Filtered acp which has no activities', []];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'Filter acp which has no activity';
|
||||||
|
}
|
||||||
|
}
|
@@ -13,9 +13,10 @@ namespace Chill\ActivityBundle\Export\Filter;
|
|||||||
|
|
||||||
use Chill\ActivityBundle\Export\Declarations;
|
use Chill\ActivityBundle\Export\Declarations;
|
||||||
use Chill\MainBundle\Export\FilterInterface;
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
|
||||||
use Chill\MainBundle\Form\Type\Export\FilterType;
|
use Chill\MainBundle\Form\Type\Export\FilterType;
|
||||||
use DateTime;
|
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
||||||
|
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||||
|
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||||
use Doctrine\ORM\Query\Expr;
|
use Doctrine\ORM\Query\Expr;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -28,9 +29,14 @@ class ActivityDateFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
protected TranslatorInterface $translator;
|
protected TranslatorInterface $translator;
|
||||||
|
|
||||||
public function __construct(TranslatorInterface $translator)
|
private RollingDateConverterInterface $rollingDateConverter;
|
||||||
{
|
|
||||||
|
public function __construct(
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
RollingDateConverterInterface $rollingDateConverter
|
||||||
|
) {
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
|
$this->rollingDateConverter = $rollingDateConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRole(): ?string
|
public function addRole(): ?string
|
||||||
@@ -54,8 +60,14 @@ class ActivityDateFilter implements FilterInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
$qb->add('where', $where);
|
$qb->add('where', $where);
|
||||||
$qb->setParameter('date_from', $data['date_from']);
|
$qb->setParameter(
|
||||||
$qb->setParameter('date_to', $data['date_to']);
|
'date_from',
|
||||||
|
$this->rollingDateConverter->convert($data['date_from'])
|
||||||
|
);
|
||||||
|
$qb->setParameter(
|
||||||
|
'date_to',
|
||||||
|
$this->rollingDateConverter->convert($data['date_to'])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyOn(): string
|
public function applyOn(): string
|
||||||
@@ -66,13 +78,13 @@ class ActivityDateFilter implements FilterInterface
|
|||||||
public function buildForm(FormBuilderInterface $builder)
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('date_from', ChillDateType::class, [
|
->add('date_from', PickRollingDateType::class, [
|
||||||
'label' => 'Activities after this date',
|
'label' => 'Activities after this date',
|
||||||
'data' => new DateTime(),
|
'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
|
||||||
])
|
])
|
||||||
->add('date_to', ChillDateType::class, [
|
->add('date_to', PickRollingDateType::class, [
|
||||||
'label' => 'Activities before this date',
|
'label' => 'Activities before this date',
|
||||||
'data' => new DateTime(),
|
'data' => new RollingDate(RollingDate::T_TODAY),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
|
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
|
||||||
@@ -121,8 +133,8 @@ class ActivityDateFilter implements FilterInterface
|
|||||||
return [
|
return [
|
||||||
'Filtered by date of activity: only between %date_from% and %date_to%',
|
'Filtered by date of activity: only between %date_from% and %date_to%',
|
||||||
[
|
[
|
||||||
'%date_from%' => $data['date_from']->format('d-m-Y'),
|
'%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'),
|
||||||
'%date_to%' => $data['date_to']->format('d-m-Y'),
|
'%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
|
|||||||
{
|
{
|
||||||
$where = $qb->getDQLPart('where');
|
$where = $qb->getDQLPart('where');
|
||||||
$join = $qb->getDQLPart('join');
|
$join = $qb->getDQLPart('join');
|
||||||
$clause = $qb->expr()->in('reasons', ':selected_activity_reasons');
|
$clause = $qb->expr()->in('actreasons', ':selected_activity_reasons');
|
||||||
|
|
||||||
if (!in_array('actreasons', $qb->getAllAliases(), true)) {
|
if (!in_array('actreasons', $qb->getAllAliases(), true)) {
|
||||||
$qb->join('activity.reasons', 'actreasons');
|
$qb->join('activity.reasons', 'actreasons');
|
||||||
@@ -77,6 +77,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
|
|||||||
'class' => ActivityReason::class,
|
'class' => ActivityReason::class,
|
||||||
'choice_label' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()),
|
'choice_label' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()),
|
||||||
'group_by' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
|
'group_by' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
|
||||||
|
'attr' => ['class' => 'select2 '],
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'expanded' => false,
|
'expanded' => false,
|
||||||
]);
|
]);
|
||||||
|
@@ -11,7 +11,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Form;
|
namespace Chill\ActivityBundle\Form;
|
||||||
|
|
||||||
use Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategory;
|
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||||
|
use Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategoryType;
|
||||||
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
@@ -25,13 +26,13 @@ class ActivityReasonType extends AbstractType
|
|||||||
$builder
|
$builder
|
||||||
->add('name', TranslatableStringFormType::class)
|
->add('name', TranslatableStringFormType::class)
|
||||||
->add('active', CheckboxType::class, ['required' => false])
|
->add('active', CheckboxType::class, ['required' => false])
|
||||||
->add('category', TranslatableActivityReasonCategory::class);
|
->add('category', TranslatableActivityReasonCategoryType::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason',
|
'data_class' => ActivityReason::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace Chill\ActivityBundle\Form;
|
|||||||
|
|
||||||
use Chill\ActivityBundle\Entity\Activity;
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
use Chill\ActivityBundle\Entity\ActivityPresence;
|
use Chill\ActivityBundle\Entity\ActivityPresence;
|
||||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
use Chill\ActivityBundle\Form\Type\PickActivityReasonType;
|
||||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
use Chill\DocStoreBundle\Form\StoredObjectType;
|
use Chill\DocStoreBundle\Form\StoredObjectType;
|
||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\Center;
|
||||||
@@ -229,19 +229,10 @@ class ActivityType extends AbstractType
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($activityType->isVisible('reasons')) {
|
if ($activityType->isVisible('reasons')) {
|
||||||
$builder->add('reasons', EntityType::class, [
|
$builder->add('reasons', PickActivityReasonType::class, [
|
||||||
'label' => $activityType->getLabel('reasons'),
|
'label' => $activityType->getLabel('reasons'),
|
||||||
'required' => $activityType->isRequired('reasons'),
|
'required' => $activityType->isRequired('reasons'),
|
||||||
'class' => ActivityReason::class,
|
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'choice_label' => function (ActivityReason $activityReason) {
|
|
||||||
return $this->translatableStringHelper->localize($activityReason->getName());
|
|
||||||
},
|
|
||||||
'attr' => ['class' => 'select2 '],
|
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
|
||||||
return $er->createQueryBuilder('a')
|
|
||||||
->where('a.active = true');
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,9 +12,9 @@ declare(strict_types=1);
|
|||||||
namespace Chill\ActivityBundle\Form\Type;
|
namespace Chill\ActivityBundle\Form\Type;
|
||||||
|
|
||||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
|
||||||
use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender;
|
use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
@@ -22,31 +22,29 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
/**
|
/**
|
||||||
* FormType to choose amongst activity reasons.
|
* FormType to choose amongst activity reasons.
|
||||||
*/
|
*/
|
||||||
class TranslatableActivityReason extends AbstractType
|
class PickActivityReasonType extends AbstractType
|
||||||
{
|
{
|
||||||
/**
|
private ActivityReasonRepository $activityReasonRepository;
|
||||||
* @var ActivityReasonRender
|
|
||||||
*/
|
|
||||||
protected $reasonRender;
|
|
||||||
|
|
||||||
/**
|
private ActivityReasonRender $reasonRender;
|
||||||
* @var TranslatableStringHelper
|
|
||||||
*/
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
protected $translatableStringHelper;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TranslatableStringHelper $translatableStringHelper,
|
ActivityReasonRepository $activityReasonRepository,
|
||||||
ActivityReasonRender $reasonRender
|
ActivityReasonRender $reasonRender,
|
||||||
|
TranslatableStringHelperInterface $translatableStringHelper
|
||||||
) {
|
) {
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
$this->activityReasonRepository = $activityReasonRepository;
|
||||||
$this->reasonRender = $reasonRender;
|
$this->reasonRender = $reasonRender;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
$resolver->setDefaults(
|
$resolver->setDefaults(
|
||||||
[
|
[
|
||||||
'class' => 'ChillActivityBundle:ActivityReason',
|
'class' => ActivityReason::class,
|
||||||
'choice_label' => function (ActivityReason $choice) {
|
'choice_label' => function (ActivityReason $choice) {
|
||||||
return $this->reasonRender->renderString($choice, []);
|
return $this->reasonRender->renderString($choice, []);
|
||||||
},
|
},
|
||||||
@@ -57,10 +55,7 @@ class TranslatableActivityReason extends AbstractType
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
'choices' => $this->activityReasonRepository->findAll(),
|
||||||
return $er->createQueryBuilder('r')
|
|
||||||
->where('r.active = true');
|
|
||||||
},
|
|
||||||
'attr' => ['class' => ' select2 '],
|
'attr' => ['class' => ' select2 '],
|
||||||
]
|
]
|
||||||
);
|
);
|
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Chill is a software for social workers
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view
|
|
||||||
* the LICENSE file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Chill\ActivityBundle\Form\Type;
|
|
||||||
|
|
||||||
use Doctrine\ORM\EntityRepository;
|
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of TranslatableActivityReasonCategory.
|
|
||||||
*/
|
|
||||||
class TranslatableActivityReasonCategory extends AbstractType
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var RequestStack
|
|
||||||
*/
|
|
||||||
private $requestStack;
|
|
||||||
|
|
||||||
public function __construct(RequestStack $requestStack)
|
|
||||||
{
|
|
||||||
$this->requestStack = $requestStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
|
||||||
{
|
|
||||||
$locale = $this->requestStack->getCurrentRequest()->getLocale();
|
|
||||||
$resolver->setDefaults(
|
|
||||||
[
|
|
||||||
'class' => 'ChillActivityBundle:ActivityReasonCategory',
|
|
||||||
'choice_label' => 'name[' . $locale . ']',
|
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
|
||||||
return $er->createQueryBuilder('c')
|
|
||||||
->where('c.active = true');
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockPrefix()
|
|
||||||
{
|
|
||||||
return 'translatable_activity_reason_category';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getParent()
|
|
||||||
{
|
|
||||||
return EntityType::class;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Form\Type;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of TranslatableActivityReasonCategory.
|
||||||
|
*/
|
||||||
|
class TranslatableActivityReasonCategoryType extends AbstractType
|
||||||
|
{
|
||||||
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
public function __construct(TranslatableStringHelperInterface $translatableStringHelper, TranslatorInterface $translator)
|
||||||
|
{
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults(
|
||||||
|
[
|
||||||
|
'class' => ActivityReasonCategory::class,
|
||||||
|
'choice_label' => function (ActivityReasonCategory $category) {
|
||||||
|
return $this->translatableStringHelper->localize($category->getName())
|
||||||
|
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : '');
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'translatable_activity_reason_category';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return EntityType::class;
|
||||||
|
}
|
||||||
|
}
|
@@ -36,7 +36,6 @@ final class AdminMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
->setAttribute('class', 'list-group-item-header')
|
->setAttribute('class', 'list-group-item-header')
|
||||||
->setExtras([
|
->setExtras([
|
||||||
'order' => 5000,
|
'order' => 5000,
|
||||||
'icons' => ['exchange'],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$menu->addChild('Activity Reasons', [
|
$menu->addChild('Activity Reasons', [
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
<?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\Repository;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\ActivityPresence;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
|
class ActivityPresenceRepository implements ActivityPresenceRepositoryInterface
|
||||||
|
{
|
||||||
|
private EntityRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
$this->repository = $entityManager->getRepository($this->getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id): ?ActivityPresence
|
||||||
|
{
|
||||||
|
return $this->repository->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
return $this->repository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||||
|
{
|
||||||
|
return $this->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria): ?ActivityPresence
|
||||||
|
{
|
||||||
|
return $this->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName(): string
|
||||||
|
{
|
||||||
|
return ActivityPresence::class;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\ActivityPresence;
|
||||||
|
|
||||||
|
interface ActivityPresenceRepositoryInterface
|
||||||
|
{
|
||||||
|
public function find($id): ?ActivityPresence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|ActivityPresence[]
|
||||||
|
*/
|
||||||
|
public function findAll(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|ActivityPresence[]
|
||||||
|
*/
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array;
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria): ?ActivityPresence;
|
||||||
|
|
||||||
|
public function getClassName(): string;
|
||||||
|
}
|
@@ -14,17 +14,38 @@ namespace Chill\ActivityBundle\Repository;
|
|||||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method ActivityReason|null find($id, $lockMode = null, $lockVersion = null)
|
* @method ActivityReason|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
* @method ActivityReason|null findOneBy(array $criteria, array $orderBy = null)
|
* @method ActivityReason|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
* @method ActivityReason[] findAll()
|
|
||||||
* @method ActivityReason[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
* @method ActivityReason[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
*/
|
*/
|
||||||
class ActivityReasonRepository extends ServiceEntityRepository
|
class ActivityReasonRepository extends ServiceEntityRepository
|
||||||
{
|
{
|
||||||
public function __construct(ManagerRegistry $registry)
|
private RequestStack $requestStack;
|
||||||
{
|
|
||||||
|
public function __construct(
|
||||||
|
ManagerRegistry $registry,
|
||||||
|
RequestStack $requestStack
|
||||||
|
) {
|
||||||
parent::__construct($registry, ActivityReason::class);
|
parent::__construct($registry, ActivityReason::class);
|
||||||
|
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ActivityReason[]
|
||||||
|
*/
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('ar');
|
||||||
|
$qb->select(['ar'])
|
||||||
|
->leftJoin('ar.category', 'category')
|
||||||
|
->addOrderBy('JSON_EXTRACT(category.name, :lang)')
|
||||||
|
->addOrderBy('JSON_EXTRACT(ar.name, :lang)')
|
||||||
|
->setParameter('lang', $this->requestStack->getCurrentRequest()->getLocale() ?? 'fr');
|
||||||
|
|
||||||
|
return $qb->getQuery()->getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -117,7 +117,8 @@ export default {
|
|||||||
target: { //name, id
|
target: { //name, id
|
||||||
},
|
},
|
||||||
edit: false,
|
edit: false,
|
||||||
addressId: null
|
addressId: null,
|
||||||
|
defaults: window.addaddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ const store = createStore({
|
|||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
suggestedEntities(state) {
|
suggestedEntities(state) {
|
||||||
if (typeof state.activity.accompanyingPeriod === "undefined") {
|
if (typeof state.activity.accompanyingPeriod === "undefined" || state.activity.accompanyingPeriod === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const allEntities = [
|
const allEntities = [
|
||||||
|
@@ -39,6 +39,9 @@ const makeConcernedThirdPartiesLocation = (locationType, store) => {
|
|||||||
return locations;
|
return locations;
|
||||||
};
|
};
|
||||||
const makeAccompanyingPeriodLocation = (locationType, store) => {
|
const makeAccompanyingPeriodLocation = (locationType, store) => {
|
||||||
|
if (store.state.activity.accompanyingPeriod === null) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
const accPeriodLocation = store.state.activity.accompanyingPeriod.location;
|
const accPeriodLocation = store.state.activity.accompanyingPeriod.location;
|
||||||
return {
|
return {
|
||||||
type: 'location',
|
type: 'location',
|
||||||
|
@@ -156,7 +156,7 @@
|
|||||||
<dd>
|
<dd>
|
||||||
<section class="chill-entity entity-comment-embeddable">
|
<section class="chill-entity entity-comment-embeddable">
|
||||||
<blockquote class="chill-user-quote private-quote">
|
<blockquote class="chill-user-quote private-quote">
|
||||||
{{ entity.privateComment.comments[userId] }}
|
{{ entity.privateComment.comments[userId]|chill_markdown_to_html }}
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</section>
|
</section>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -172,7 +172,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="chill-no-data-statement">{{ 'Any document found'|trans }}</span>
|
<span class="chill-no-data-statement">{{ 'No document found'|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -7,13 +7,25 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ 'Name'|trans }}</th>
|
<th>{{ 'Name'|trans }}</th>
|
||||||
|
<th>{{ 'Active'|trans }}</th>
|
||||||
<th>{{ 'Actions'|trans }}</th>
|
<th>{{ 'Actions'|trans }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for entity in entities %}
|
{% for entity in entities %}
|
||||||
<tr class="{% if entity.active %}active{% else %}inactive{% endif %}">
|
<tr class="{% if entity.active %}active{% else %}inactive{% endif %}">
|
||||||
<td><a href="{{ path('chill_activity_activityreason_show', { 'id': entity.id }) }}">{{ entity.name|localize_translatable_string }}</a></td>
|
<td>
|
||||||
|
{% if entity.category is not null -%}
|
||||||
|
{{ entity.category.name|localize_translatable_string }} >
|
||||||
|
{% endif -%}
|
||||||
|
{{ entity.name|localize_translatable_string }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<i class="fa {% if entity.active %}fa-check-square-o{% else %}fa-square-o{% endif %}"></i>
|
||||||
|
{% if entity.active and not entity.isActiveAndParentActive %}
|
||||||
|
<span class="badge text-bg-danger text-white">{{ 'Associated activity reason category is inactive'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ 'Name'|trans }}</th>
|
<th>{{ 'Name'|trans }}</th>
|
||||||
|
<th>{{ 'Active'|trans }}</th>
|
||||||
<th>{{ 'Actions'|trans }}</th>
|
<th>{{ 'Actions'|trans }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -14,7 +15,11 @@
|
|||||||
{% for entity in entities %}
|
{% for entity in entities %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ path('chill_activity_activityreasoncategory_show', { 'id': entity.id }) }}">{{ entity.name|localize_translatable_string }}</a></td>
|
{{ entity.name|localize_translatable_string }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<i class="fa {% if entity.active %}fa-check-square-o{% else %}fa-square-o{% endif %}"></i>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
|
@@ -369,8 +369,12 @@ final class ActivityControllerTest extends WebTestCase
|
|||||||
$center
|
$center
|
||||||
);
|
);
|
||||||
$reachableScopesId = array_intersect(
|
$reachableScopesId = array_intersect(
|
||||||
array_map(static function ($s) { return $s->getId(); }, $reachableScopesDelete),
|
array_map(static function ($s) {
|
||||||
array_map(static function ($s) { return $s->getId(); }, $reachableScopesUpdate)
|
return $s->getId();
|
||||||
|
}, $reachableScopesDelete),
|
||||||
|
array_map(static function ($s) {
|
||||||
|
return $s->getId();
|
||||||
|
}, $reachableScopesUpdate)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (count($reachableScopesId) === 0) {
|
if (count($reachableScopesId) === 0) {
|
||||||
|
@@ -188,7 +188,9 @@ final class ActivityTypeTest extends KernelTestCase
|
|||||||
|
|
||||||
// map all the values in an array
|
// map all the values in an array
|
||||||
$values = array_map(
|
$values = array_map(
|
||||||
static function ($choice) { return $choice->value; },
|
static function ($choice) {
|
||||||
|
return $choice->value;
|
||||||
|
},
|
||||||
$view['activity']['durationTime']->vars['choices']
|
$view['activity']['durationTime']->vars['choices']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Tests\Form\Type;
|
namespace Chill\ActivityBundle\Tests\Form\Type;
|
||||||
|
|
||||||
use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
|
use Chill\ActivityBundle\Form\Type\PickActivityReasonType;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
use Symfony\Component\Form\PreloadedExtension;
|
use Symfony\Component\Form\PreloadedExtension;
|
||||||
use Symfony\Component\Form\Test\TypeTestCase;
|
use Symfony\Component\Form\Test\TypeTestCase;
|
||||||
@@ -36,7 +36,7 @@ final class TranslatableActivityReasonTest extends TypeTestCase
|
|||||||
|
|
||||||
public function testSimple()
|
public function testSimple()
|
||||||
{
|
{
|
||||||
$translatableActivityReasonType = new TranslatableActivityReason(
|
$translatableActivityReasonType = new PickActivityReasonType(
|
||||||
$this->getTranslatableStringHelper()
|
$this->getTranslatableStringHelper()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -1,4 +1,11 @@
|
|||||||
services:
|
services:
|
||||||
Chill\ActivityBundle\Controller\ActivityController:
|
_defaults:
|
||||||
autowire: true
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Controller\:
|
||||||
|
resource: '../../Controller/'
|
||||||
|
tags: ['controller.service_arguments']
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Controller\ActivityController:
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
@@ -41,6 +41,12 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export, alias: 'avg_activity_visit_duration_linked_to_acp' }
|
- { name: chill.export, alias: 'avg_activity_visit_duration_linked_to_acp' }
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Export\LinkedToACP\ListActivity:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export, alias: 'list_activity_acp'}
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Export\ListActivityHelper: ~
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
chill.activity.export.type_filter:
|
chill.activity.export.type_filter:
|
||||||
class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter
|
class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter
|
||||||
@@ -120,15 +126,18 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export_filter, alias: 'activity_usersscope_filter' }
|
- { name: chill.export_filter, alias: 'activity_usersscope_filter' }
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Filter\ACPFilters\HasNoActivityFilter:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: 'accompanyingcourse_has_no_activity_filter' }
|
||||||
|
|
||||||
## Aggregators
|
## Aggregators
|
||||||
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator:
|
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_reason_aggregator }
|
- { name: chill.export_aggregator, alias: activity_reason_aggregator }
|
||||||
|
|
||||||
chill.activity.export.type_aggregator:
|
Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator:
|
||||||
class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator
|
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_type_aggregator }
|
- { name: chill.export_aggregator, alias: activity_common_type_aggregator }
|
||||||
|
|
||||||
chill.activity.export.user_aggregator:
|
chill.activity.export.user_aggregator:
|
||||||
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
|
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
|
||||||
@@ -179,3 +188,11 @@ services:
|
|||||||
Chill\ActivityBundle\Export\Aggregator\ActivityUsersJobAggregator:
|
Chill\ActivityBundle\Export\Aggregator\ActivityUsersJobAggregator:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_users_job_aggregator }
|
- { name: chill.export_aggregator, alias: activity_users_job_aggregator }
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityNumberAggregator:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: accompanyingcourse_by_activity_number_aggregator }
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Aggregator\SentReceivedAggregator:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: activity_sentreceived_aggregator }
|
||||||
|
@@ -1,19 +1,12 @@
|
|||||||
---
|
---
|
||||||
services:
|
services:
|
||||||
chill.activity.form.type.translatableactivityreasoncategory:
|
Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategoryType:
|
||||||
class: Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategory
|
autowire: true
|
||||||
arguments:
|
autoconfigure: true
|
||||||
- "@request_stack"
|
|
||||||
tags:
|
|
||||||
- { name: form.type, alias: translatable_activity_reason_category }
|
|
||||||
|
|
||||||
chill.activity.form.type.translatableactivityreason:
|
Chill\ActivityBundle\Form\Type\PickActivityReasonType:
|
||||||
class: Chill\ActivityBundle\Form\Type\TranslatableActivityReason
|
autowire: true
|
||||||
arguments:
|
autoconfigure: true
|
||||||
$translatableStringHelper: "@chill.main.helper.translatable_string"
|
|
||||||
$reasonRender: '@Chill\ActivityBundle\Templating\Entity\ActivityReasonRender'
|
|
||||||
tags:
|
|
||||||
- { name: form.type, alias: translatable_activity_reason }
|
|
||||||
|
|
||||||
chill.activity.form.type.translatableactivitytype:
|
chill.activity.form.type.translatableactivitytype:
|
||||||
class: Chill\ActivityBundle\Form\Type\TranslatableActivityType
|
class: Chill\ActivityBundle\Form\Type\TranslatableActivityType
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
---
|
---
|
||||||
services:
|
services:
|
||||||
|
Chill\ActivityBundle\Repository\ActivityReasonRepository:
|
||||||
|
autowire: true
|
||||||
|
|
||||||
chill_activity.repository.activity_type: '@Chill\ActivityBundle\Repository\ActivityTypeRepository'
|
chill_activity.repository.activity_type: '@Chill\ActivityBundle\Repository\ActivityTypeRepository'
|
||||||
chill_activity.repository.reason: '@Chill\ActivityBundle\Repository\ActivityReasonRepository'
|
chill_activity.repository.reason: '@Chill\ActivityBundle\Repository\ActivityReasonRepository'
|
||||||
chill_activity.repository.reason_category: '@Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository'
|
chill_activity.repository.reason_category: '@Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository'
|
||||||
|
@@ -45,6 +45,8 @@ by: 'Par '
|
|||||||
location: Lieu
|
location: Lieu
|
||||||
Reasons: Sujets
|
Reasons: Sujets
|
||||||
Private comment: Commentaire privé
|
Private comment: Commentaire privé
|
||||||
|
sent: Envoyé
|
||||||
|
received: Reçu
|
||||||
|
|
||||||
|
|
||||||
#forms
|
#forms
|
||||||
@@ -115,6 +117,7 @@ Activity Reasons: Sujets d'une activité
|
|||||||
Activity Reasons Category: Catégories de sujet d'activités
|
Activity Reasons Category: Catégories de sujet d'activités
|
||||||
Activity Types Categories: Catégories des types d'activité
|
Activity Types Categories: Catégories des types d'activité
|
||||||
Activity Presences: Presences aux activités
|
Activity Presences: Presences aux activités
|
||||||
|
Associated activity reason category is inactive: La catégorie de sujet attachée est inactive
|
||||||
|
|
||||||
|
|
||||||
# Crud
|
# Crud
|
||||||
@@ -260,8 +263,6 @@ activity is not emergency: l'activité n'est pas urgente
|
|||||||
Filter activity by sentreceived: Filtrer les activités par envoyé/reçu
|
Filter activity by sentreceived: Filtrer les activités par envoyé/reçu
|
||||||
'Filtered activity by sentreceived: only %sentreceived%': "Filtré par envoyé/reçu: uniquement %sentreceived%"
|
'Filtered activity by sentreceived: only %sentreceived%': "Filtré par envoyé/reçu: uniquement %sentreceived%"
|
||||||
Accepted sentreceived: ''
|
Accepted sentreceived: ''
|
||||||
is sent: envoyé
|
|
||||||
is received: reçu
|
|
||||||
Filter activity by linked socialaction: Filtrer les activités par action liée
|
Filter activity by linked socialaction: Filtrer les activités par action liée
|
||||||
'Filtered activity by linked socialaction: only %actions%': "Filtré par action liée: uniquement %actions%"
|
'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 activités par problématique liée
|
||||||
@@ -277,6 +278,10 @@ Filter activity by userscope: Filtrer les activités par service du créateur
|
|||||||
'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
|
'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
|
||||||
Accepted userscope: Services
|
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é
|
||||||
|
|
||||||
#aggregators
|
#aggregators
|
||||||
Activity type: Type d'activité
|
Activity type: Type d'activité
|
||||||
Activity user: Utilisateur lié à l'activité
|
Activity user: Utilisateur lié à l'activité
|
||||||
@@ -319,11 +324,32 @@ This is the minimal activity data: Activité n°
|
|||||||
|
|
||||||
docgen:
|
docgen:
|
||||||
Activity basic: Echange
|
Activity basic: Echange
|
||||||
A basic context for activity: Contexte pour les échanges
|
A basic context for activity: Contexte pour les activités
|
||||||
Accompanying period with a list of activities: Parcours d'accompagnement avec liste des échanges
|
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 échanges pour un parcours. Les échanges ne sont pas filtré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.
|
||||||
|
|
||||||
export:
|
export:
|
||||||
|
list:
|
||||||
|
activity:
|
||||||
|
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
|
||||||
|
thirds parties: Tiers
|
||||||
|
date: Date de l'activité
|
||||||
|
locationName: Localisation
|
||||||
|
sent received: Envoyé ou reçu
|
||||||
|
emergency: Urgence
|
||||||
|
accompanying course id: Identifiant du parcours
|
||||||
|
course circles: Cercles du parcours
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
filter:
|
filter:
|
||||||
activity:
|
activity:
|
||||||
by_usersjob:
|
by_usersjob:
|
||||||
@@ -332,3 +358,10 @@ export:
|
|||||||
by_usersscope:
|
by_usersscope:
|
||||||
Filter by users scope: Filtrer les activités par services d'au moins un utilisateur participant
|
Filter by users scope: Filtrer les activités 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%'
|
'Filtered activity by users scope: only %scopes%': 'Filtré par service d''au moins un utilisateur participant: seulement %scopes%'
|
||||||
|
aggregator:
|
||||||
|
activity:
|
||||||
|
by_sent_received:
|
||||||
|
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
|
||||||
|
@@ -231,4 +231,4 @@ This is the minimal activity data: Activité n°
|
|||||||
|
|
||||||
docgen:
|
docgen:
|
||||||
Activity basic: Echange
|
Activity basic: Echange
|
||||||
A basic context for activity: Contexte pour les échanges
|
A basic context for activity: Contexte pour les activités
|
||||||
|
@@ -16,7 +16,7 @@ For this type of activity, document is required: Pour ce type d'activité, un do
|
|||||||
For this type of activity, emergency is required: Pour ce type d'activité, le champ "Urgent" 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, 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 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 indiquez au moins une action 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
|
||||||
|
|
||||||
# admin
|
# 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"
|
This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales"
|
||||||
|
@@ -30,6 +30,8 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
|
|||||||
$loader->load('services.yaml');
|
$loader->load('services.yaml');
|
||||||
$loader->load('services/form.yaml');
|
$loader->load('services/form.yaml');
|
||||||
$loader->load('services/menu.yaml');
|
$loader->load('services/menu.yaml');
|
||||||
|
$loader->load('services/security.yaml');
|
||||||
|
$loader->load('services/export.yaml');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function prepend(ContainerBuilder $container)
|
public function prepend(ContainerBuilder $container)
|
||||||
|
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Export\Aggregator;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Export\Declarations;
|
||||||
|
use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository;
|
||||||
|
use Chill\MainBundle\Export\AggregatorInterface;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class ByActivityTypeAggregator implements AggregatorInterface
|
||||||
|
{
|
||||||
|
private AsideActivityCategoryRepository $asideActivityCategoryRepository;
|
||||||
|
|
||||||
|
private TranslatableStringHelper $translatableStringHelper;
|
||||||
|
|
||||||
|
public function __construct(AsideActivityCategoryRepository $asideActivityCategoryRepository, TranslatableStringHelper $translatableStringHelper)
|
||||||
|
{
|
||||||
|
$this->asideActivityCategoryRepository = $asideActivityCategoryRepository;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
|
{
|
||||||
|
$qb->addSelect('IDENTITY(aside.type) AS by_aside_activity_type_aggregator')
|
||||||
|
->addGroupBy('by_aside_activity_type_aggregator');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
// No form needed
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
$this->asideActivityCategoryRepository->findBy(['id' => $values]);
|
||||||
|
|
||||||
|
return function ($value): string {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'export.aggregator.Aside activity type';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$t = $this->asideActivityCategoryRepository->find($value);
|
||||||
|
|
||||||
|
return $this->translatableStringHelper->localize($t->getTitle());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['by_aside_activity_type_aggregator'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.aggregator.Group by aside activity type';
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,20 @@
|
|||||||
|
<?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\AsideActivityBundle\Export;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class declare constants used for the export framework.
|
||||||
|
*/
|
||||||
|
abstract class Declarations
|
||||||
|
{
|
||||||
|
public const ASIDE_ACTIVITY_TYPE = 'aside_activity';
|
||||||
|
}
|
@@ -0,0 +1,105 @@
|
|||||||
|
<?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\AsideActivityBundle\Export\Export;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Repository\AsideActivityRepository;
|
||||||
|
use Chill\AsideActivityBundle\Security\AsideActivityVoter;
|
||||||
|
use Chill\MainBundle\Export\ExportInterface;
|
||||||
|
use Chill\MainBundle\Export\FormatterInterface;
|
||||||
|
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||||
|
use ChillAsideActivityBundle\Export\Declarations;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
|
use LogicException;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class CountAsideActivity implements ExportInterface, GroupedExportInterface
|
||||||
|
{
|
||||||
|
private AsideActivityRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
AsideActivityRepository $repository
|
||||||
|
) {
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowedFormattersTypes(): array
|
||||||
|
{
|
||||||
|
return [FormatterInterface::TYPE_TABULAR];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'export.Count aside activities by various parameters.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGroup(): string
|
||||||
|
{
|
||||||
|
return 'export.Exports of aside activities';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
if ('export_result' !== $key) {
|
||||||
|
throw new LogicException("the key {$key} is not used by this export");
|
||||||
|
}
|
||||||
|
|
||||||
|
$labels = array_combine($values, $values);
|
||||||
|
$labels['_header'] = $this->getTitle();
|
||||||
|
|
||||||
|
return static function ($value) use ($labels) {
|
||||||
|
return $labels[$value];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['export_result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult($query, $data)
|
||||||
|
{
|
||||||
|
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.Count aside activities';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('aside');
|
||||||
|
|
||||||
|
$qb->select('COUNT(DISTINCT aside.id) AS export_result');
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiredRole(): string
|
||||||
|
{
|
||||||
|
return AsideActivityVoter::STATS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsModifiers(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,96 @@
|
|||||||
|
<?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\AsideActivityBundle\Export\Filter;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||||
|
use Chill\AsideActivityBundle\Export\Declarations;
|
||||||
|
use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository;
|
||||||
|
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class ByActivityTypeFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
private AsideActivityCategoryRepository $asideActivityTypeRepository;
|
||||||
|
|
||||||
|
private CategoryRender $categoryRender;
|
||||||
|
|
||||||
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
CategoryRender $categoryRender,
|
||||||
|
TranslatableStringHelperInterface $translatableStringHelper,
|
||||||
|
AsideActivityCategoryRepository $asideActivityTypeRepository
|
||||||
|
) {
|
||||||
|
$this->categoryRender = $categoryRender;
|
||||||
|
$this->asideActivityTypeRepository = $asideActivityTypeRepository;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
|
{
|
||||||
|
$clause = $qb->expr()->in('aside.type', ':types');
|
||||||
|
|
||||||
|
$qb->andWhere($clause);
|
||||||
|
$qb->setParameter('types', $data['types']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('types', EntityType::class, [
|
||||||
|
'class' => AsideActivityCategory::class,
|
||||||
|
'choices' => $this->asideActivityTypeRepository->findAllActive(),
|
||||||
|
'required' => false,
|
||||||
|
'multiple' => true,
|
||||||
|
'expanded' => false,
|
||||||
|
'attr' => [
|
||||||
|
'class' => 'select2',
|
||||||
|
],
|
||||||
|
'choice_label' => function (AsideActivityCategory $category) {
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
return $this->categoryRender->renderString($category, $options);
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAction($data, $format = 'string'): array
|
||||||
|
{
|
||||||
|
$types = array_map(
|
||||||
|
fn (AsideActivityCategory $t): string => $this->translatableStringHelper->localize($t->getName()),
|
||||||
|
$this->asideActivityTypeRepository->findBy(['id' => $data['types']->toArray()])
|
||||||
|
);
|
||||||
|
|
||||||
|
return ['export.filter.Filtered by aside activity type: only %type%', [
|
||||||
|
'%type%' => implode(', ', $types),
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.Filter by aside activity type';
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,143 @@
|
|||||||
|
<?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\AsideActivityBundle\Export\Filter;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Export\Declarations;
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\MainBundle\Form\Type\Export\FilterType;
|
||||||
|
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
||||||
|
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||||
|
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||||
|
use Doctrine\ORM\Query\Expr\Andx;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormError;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
class ByDateFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
protected TranslatorInterface $translator;
|
||||||
|
|
||||||
|
private RollingDateConverterInterface $rollingDateConverter;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
RollingDateConverterInterface $rollingDateConverter,
|
||||||
|
TranslatorInterface $translator
|
||||||
|
) {
|
||||||
|
$this->translator = $translator;
|
||||||
|
$this->rollingDateConverter = $rollingDateConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
|
{
|
||||||
|
$where = $qb->getDQLPart('where');
|
||||||
|
$clause = $qb->expr()->between(
|
||||||
|
'aside.date',
|
||||||
|
':date_from',
|
||||||
|
':date_to'
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($where instanceof Andx) {
|
||||||
|
$where->add($clause);
|
||||||
|
} else {
|
||||||
|
$where = $qb->expr()->andX($clause);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->add('where', $where);
|
||||||
|
$qb->setParameter(
|
||||||
|
'date_from',
|
||||||
|
$this->rollingDateConverter->convert($data['date_from'])
|
||||||
|
);
|
||||||
|
$qb->setParameter(
|
||||||
|
'date_to',
|
||||||
|
$this->rollingDateConverter->convert($data['date_to'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('date_from', PickRollingDateType::class, [
|
||||||
|
'label' => 'export.filter.Aside activities after this date',
|
||||||
|
'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
|
||||||
|
])
|
||||||
|
->add('date_to', PickRollingDateType::class, [
|
||||||
|
'label' => 'export.filter.Aside activities before this date',
|
||||||
|
'data' => new RollingDate(RollingDate::T_TODAY),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
|
||||||
|
/** @var \Symfony\Component\Form\FormInterface $filterForm */
|
||||||
|
$filterForm = $event->getForm()->getParent();
|
||||||
|
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
|
||||||
|
|
||||||
|
if (true === $enabled) {
|
||||||
|
// if the filter is enabled, add some validation
|
||||||
|
$form = $event->getForm();
|
||||||
|
$date_from = $form->get('date_from')->getData();
|
||||||
|
$date_to = $form->get('date_to')->getData();
|
||||||
|
|
||||||
|
// check that fields are not empty
|
||||||
|
if (null === $date_from) {
|
||||||
|
$form->get('date_from')->addError(new FormError(
|
||||||
|
$this->translator->trans('This field '
|
||||||
|
. 'should not be empty')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $date_to) {
|
||||||
|
$form->get('date_to')->addError(new FormError(
|
||||||
|
$this->translator->trans('This field '
|
||||||
|
. 'should not be empty')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that date_from is before date_to
|
||||||
|
if (
|
||||||
|
(null !== $date_from && null !== $date_to)
|
||||||
|
&& $date_from >= $date_to
|
||||||
|
) {
|
||||||
|
$form->get('date_to')->addError(new FormError(
|
||||||
|
$this->translator->trans('export.filter.This date should be after '
|
||||||
|
. 'the date given in "Implied in an aside activity after '
|
||||||
|
. 'this date" field')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAction($data, $format = 'string'): array
|
||||||
|
{
|
||||||
|
return ['export.filter.Filtered by aside activities between %dateFrom% and %dateTo%', [
|
||||||
|
'%dateFrom%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'),
|
||||||
|
'%dateTo%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'),
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.Filter by aside activity date';
|
||||||
|
}
|
||||||
|
}
|
@@ -12,8 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\AsideActivityBundle\Form;
|
namespace Chill\AsideActivityBundle\Form;
|
||||||
|
|
||||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
use Chill\AsideActivityBundle\Form\Type\PickAsideActivityCategoryType;
|
||||||
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||||
@@ -21,8 +20,6 @@ use DateInterval;
|
|||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use Doctrine\ORM\EntityRepository;
|
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
||||||
@@ -37,20 +34,16 @@ use function in_array;
|
|||||||
|
|
||||||
final class AsideActivityFormType extends AbstractType
|
final class AsideActivityFormType extends AbstractType
|
||||||
{
|
{
|
||||||
private CategoryRender $categoryRender;
|
|
||||||
|
|
||||||
private TokenStorageInterface $storage;
|
private TokenStorageInterface $storage;
|
||||||
|
|
||||||
private array $timeChoices;
|
private array $timeChoices;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ParameterBagInterface $parameterBag,
|
ParameterBagInterface $parameterBag,
|
||||||
TokenStorageInterface $storage,
|
TokenStorageInterface $storage
|
||||||
CategoryRender $categoryRender
|
|
||||||
) {
|
) {
|
||||||
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
$this->categoryRender = $categoryRender;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
@@ -81,28 +74,10 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
'required' => true,
|
'required' => true,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
->add(
|
->add('type', PickAsideActivityCategoryType::class, [
|
||||||
'type',
|
|
||||||
EntityType::class,
|
|
||||||
[
|
|
||||||
'label' => 'Type',
|
'label' => 'Type',
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'class' => AsideActivityCategory::class,
|
])
|
||||||
'placeholder' => 'Choose the activity category',
|
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
|
||||||
$qb = $er->createQueryBuilder('ac');
|
|
||||||
$qb->where($qb->expr()->eq('ac.isActive', 'TRUE'))
|
|
||||||
->addOrderBy('ac.ordering', 'ASC');
|
|
||||||
|
|
||||||
return $qb;
|
|
||||||
},
|
|
||||||
'choice_label' => function (AsideActivityCategory $asideActivityCategory) {
|
|
||||||
$options = [];
|
|
||||||
|
|
||||||
return $this->categoryRender->renderString($asideActivityCategory, $options);
|
|
||||||
},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
->add('duration', ChoiceType::class, $durationTimeOptions)
|
->add('duration', ChoiceType::class, $durationTimeOptions)
|
||||||
->add('note', ChillTextareaType::class, [
|
->add('note', ChillTextareaType::class, [
|
||||||
'label' => 'Note',
|
'label' => 'Note',
|
||||||
|
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Form\Type;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||||
|
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
final class PickAsideActivityCategoryType extends AbstractType
|
||||||
|
{
|
||||||
|
private CategoryRender $categoryRender;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
CategoryRender $categoryRender
|
||||||
|
) {
|
||||||
|
$this->categoryRender = $categoryRender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefaults([
|
||||||
|
'class' => AsideActivityCategory::class,
|
||||||
|
'placeholder' => 'Choose the activity category',
|
||||||
|
'query_builder' => static function (EntityRepository $er) {
|
||||||
|
$qb = $er->createQueryBuilder('ac');
|
||||||
|
$qb->where($qb->expr()->eq('ac.isActive', 'TRUE'))
|
||||||
|
->addOrderBy('ac.ordering', 'ASC');
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
},
|
||||||
|
'choice_label' => function (AsideActivityCategory $asideActivityCategory) {
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
return $this->categoryRender->renderString($asideActivityCategory, $options);
|
||||||
|
},
|
||||||
|
'attr' => ['class' => 'select2'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent(): string
|
||||||
|
{
|
||||||
|
return EntityType::class;
|
||||||
|
}
|
||||||
|
}
|
@@ -38,6 +38,11 @@ class AsideActivityCategoryRepository implements ObjectRepository
|
|||||||
return $this->repository->findAll();
|
return $this->repository->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findAllActive(): array
|
||||||
|
{
|
||||||
|
return $this->repository->findBy(['isActive' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed|null $limit
|
* @param mixed|null $limit
|
||||||
* @param mixed|null $offset
|
* @param mixed|null $offset
|
||||||
|
@@ -12,46 +12,20 @@ declare(strict_types=1);
|
|||||||
namespace Chill\AsideActivityBundle\Repository;
|
namespace Chill\AsideActivityBundle\Repository;
|
||||||
|
|
||||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
|
||||||
|
|
||||||
final class AsideActivityRepository implements ObjectRepository
|
/**
|
||||||
|
* @method AsideActivity|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method AsideActivity|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method AsideActivity[] findAll()
|
||||||
|
* @method AsideActivity[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
final class AsideActivityRepository extends ServiceEntityRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $entityManager)
|
|
||||||
{
|
{
|
||||||
$this->repository = $entityManager->getRepository(AsideActivity::class);
|
parent::__construct($registry, AsideActivity::class);
|
||||||
}
|
|
||||||
|
|
||||||
public function find($id): ?AsideActivity
|
|
||||||
{
|
|
||||||
return $this->repository->find($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return AsideActivity[]
|
|
||||||
*/
|
|
||||||
public function findAll(): array
|
|
||||||
{
|
|
||||||
return $this->repository->findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed|null $limit
|
|
||||||
* @param mixed|null $offset
|
|
||||||
*
|
|
||||||
* @return AsideActivity[]
|
|
||||||
*/
|
|
||||||
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
|
|
||||||
{
|
|
||||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function findOneBy(array $criteria): ?AsideActivity
|
|
||||||
{
|
|
||||||
return $this->repository->findOneBy($criteria);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClassName(): string
|
public function getClassName(): string
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div class="{% block crud_content_main_div_class %}col-10 centered{% endblock %}">
|
|
||||||
{% block crud_content_header %}
|
{% block crud_content_header %}
|
||||||
<h1>{{ ('crud.'~crud_name~'.title_delete')|trans({ '%as_string%': 'Aside Activity' }) }}</h1>
|
<h1>{{ ('crud.'~crud_name~'.title_delete')|trans({ '%as_string%': 'Aside Activity' }) }}</h1>
|
||||||
{% endblock crud_content_header %}
|
{% endblock crud_content_header %}
|
||||||
@@ -27,4 +27,4 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
</div>
|
|
||||||
|
@@ -87,5 +87,5 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
{% extends '@ChillMain/Admin/layout.html.twig' %}
|
{% extends '@ChillMain/layout.html.twig' %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
|
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block admin_content %}
|
{% block content %}
|
||||||
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
|
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
|
||||||
{% block content_form_actions_save_and_show %}{% endblock %}
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
{% endembed %}
|
{% endembed %}
|
||||||
|
@@ -0,0 +1,79 @@
|
|||||||
|
<?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\AsideActivityBundle\Security;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||||
|
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
||||||
|
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
||||||
|
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
|
||||||
|
class AsideActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||||
|
{
|
||||||
|
public const STATS = 'CHILL_ASIDE_ACTIVITY_STATS';
|
||||||
|
|
||||||
|
private VoterHelperInterface $voterHelper;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
VoterHelperFactoryInterface $voterHelperFactory
|
||||||
|
) {
|
||||||
|
$this->voterHelper = $voterHelperFactory
|
||||||
|
->generate(self::class)
|
||||||
|
->addCheckFor(Center::class, [self::STATS])
|
||||||
|
->build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getRoles(): array
|
||||||
|
{
|
||||||
|
return $this->getAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[][]
|
||||||
|
*/
|
||||||
|
public function getRolesWithHierarchy(): array
|
||||||
|
{
|
||||||
|
return ['Aside activity' => $this->getRoles()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getRolesWithoutScope(): array
|
||||||
|
{
|
||||||
|
return $this->getAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function supports($attribute, $subject)
|
||||||
|
{
|
||||||
|
return $this->voterHelper->supports($attribute, $subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
|
||||||
|
{
|
||||||
|
if (!$token->getUser() instanceof User) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->voterHelper->voteOnAttribute($attribute, $subject, $token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAttributes(): array
|
||||||
|
{
|
||||||
|
return [self::STATS];
|
||||||
|
}
|
||||||
|
}
|
@@ -20,3 +20,33 @@ services:
|
|||||||
resource: "../Controller"
|
resource: "../Controller"
|
||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
|
|
||||||
|
|
||||||
|
## Exports
|
||||||
|
|
||||||
|
# indicators
|
||||||
|
Chill\AsideActivityBundle\Export\Export\CountAsideActivity:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
tags:
|
||||||
|
- { name: chill.export, alias: count_asideactivity }
|
||||||
|
|
||||||
|
# filters
|
||||||
|
Chill\AsideActivityBundle\Export\Filter\ByDateFilter:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: asideactivity_bydate_filter }
|
||||||
|
|
||||||
|
Chill\AsideActivityBundle\Export\Filter\ByActivityTypeFilter:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: asideactivity_activitytype_filter }
|
||||||
|
|
||||||
|
# aggregators
|
||||||
|
Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: asideactivity_activitytype_aggregator }
|
||||||
|
@@ -0,0 +1,27 @@
|
|||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
## Indicators
|
||||||
|
Chill\AsideActivityBundle\Export\Export\CountAsideActivity:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export, alias: 'count_aside_activity' }
|
||||||
|
|
||||||
|
## Filters
|
||||||
|
chill.aside_activity.export.date_filter:
|
||||||
|
class: Chill\AsideActivityBundle\Export\Filter\ByDateFilter
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: 'aside_activity_date_filter' }
|
||||||
|
|
||||||
|
chill.aside_activity.export.type_filter:
|
||||||
|
class: Chill\AsideActivityBundle\Export\Filter\ByActivityTypeFilter
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: 'aside_activity_type_filter' }
|
||||||
|
|
||||||
|
## Aggregators
|
||||||
|
|
||||||
|
chill.aside_activity.export.type_aggregator:
|
||||||
|
class: Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: activity_type_aggregator }
|
@@ -0,0 +1,7 @@
|
|||||||
|
services:
|
||||||
|
Chill\AsideActivityBundle\Security\AsideActivityVoter:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
tags:
|
||||||
|
- { name: security.voter }
|
||||||
|
- { name: chill.role }
|
@@ -166,3 +166,21 @@ Aside activities: Activités annexes
|
|||||||
Aside activity types: Types d'activités annexes
|
Aside activity types: Types d'activités annexes
|
||||||
Aside activity type configuration: Configuration des categories d'activités annexes
|
Aside activity type configuration: Configuration des categories d'activités annexes
|
||||||
Aside activity configuration: Configuration des activités annexes
|
Aside activity configuration: Configuration des activités annexes
|
||||||
|
|
||||||
|
# exports
|
||||||
|
export:
|
||||||
|
Exports of aside activities: Exports des activités annexes
|
||||||
|
Count aside activities: Nombre d'activités annexes
|
||||||
|
Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères
|
||||||
|
filter:
|
||||||
|
Filter by aside activity date: Filtrer les activités annexes par date
|
||||||
|
Filter by aside activity type: Filtrer les activités annexes par type d'activité
|
||||||
|
'Filtered by aside activity type: only %type%': "Filtré par type d'activité annexe: uniquement %type%"
|
||||||
|
This date should be after the date given in "Implied in an aside activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités annexes après cette date"
|
||||||
|
Aside activities after this date: Actvitités annexes après cette date
|
||||||
|
Aside activities before this date: Actvitités annexes avant cette date
|
||||||
|
aggregator:
|
||||||
|
Group by aside activity type: Grouper les activités annexes par type d'activité
|
||||||
|
Aside activity type: Type d'activité annexe
|
||||||
|
|
||||||
|
|
||||||
|
@@ -31,7 +31,9 @@ class ConfigRepository
|
|||||||
|
|
||||||
public function getChargesKeys(bool $onlyActive = false): array
|
public function getChargesKeys(bool $onlyActive = false): array
|
||||||
{
|
{
|
||||||
return array_map(static function ($element) { return $element['key']; }, $this->getCharges($onlyActive));
|
return array_map(static function ($element) {
|
||||||
|
return $element['key'];
|
||||||
|
}, $this->getCharges($onlyActive));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +52,9 @@ class ConfigRepository
|
|||||||
|
|
||||||
public function getResourcesKeys(bool $onlyActive = false): array
|
public function getResourcesKeys(bool $onlyActive = false): array
|
||||||
{
|
{
|
||||||
return array_map(static function ($element) { return $element['key']; }, $this->getResources($onlyActive));
|
return array_map(static function ($element) {
|
||||||
|
return $element['key'];
|
||||||
|
}, $this->getResources($onlyActive));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,14 +74,18 @@ class ConfigRepository
|
|||||||
private function getCharges(bool $onlyActive = false): array
|
private function getCharges(bool $onlyActive = false): array
|
||||||
{
|
{
|
||||||
return $onlyActive ?
|
return $onlyActive ?
|
||||||
array_filter($this->charges, static function ($el) { return $el['active']; })
|
array_filter($this->charges, static function ($el) {
|
||||||
|
return $el['active'];
|
||||||
|
})
|
||||||
: $this->charges;
|
: $this->charges;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getResources(bool $onlyActive = false): array
|
private function getResources(bool $onlyActive = false): array
|
||||||
{
|
{
|
||||||
return $onlyActive ?
|
return $onlyActive ?
|
||||||
array_filter($this->resources, static function ($el) { return $el['active']; })
|
array_filter($this->resources, static function ($el) {
|
||||||
|
return $el['active'];
|
||||||
|
})
|
||||||
: $this->resources;
|
: $this->resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,26 @@
|
|||||||
|
<?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\BudgetBundle\Controller\Admin;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class AdminController extends AbstractController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/admin/budget", name="chill_admin_budget")
|
||||||
|
*/
|
||||||
|
public function indexAdminAction()
|
||||||
|
{
|
||||||
|
return $this->render('@ChillBudget/Admin/index.html.twig');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
<?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\BudgetBundle\Controller\Admin;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
class ChargeKindController extends CRUDController
|
||||||
|
{
|
||||||
|
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||||
|
{
|
||||||
|
/** @var QueryBuilder $query */
|
||||||
|
$query->addOrderBy('e.ordering', 'ASC');
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
<?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\BudgetBundle\Controller\Admin;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
class ResourceKindController extends CRUDController
|
||||||
|
{
|
||||||
|
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||||
|
{
|
||||||
|
/** @var QueryBuilder $query */
|
||||||
|
$query->addOrderBy('e.ordering', 'ASC');
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\BudgetBundle\DependencyInjection;
|
namespace Chill\BudgetBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Chill\BudgetBundle\Controller\Admin\ChargeKindController;
|
||||||
|
use Chill\BudgetBundle\Controller\Admin\ResourceKindController;
|
||||||
|
use Chill\BudgetBundle\Entity\ChargeKind;
|
||||||
|
use Chill\BudgetBundle\Entity\ResourceKind;
|
||||||
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
@@ -33,6 +37,7 @@ class ChillBudgetExtension extends Extension implements PrependExtensionInterfac
|
|||||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||||
$loader->load('services/config.yaml');
|
$loader->load('services/config.yaml');
|
||||||
$loader->load('services/form.yaml');
|
$loader->load('services/form.yaml');
|
||||||
|
$loader->load('services/repository.yaml');
|
||||||
$loader->load('services/security.yaml');
|
$loader->load('services/security.yaml');
|
||||||
$loader->load('services/controller.yaml');
|
$loader->load('services/controller.yaml');
|
||||||
$loader->load('services/templating.yaml');
|
$loader->load('services/templating.yaml');
|
||||||
@@ -48,6 +53,7 @@ class ChillBudgetExtension extends Extension implements PrependExtensionInterfac
|
|||||||
{
|
{
|
||||||
$this->prependAuthorization($container);
|
$this->prependAuthorization($container);
|
||||||
$this->prependRoutes($container);
|
$this->prependRoutes($container);
|
||||||
|
$this->prependCruds($container);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** (non-PHPdoc).
|
/** (non-PHPdoc).
|
||||||
@@ -75,6 +81,56 @@ class ChillBudgetExtension extends Extension implements PrependExtensionInterfac
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function prependCruds(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
$container->prependExtensionConfig('chill_main', [
|
||||||
|
'cruds' => [
|
||||||
|
[
|
||||||
|
'class' => ChargeKind::class,
|
||||||
|
'name' => 'charge_kind',
|
||||||
|
'base_path' => '/admin/budget/charge-kind',
|
||||||
|
'form_class' => \Chill\BudgetBundle\Form\Admin\ChargeKindType::class,
|
||||||
|
'controller' => ChargeKindController::class,
|
||||||
|
'actions' => [
|
||||||
|
'index' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillBudget/Admin/Charge/index.html.twig',
|
||||||
|
],
|
||||||
|
'new' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillBudget/Admin/Charge/new.html.twig',
|
||||||
|
],
|
||||||
|
'edit' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillBudget/Admin/Charge/edit.html.twig',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'class' => ResourceKind::class,
|
||||||
|
'name' => 'resource_kind',
|
||||||
|
'base_path' => '/admin/budget/resource-kind',
|
||||||
|
'form_class' => \Chill\BudgetBundle\Form\Admin\ResourceKindType::class,
|
||||||
|
'controller' => ResourceKindController::class,
|
||||||
|
'actions' => [
|
||||||
|
'index' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillBudget/Admin/Resource/index.html.twig',
|
||||||
|
],
|
||||||
|
'new' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillBudget/Admin/Resource/new.html.twig',
|
||||||
|
],
|
||||||
|
'edit' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillBudget/Admin/Resource/edit.html.twig',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
protected function storeConfig($position, array $config, ContainerBuilder $container)
|
protected function storeConfig($position, array $config, ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$container
|
$container
|
||||||
|
@@ -26,6 +26,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
|
|
||||||
// ressources
|
// ressources
|
||||||
->arrayNode('resources')->defaultValue([])
|
->arrayNode('resources')->defaultValue([])
|
||||||
|
->setDeprecated('Chill', '2.0', 'Since the introduction of budget admin entities, config is no longer used')
|
||||||
->arrayPrototype()
|
->arrayPrototype()
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('key')->isRequired()->cannotBeEmpty()
|
->scalarNode('key')->isRequired()->cannotBeEmpty()
|
||||||
@@ -49,6 +50,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->arrayNode('charges')->defaultValue([])
|
->arrayNode('charges')->defaultValue([])
|
||||||
|
->setDeprecated('Chill', '2.0', 'Since the introduction of budget admin entities, config is no longer used')
|
||||||
->arrayPrototype()
|
->arrayPrototype()
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('key')->isRequired()->cannotBeEmpty()
|
->scalarNode('key')->isRequired()->cannotBeEmpty()
|
||||||
|
@@ -150,7 +150,7 @@ abstract class AbstractElement
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHousehold(Household $household): self
|
public function setHousehold(?Household $household): self
|
||||||
{
|
{
|
||||||
$this->household = $household;
|
$this->household = $household;
|
||||||
|
|
||||||
|
@@ -11,8 +11,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\BudgetBundle\Entity;
|
namespace Chill\BudgetBundle\Entity;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\HasCentersInterface;
|
||||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
* @ORM\Table(name="chill_budget.charge")
|
* @ORM\Table(name="chill_budget.charge")
|
||||||
* @ORM\Entity(repositoryClass="Chill\BudgetBundle\Repository\ChargeRepository")
|
* @ORM\Entity(repositoryClass="Chill\BudgetBundle\Repository\ChargeRepository")
|
||||||
*/
|
*/
|
||||||
class Charge extends AbstractElement implements HasCenterInterface
|
class Charge extends AbstractElement implements HasCentersInterface
|
||||||
{
|
{
|
||||||
public const HELP_ASKED = 'running';
|
public const HELP_ASKED = 'running';
|
||||||
|
|
||||||
@@ -39,6 +39,12 @@ class Charge extends AbstractElement implements HasCenterInterface
|
|||||||
self::HELP_NOT_RELEVANT,
|
self::HELP_NOT_RELEVANT,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=ChargeKind::class, inversedBy="AbstractElement")
|
||||||
|
* @ORM\JoinColumn
|
||||||
|
*/
|
||||||
|
private ?ChargeKind $charge = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
* @ORM\Column(name="help", type="string", nullable=true)
|
* @ORM\Column(name="help", type="string", nullable=true)
|
||||||
@@ -46,22 +52,29 @@ class Charge extends AbstractElement implements HasCenterInterface
|
|||||||
private $help = self::HELP_NOT_RELEVANT;
|
private $help = self::HELP_NOT_RELEVANT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
|
||||||
*
|
|
||||||
* @ORM\Column(name="id", type="integer")
|
* @ORM\Column(name="id", type="integer")
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue(strategy="AUTO")
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
*/
|
*/
|
||||||
private $id;
|
private ?int $id = null;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->setStartDate(new DateTimeImmutable('today'));
|
$this->setStartDate(new DateTimeImmutable('today'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCenter(): ?Center
|
public function getCenters(): array
|
||||||
{
|
{
|
||||||
return $this->getPerson()->getCenter();
|
if (null !== $this->getPerson()) {
|
||||||
|
return [$this->getPerson()->getCenter()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getHousehold()->getCurrentPersons()->map(static fn (Person $p) => $p->getCenter())->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCharge(): ?ChargeKind
|
||||||
|
{
|
||||||
|
return $this->charge;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHelp()
|
public function getHelp()
|
||||||
@@ -89,6 +102,13 @@ class Charge extends AbstractElement implements HasCenterInterface
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setCharge(?ChargeKind $charge): self
|
||||||
|
{
|
||||||
|
$this->charge = $charge;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setHelp($help)
|
public function setHelp($help)
|
||||||
{
|
{
|
||||||
$this->help = $help;
|
$this->help = $help;
|
||||||
|
108
src/Bundle/ChillBudgetBundle/Entity/ChargeKind.php
Normal file
108
src/Bundle/ChillBudgetBundle/Entity/ChargeKind.php
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<?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\BudgetBundle\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of charge.
|
||||||
|
*
|
||||||
|
* @ORM\Table(name="chill_budget.charge_type")
|
||||||
|
* @ORM\Entity
|
||||||
|
*/
|
||||||
|
class ChargeKind
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\GeneratedValue
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="boolean", options={"default": true})
|
||||||
|
*/
|
||||||
|
private bool $isActive = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=255, options={"default": ""}, nullable=false)
|
||||||
|
*/
|
||||||
|
private string $kind = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="json", length=255, options={"default": "[]"})
|
||||||
|
*/
|
||||||
|
private array $name = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="float", options={"default": 0.00})
|
||||||
|
*/
|
||||||
|
private float $ordering = 0.00;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="json", length=255, options={"default": "[]"})
|
||||||
|
*/
|
||||||
|
private array $tags = [];
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsActive(): bool
|
||||||
|
{
|
||||||
|
return $this->isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKind(): ?string
|
||||||
|
{
|
||||||
|
return $this->kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?array
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOrdering(): float
|
||||||
|
{
|
||||||
|
return $this->ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsActive(bool $isActive): self
|
||||||
|
{
|
||||||
|
$this->isActive = $isActive;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setKind(?string $kind): self
|
||||||
|
{
|
||||||
|
$this->kind = $kind;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(array $name): self
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOrdering(float $ordering): ChargeKind
|
||||||
|
{
|
||||||
|
$this->ordering = $ordering;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@@ -11,8 +11,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\BudgetBundle\Entity;
|
namespace Chill\BudgetBundle\Entity;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\HasCentersInterface;
|
||||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
@@ -22,25 +22,33 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
* @ORM\Table(name="chill_budget.resource")
|
* @ORM\Table(name="chill_budget.resource")
|
||||||
* @ORM\Entity(repositoryClass="Chill\BudgetBundle\Repository\ResourceRepository")
|
* @ORM\Entity(repositoryClass="Chill\BudgetBundle\Repository\ResourceRepository")
|
||||||
*/
|
*/
|
||||||
class Resource extends AbstractElement implements HasCenterInterface
|
class Resource extends AbstractElement implements HasCentersInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var int
|
|
||||||
*
|
|
||||||
* @ORM\Column(name="id", type="integer")
|
* @ORM\Column(name="id", type="integer")
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue(strategy="AUTO")
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
*/
|
*/
|
||||||
private $id;
|
private ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=ResourceKind::class, inversedBy="AbstractElement")
|
||||||
|
* @ORM\JoinColumn
|
||||||
|
*/
|
||||||
|
private ?ResourceKind $resource = null;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->setStartDate(new DateTimeImmutable('today'));
|
$this->setStartDate(new DateTimeImmutable('today'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCenter(): ?Center
|
public function getCenters(): array
|
||||||
{
|
{
|
||||||
return $this->getPerson()->getCenter();
|
if (null !== $this->getPerson()) {
|
||||||
|
return [$this->getPerson()->getCenter()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getHousehold()->getCurrentPersons()->map(static fn (Person $p) => $p->getCenter())->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,6 +61,11 @@ class Resource extends AbstractElement implements HasCenterInterface
|
|||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getResource(): ?ResourceKind
|
||||||
|
{
|
||||||
|
return $this->resource;
|
||||||
|
}
|
||||||
|
|
||||||
public function isCharge(): bool
|
public function isCharge(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -62,4 +75,11 @@ class Resource extends AbstractElement implements HasCenterInterface
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setResource(?ResourceKind $resource): self
|
||||||
|
{
|
||||||
|
$this->resource = $resource;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
108
src/Bundle/ChillBudgetBundle/Entity/ResourceKind.php
Normal file
108
src/Bundle/ChillBudgetBundle/Entity/ResourceKind.php
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<?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\BudgetBundle\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of resource.
|
||||||
|
*
|
||||||
|
* @ORM\Table(name="chill_budget.resource_type")
|
||||||
|
* @ORM\Entity
|
||||||
|
*/
|
||||||
|
class ResourceKind
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\GeneratedValue
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="boolean", options={"default": true})
|
||||||
|
*/
|
||||||
|
private bool $isActive = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=255, nullable=false, options={"default": ""})
|
||||||
|
*/
|
||||||
|
private string $kind = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="json", length=255, options={"default": "[]"})
|
||||||
|
*/
|
||||||
|
private array $name = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="float", options={"default": 0.00})
|
||||||
|
*/
|
||||||
|
private float $ordering = 0.00;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="json", length=255, options={"default": "[]"})
|
||||||
|
*/
|
||||||
|
private array $tags = [];
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsActive(): bool
|
||||||
|
{
|
||||||
|
return $this->isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKind(): ?string
|
||||||
|
{
|
||||||
|
return $this->kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?array
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOrdering(): float
|
||||||
|
{
|
||||||
|
return $this->ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsActive(bool $isActive): self
|
||||||
|
{
|
||||||
|
$this->isActive = $isActive;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setKind(?string $kind): self
|
||||||
|
{
|
||||||
|
$this->kind = $kind;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(array $name): self
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOrdering(float $ordering): self
|
||||||
|
{
|
||||||
|
$this->ordering = $ordering;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
42
src/Bundle/ChillBudgetBundle/Form/Admin/ChargeKindType.php
Normal file
42
src/Bundle/ChillBudgetBundle/Form/Admin/ChargeKindType.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?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\BudgetBundle\Form\Admin;
|
||||||
|
|
||||||
|
use Chill\BudgetBundle\Entity\ChargeKind;
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class ChargeKindType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('name', TranslatableStringFormType::class, [
|
||||||
|
'label' => 'Nom',
|
||||||
|
])
|
||||||
|
->add('ordering', NumberType::class)
|
||||||
|
->add('isActive', CheckboxType::class, [
|
||||||
|
'label' => 'Actif ?',
|
||||||
|
'required' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefault('class', ChargeKind::class);
|
||||||
|
}
|
||||||
|
}
|
42
src/Bundle/ChillBudgetBundle/Form/Admin/ResourceKindType.php
Normal file
42
src/Bundle/ChillBudgetBundle/Form/Admin/ResourceKindType.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?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\BudgetBundle\Form\Admin;
|
||||||
|
|
||||||
|
use Chill\BudgetBundle\Entity\ResourceKind;
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class ResourceKindType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('name', TranslatableStringFormType::class, [
|
||||||
|
'label' => 'Nom',
|
||||||
|
])
|
||||||
|
->add('ordering', NumberType::class)
|
||||||
|
->add('isActive', CheckboxType::class, [
|
||||||
|
'label' => 'Actif ?',
|
||||||
|
'required' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefault('class', ResourceKind::class);
|
||||||
|
}
|
||||||
|
}
|
@@ -13,15 +13,18 @@ namespace Chill\BudgetBundle\Form;
|
|||||||
|
|
||||||
use Chill\BudgetBundle\Config\ConfigRepository;
|
use Chill\BudgetBundle\Config\ConfigRepository;
|
||||||
use Chill\BudgetBundle\Entity\Charge;
|
use Chill\BudgetBundle\Entity\Charge;
|
||||||
|
use Chill\BudgetBundle\Entity\ChargeKind;
|
||||||
|
use Chill\BudgetBundle\Repository\ChargeKindRepository;
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
use function array_flip;
|
use function array_flip;
|
||||||
use function asort;
|
use function asort;
|
||||||
|
|
||||||
@@ -31,21 +34,35 @@ class ChargeType extends AbstractType
|
|||||||
|
|
||||||
protected TranslatableStringHelperInterface $translatableStringHelper;
|
protected TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
private ChargeKindRepository $repository;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ConfigRepository $configRepository,
|
ConfigRepository $configRepository,
|
||||||
TranslatableStringHelperInterface $translatableStringHelper
|
TranslatableStringHelperInterface $translatableStringHelper,
|
||||||
|
ChargeKindRepository $repository,
|
||||||
|
TranslatorInterface $translator
|
||||||
) {
|
) {
|
||||||
$this->configRepository = $configRepository;
|
$this->configRepository = $configRepository;
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->translator = $translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('type', ChoiceType::class, [
|
->add('charge', EntityType::class, [
|
||||||
'choices' => $this->getTypes(),
|
'class' => ChargeKind::class,
|
||||||
'placeholder' => 'Choose a charge type',
|
'choices' => $this->repository->findAllActive(),
|
||||||
'attr' => ['class' => ' select2 '],
|
'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());
|
||||||
|
},
|
||||||
|
'attr' => ['class' => 'select2'],
|
||||||
])
|
])
|
||||||
->add('amount', MoneyType::class)
|
->add('amount', MoneyType::class)
|
||||||
->add('comment', TextareaType::class, [
|
->add('comment', TextareaType::class, [
|
||||||
|
@@ -13,15 +13,17 @@ namespace Chill\BudgetBundle\Form;
|
|||||||
|
|
||||||
use Chill\BudgetBundle\Config\ConfigRepository;
|
use Chill\BudgetBundle\Config\ConfigRepository;
|
||||||
use Chill\BudgetBundle\Entity\Resource;
|
use Chill\BudgetBundle\Entity\Resource;
|
||||||
|
use Chill\BudgetBundle\Entity\ResourceKind;
|
||||||
|
use Chill\BudgetBundle\Repository\ResourceKindRepository;
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
use function array_flip;
|
use function array_flip;
|
||||||
|
|
||||||
class ResourceType extends AbstractType
|
class ResourceType extends AbstractType
|
||||||
@@ -30,22 +32,35 @@ class ResourceType extends AbstractType
|
|||||||
|
|
||||||
protected TranslatableStringHelperInterface $translatableStringHelper;
|
protected TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
private ResourceKindRepository $repository;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ConfigRepository $configRepository,
|
ConfigRepository $configRepository,
|
||||||
TranslatableStringHelperInterface $translatableStringHelper
|
TranslatableStringHelperInterface $translatableStringHelper,
|
||||||
|
ResourceKindRepository $repository,
|
||||||
|
TranslatorInterface $translator
|
||||||
) {
|
) {
|
||||||
$this->configRepository = $configRepository;
|
$this->configRepository = $configRepository;
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->translator = $translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('type', ChoiceType::class, [
|
->add('resource', EntityType::class, [
|
||||||
'choices' => $this->getTypes(),
|
'class' => ResourceKind::class,
|
||||||
'placeholder' => 'Choose a resource type',
|
'choices' => $this->repository->findAllActive(),
|
||||||
'label' => 'Resource element type',
|
'label' => 'Resource type',
|
||||||
'attr' => ['class' => ' select2 '],
|
'required' => true,
|
||||||
|
'placeholder' => $this->translator->trans('admin.form.Choose the type of resource'),
|
||||||
|
'choice_label' => function (ResourceKind $resource) {
|
||||||
|
return $this->translatableStringHelper->localize($resource->getName());
|
||||||
|
},
|
||||||
|
'attr' => ['class' => 'select2'],
|
||||||
])
|
])
|
||||||
->add('amount', MoneyType::class)
|
->add('amount', MoneyType::class)
|
||||||
->add('comment', TextareaType::class, [
|
->add('comment', TextareaType::class, [
|
||||||
|
62
src/Bundle/ChillBudgetBundle/Menu/AdminMenuBuilder.php
Normal file
62
src/Bundle/ChillBudgetBundle/Menu/AdminMenuBuilder.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\BudgetBundle\Menu;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
|
use Knp\Menu\MenuItem;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
final class AdminMenuBuilder implements LocalMenuBuilderInterface
|
||||||
|
{
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
public function __construct(Security $security)
|
||||||
|
{
|
||||||
|
$this->security = $security;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
|
{
|
||||||
|
// all the entries below must have ROLE_ADMIN permissions
|
||||||
|
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu->addChild('Budget', [
|
||||||
|
'route' => 'chill_admin_budget',
|
||||||
|
])
|
||||||
|
->setAttribute('class', 'list-group-item-header')
|
||||||
|
->setExtras([
|
||||||
|
'order' => 7050,
|
||||||
|
'explain' => 'Budget resource and charge type configuration',
|
||||||
|
]);
|
||||||
|
$menu
|
||||||
|
->addChild('admin.menu.Resource types', [
|
||||||
|
'route' => 'chill_crud_resource_kind_index',
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 7060,
|
||||||
|
]);
|
||||||
|
$menu
|
||||||
|
->addChild('admin.menu.Charge types', [
|
||||||
|
'route' => 'chill_crud_charge_kind_index',
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 7070,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getMenuIds(): array
|
||||||
|
{
|
||||||
|
return ['admin_section', 'admin_budget'];
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\BudgetBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\BudgetBundle\Entity\ChargeKind;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
|
class ChargeKindRepository implements ObjectRepository
|
||||||
|
{
|
||||||
|
private EntityRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
$this->repository = $entityManager->getRepository(ChargeKind::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id): ?ChargeKind
|
||||||
|
{
|
||||||
|
return $this->repository->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ChargeType[]
|
||||||
|
*/
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
return $this->repository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ChargeType[]
|
||||||
|
*/
|
||||||
|
public function findAllActive(): array
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('c');
|
||||||
|
|
||||||
|
return $qb
|
||||||
|
->select('c')
|
||||||
|
->where($qb->expr()->eq('c.isActive', 'true'))
|
||||||
|
->orderBy('c.ordering', 'ASC')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ChargeType[]
|
||||||
|
*/
|
||||||
|
public function findAllByType(string $type): array
|
||||||
|
{
|
||||||
|
return $this->findBy(['elementType' => $type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed|null $limit
|
||||||
|
* @param mixed|null $offset
|
||||||
|
*
|
||||||
|
* @return ChargeType[]
|
||||||
|
*/
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||||
|
{
|
||||||
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria): ?ChargeKind
|
||||||
|
{
|
||||||
|
return $this->repository->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName(): string
|
||||||
|
{
|
||||||
|
return ChargeKind::class;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\BudgetBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\BudgetBundle\Entity\ResourceKind;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
|
class ResourceKindRepository implements ObjectRepository
|
||||||
|
{
|
||||||
|
private EntityRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
$this->repository = $entityManager->getRepository(ResourceKind::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id): ?ResourceKind
|
||||||
|
{
|
||||||
|
return $this->repository->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ResourceType[]
|
||||||
|
*/
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
return $this->repository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ResourceType[]
|
||||||
|
*/
|
||||||
|
public function findAllActive(): array
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('r');
|
||||||
|
|
||||||
|
return $qb
|
||||||
|
->select('r')
|
||||||
|
->where($qb->expr()->eq('r.isActive', 'true'))
|
||||||
|
->orderBy('r.ordering', 'ASC')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ResourceType[]
|
||||||
|
*/
|
||||||
|
public function findAllByType(string $type): array
|
||||||
|
{
|
||||||
|
return $this->findBy(['elementType' => $type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed|null $limit
|
||||||
|
* @param mixed|null $offset
|
||||||
|
*
|
||||||
|
* @return ResourceType[]
|
||||||
|
*/
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||||
|
{
|
||||||
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria): ?ResourceKind
|
||||||
|
{
|
||||||
|
return $this->repository->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName(): string
|
||||||
|
{
|
||||||
|
return ResourceKind::class;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
|
||||||
|
{% block content_form_actions_view %}{% endblock %}
|
||||||
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
|
{% endembed %}
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,49 @@
|
|||||||
|
{% extends '@ChillMain/Admin/layoutWithVerticalMenu.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'admin.title.Charge Type List'|trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
|
||||||
|
<h1>{{ 'admin.title.Charge Type List'|trans }}</h1>
|
||||||
|
|
||||||
|
<table class="records_list table table-bordered border-dark">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'Ordering'|trans }}</th>
|
||||||
|
<th>{{ 'Name'|trans }}</th>
|
||||||
|
<th>{{ 'Active'|trans }}</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for entity in entities %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ entity.ordering }}</td>
|
||||||
|
<td>{{ entity|chill_entity_render_box }}</td>
|
||||||
|
<td style="text-align:center;">
|
||||||
|
{%- if entity.isActive -%}
|
||||||
|
<i class="fa fa-check-square-o"></i>
|
||||||
|
{%- else -%}
|
||||||
|
<i class="fa fa-square-o"></i>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_crud_charge_kind_edit', { 'id': entity.id }) }}" class="btn btn-edit" title="{{ 'edit'|trans }}"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_crud_charge_kind_new') }}" class="btn btn-create">
|
||||||
|
{{ 'admin.new.Create a new charge type'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,11 @@
|
|||||||
|
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
|
||||||
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
|
{% endembed %}
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
|
||||||
|
{% block content_form_actions_view %}{% endblock %}
|
||||||
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
|
{% endembed %}
|
||||||
|
{% endblock %}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user