mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-13 05:44:24 +00:00
Merge branch 'feature/change-parcours-status' into 'master'
Feature/change parcours status See merge request Chill-Projet/chill-bundles!527
This commit is contained in:
commit
addbdacee8
@ -34,6 +34,7 @@
|
|||||||
"sensio/framework-extra-bundle": "^5.5",
|
"sensio/framework-extra-bundle": "^5.5",
|
||||||
"spomky-labs/base64url": "^2.0",
|
"spomky-labs/base64url": "^2.0",
|
||||||
"symfony/browser-kit": "^4.4",
|
"symfony/browser-kit": "^4.4",
|
||||||
|
"symfony/clock": "^6.2",
|
||||||
"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",
|
||||||
|
203
docs/source/development/entity-info.rst
Normal file
203
docs/source/development/entity-info.rst
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
|
||||||
|
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
||||||
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
|
under the terms of the GNU Free Documentation License, Version 1.3
|
||||||
|
or any later version published by the Free Software Foundation;
|
||||||
|
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||||
|
A copy of the license is included in the section entitled "GNU
|
||||||
|
Free Documentation License".
|
||||||
|
|
||||||
|
.. _entity-info:
|
||||||
|
|
||||||
|
Stats about event on entity in php world
|
||||||
|
########################################
|
||||||
|
|
||||||
|
It is necessary to be able to gather information about events for some entities:
|
||||||
|
|
||||||
|
- when the event has been done;
|
||||||
|
- who did it;
|
||||||
|
- ...
|
||||||
|
|
||||||
|
Those "infos" are not linked with right management, like describe in :ref:`timelines`.
|
||||||
|
|
||||||
|
|
||||||
|
“infos” for some stats and info about an entity
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
Building an info means:
|
||||||
|
|
||||||
|
- create an Entity, and map this entity to a SQL view (not a regular table);
|
||||||
|
- use the framework to build this entity dynamically.
|
||||||
|
|
||||||
|
A framework api is built to be able to build multiple “infos” entities
|
||||||
|
through “union” views:
|
||||||
|
|
||||||
|
- use a command ``bin/console chill:db:sync-views`` to synchronize view (create view if it does not exists, or update
|
||||||
|
views when new SQL parts are added in the UNION query. Internally, this command call a new ``ViewEntityInfoManager``,
|
||||||
|
which iterate over available views to build the SQL;
|
||||||
|
- one can create a new “view entity info” by implementing a
|
||||||
|
``ViewEntityInfoProviderInterface``
|
||||||
|
- this implementation of the interface is free to create another
|
||||||
|
interface for building each part of the UNION query. This interface
|
||||||
|
is created for AccompanyingPeriodInfo:
|
||||||
|
``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``
|
||||||
|
|
||||||
|
So, converting new “events” into rows for ``AccompanyingPeriodInfo`` is
|
||||||
|
just implementing this interface!
|
||||||
|
|
||||||
|
Implementation for AccompanyingPeriod (``AccompanyingPeriod/AccompanyingPeriodInfo``)
|
||||||
|
-------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
A class is created for computing some statistical info for an
|
||||||
|
AccompanyingPeriod: ``AccompanyingPeriod/AccompanyingPeriodInfo``. This
|
||||||
|
contains information about “something happens”, who did it and when.
|
||||||
|
|
||||||
|
Having those info in table answer some questions like:
|
||||||
|
|
||||||
|
- when is the last and the first action (AccompanyingPeriodWork,
|
||||||
|
Activity, AccompanyingPeriodWorkEvaluation, …) on the period;
|
||||||
|
- who is “acting” on the period, and when is the last “action” for each
|
||||||
|
user.
|
||||||
|
|
||||||
|
The AccompanyingPeriod info is mapped to a SQL view, not a table. The
|
||||||
|
sql view is built dynamically (see below), and gather infos from
|
||||||
|
ActivityBundle, PersonBundle, CalendarBundle, … It is possible to create
|
||||||
|
custom bundle and add info on this view.
|
||||||
|
|
||||||
|
.. code:: php
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table(name="view_chill_person_accompanying_period_info") <==== THIS IS A VIEW, NOT A TABLE
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodInfo
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
Why do we need this ?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For multiple jobs in PHP world:
|
||||||
|
|
||||||
|
- moving the accompanying period to another steps when inactive,
|
||||||
|
automatically;
|
||||||
|
- listing all the users which are intervening on the action on a new
|
||||||
|
“Liste des intervenants” page;
|
||||||
|
- filtering on exports
|
||||||
|
|
||||||
|
Later, we will launch automatic anonymise for accompanying period and
|
||||||
|
all related entities through this information.
|
||||||
|
|
||||||
|
How is built the SQL views which is mapped to “info” entities ?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The AccompanyingPeriodInfo entity is mapped by a SQL view (not a regular
|
||||||
|
table).
|
||||||
|
|
||||||
|
The sql view is built dynamically, it is a SQL view like this, for now (April 2023):
|
||||||
|
|
||||||
|
.. code:: sql
|
||||||
|
|
||||||
|
create view view_chill_person_accompanying_period_info
|
||||||
|
(accompanyingperiod_id, relatedentity, relatedentityid, user_id, infodate, discriminator, metadata) as
|
||||||
|
SELECT w.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||||
|
w.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
w.enddate AS infodate,
|
||||||
|
'accompanying_period_work_end'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE w.enddate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
e.updatedby_id AS user_id,
|
||||||
|
e.updatedat AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_updated_at'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
WHERE e.updatedat IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.maxdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE e.maxdate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.startdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument'::text AS relatedentity,
|
||||||
|
doc.id AS relatedentityid,
|
||||||
|
doc.updatedby_id AS user_id,
|
||||||
|
doc.updatedat AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_document_updated_at'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation_document doc
|
||||||
|
JOIN chill_person_accompanying_period_work_evaluation e ON doc.accompanyingperiodworkevaluation_id = e.id
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
WHERE doc.updatedat IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.maxdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_max'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE e.maxdate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT w.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||||
|
w.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
w.startdate AS infodate,
|
||||||
|
'accompanying_period_work_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
UNION
|
||||||
|
SELECT activity.accompanyingperiod_id,
|
||||||
|
'Chill\ActivityBundle\Entity\Activity'::text AS relatedentity,
|
||||||
|
activity.id AS relatedentityid,
|
||||||
|
au.user_id,
|
||||||
|
activity.date AS infodate,
|
||||||
|
'activity_date'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM activity
|
||||||
|
LEFT JOIN activity_user au ON activity.id = au.activity_id
|
||||||
|
WHERE activity.accompanyingperiod_id IS NOT NULL;
|
||||||
|
|
||||||
|
As you can see, the view gather multiple SELECT queries and bind them
|
||||||
|
with UNION.
|
||||||
|
|
||||||
|
Each SELECT query is built dynamically, through a class implementing an
|
||||||
|
interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``, `like
|
||||||
|
here <https://gitlab.com/Chill-Projet/chill-bundles/-/blob/master/src/Bundle/ChillPersonBundle/Service/EntityInfo/AccompanyingPeriodInfoQueryPart/AccompanyingPeriodWorkEndQueryPartForAccompanyingPeriodInfo.php>`__
|
||||||
|
|
||||||
|
To add new `SELECT` query in different `UNION` parts in the sql view, create a
|
||||||
|
service and implements this interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``.
|
@ -35,6 +35,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
|
|||||||
manual/index.rst
|
manual/index.rst
|
||||||
Assets <assets.rst>
|
Assets <assets.rst>
|
||||||
Cron Jobs <cronjob.rst>
|
Cron Jobs <cronjob.rst>
|
||||||
|
Info about entities <entity-info.rst>
|
||||||
|
|
||||||
Layout and UI
|
Layout and UI
|
||||||
**************
|
**************
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
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".
|
||||||
|
|
||||||
|
.. _timelines:
|
||||||
|
|
||||||
Timelines
|
Timelines
|
||||||
*********
|
*********
|
||||||
|
|
||||||
|
@ -151,6 +151,7 @@ This script will :
|
|||||||
|
|
||||||
# mount into to container
|
# mount into to container
|
||||||
./docker-php.sh
|
./docker-php.sh
|
||||||
|
bin/console chill:db:sync-views
|
||||||
# and load fixtures
|
# and load fixtures
|
||||||
bin/console doctrine:migrations:migrate
|
bin/console doctrine:migrations:migrate
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
|
|||||||
|
|
||||||
# mount into to container
|
# mount into to container
|
||||||
./docker-php.sh
|
./docker-php.sh
|
||||||
# and load fixtures
|
# and load fixtures (do not this for production)
|
||||||
bin/console doctrine:fixtures:load --purge-with-truncate
|
bin/console doctrine:fixtures:load --purge-with-truncate
|
||||||
|
|
||||||
There are several users available:
|
There are several users available:
|
||||||
@ -204,8 +205,10 @@ How to create the database schema (= run migrations) ?
|
|||||||
# if a container is running
|
# if a container is running
|
||||||
./docker-php.sh
|
./docker-php.sh
|
||||||
bin/console doctrine:migrations:migrate
|
bin/console doctrine:migrations:migrate
|
||||||
|
bin/console chill:db:sync-views
|
||||||
# if not
|
# if not
|
||||||
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
|
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
|
||||||
|
docker-compose run --user $(id -u) php bin/console chill:db:sync-views
|
||||||
|
|
||||||
|
|
||||||
How to read the email sent by the program ?
|
How to read the email sent by the program ?
|
||||||
@ -236,6 +239,23 @@ How to open a terminal in the project
|
|||||||
# if not
|
# if not
|
||||||
docker-compose run --user $(id -u) php /bin/bash
|
docker-compose run --user $(id -u) php /bin/bash
|
||||||
|
|
||||||
|
How to run cron-jobs ?
|
||||||
|
======================
|
||||||
|
|
||||||
|
Some command must be executed in :ref:`cron jobs <cronjob>`. To execute them:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# if a container is running
|
||||||
|
./docker-php.sh
|
||||||
|
bin/console chill:cron-job:execute
|
||||||
|
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||||
|
bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||||
|
# if not
|
||||||
|
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute
|
||||||
|
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||||
|
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||||
|
|
||||||
How to run composer ?
|
How to run composer ?
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
@ -38,6 +38,14 @@ This should be adapted to your needs:
|
|||||||
|
|
||||||
* Think about how you will backup your database. Some adminsys find easier to store database outside of docker, which might be easier to administrate or replicate.
|
* Think about how you will backup your database. Some adminsys find easier to store database outside of docker, which might be easier to administrate or replicate.
|
||||||
|
|
||||||
|
Run migrations on each update
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Every time you start a new version, you should apply update the sql schema:
|
||||||
|
|
||||||
|
- running ``bin/console doctrine:migration:migrate`` to run sql migration;
|
||||||
|
- synchonizing sql views to the last state: ``bin/console chill:db:sync-views``
|
||||||
|
|
||||||
Cron jobs
|
Cron jobs
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class ActivityUsersDateQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'activity.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return Activity::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'activity.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'au.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'activity.date';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'activity_date';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return '\'{}\'::jsonb';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'activity
|
||||||
|
LEFT JOIN activity_user au on activity.id = au.activity_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'activity.accompanyingperiod_id IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ services:
|
|||||||
resource: '../Validator/Constraints/'
|
resource: '../Validator/Constraints/'
|
||||||
|
|
||||||
Chill\ActivityBundle\Service\DocGenerator\:
|
Chill\ActivityBundle\Service\DocGenerator\:
|
||||||
autowire: true
|
|
||||||
autoconfigure: true
|
|
||||||
resource: '../Service/DocGenerator/'
|
resource: '../Service/DocGenerator/'
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Service\EntityInfo\:
|
||||||
|
resource: '../Service/EntityInfo/'
|
||||||
|
@ -30,6 +30,7 @@ use Chill\MainBundle\Search\SearchApiInterface;
|
|||||||
use Chill\MainBundle\Security\ProvideRoleInterface;
|
use Chill\MainBundle\Security\ProvideRoleInterface;
|
||||||
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
|
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
|
||||||
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
|
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
|
||||||
|
use Chill\MainBundle\Service\EntityInfo\ViewEntityInfoProviderInterface;
|
||||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
||||||
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
|
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
|
||||||
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
|
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
|
||||||
@ -62,6 +63,8 @@ class ChillMainBundle extends Bundle
|
|||||||
->addTag('chill_main.workflow_handler');
|
->addTag('chill_main.workflow_handler');
|
||||||
$container->registerForAutoconfiguration(CronJobInterface::class)
|
$container->registerForAutoconfiguration(CronJobInterface::class)
|
||||||
->addTag('chill_main.cron_job');
|
->addTag('chill_main.cron_job');
|
||||||
|
$container->registerForAutoconfiguration(ViewEntityInfoProviderInterface::class)
|
||||||
|
->addTag('chill_main.entity_info_provider');
|
||||||
|
|
||||||
$container->addCompilerPass(new SearchableServicesCompilerPass());
|
$container->addCompilerPass(new SearchableServicesCompilerPass());
|
||||||
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
|
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Command;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Service\EntityInfo\ViewEntityInfoManager;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class SynchronizeEntityInfoViewsCommand extends Command
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private ViewEntityInfoManager $viewEntityInfoManager,
|
||||||
|
) {
|
||||||
|
parent::__construct('chill:db:sync-views');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setDescription('Update or create sql views which provide info for various entities');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$this->viewEntityInfoManager->synchronizeOnDB();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -41,12 +41,12 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
|
|||||||
{
|
{
|
||||||
$object = $args->getObject();
|
$object = $args->getObject();
|
||||||
|
|
||||||
if (
|
if ($object instanceof TrackCreationInterface) {
|
||||||
$object instanceof TrackCreationInterface
|
|
||||||
&& $this->security->getUser() instanceof User
|
|
||||||
) {
|
|
||||||
$object->setCreatedBy($this->security->getUser());
|
|
||||||
$object->setCreatedAt(new DateTimeImmutable('now'));
|
$object->setCreatedAt(new DateTimeImmutable('now'));
|
||||||
|
|
||||||
|
if ($this->security->getUser() instanceof User) {
|
||||||
|
$object->setCreatedBy($this->security->getUser());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->onUpdate($object);
|
$this->onUpdate($object);
|
||||||
@ -61,12 +61,12 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
|
|||||||
|
|
||||||
protected function onUpdate(object $object): void
|
protected function onUpdate(object $object): void
|
||||||
{
|
{
|
||||||
if (
|
if ($object instanceof TrackUpdateInterface) {
|
||||||
$object instanceof TrackUpdateInterface
|
|
||||||
&& $this->security->getUser() instanceof User
|
|
||||||
) {
|
|
||||||
$object->setUpdatedBy($this->security->getUser());
|
|
||||||
$object->setUpdatedAt(new DateTimeImmutable('now'));
|
$object->setUpdatedAt(new DateTimeImmutable('now'));
|
||||||
|
|
||||||
|
if ($this->security->getUser() instanceof User) {
|
||||||
|
$object->setUpdatedBy($this->security->getUser());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Service\EntityInfo;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Connection;
|
||||||
|
|
||||||
|
class ViewEntityInfoManager
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
/**
|
||||||
|
* @var ViewEntityInfoProviderInterface[]
|
||||||
|
*/
|
||||||
|
private iterable $vienEntityInfoProviders,
|
||||||
|
private Connection $connection,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function synchronizeOnDB(): void
|
||||||
|
{
|
||||||
|
$this->connection->transactional(function (Connection $conn): void {
|
||||||
|
foreach ($this->vienEntityInfoProviders as $viewProvider) {
|
||||||
|
foreach ($this->createOrReplaceViewSQL($viewProvider, $viewProvider->getViewName()) as $sql) {
|
||||||
|
$conn->executeQuery($sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string>
|
||||||
|
*/
|
||||||
|
private function createOrReplaceViewSQL(ViewEntityInfoProviderInterface $viewProvider, string $viewName): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"DROP VIEW IF EXISTS {$viewName}",
|
||||||
|
sprintf("CREATE VIEW {$viewName} AS %s", $viewProvider->getViewQuery())
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Service\EntityInfo;
|
||||||
|
|
||||||
|
interface ViewEntityInfoProviderInterface
|
||||||
|
{
|
||||||
|
public function getViewQuery(): string;
|
||||||
|
|
||||||
|
public function getViewName(): string;
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
parameters:
|
parameters:
|
||||||
# cl_chill_main.example.class: Chill\MainBundle\Example
|
# cl_chill_main.example.class: Chill\MainBundle\Example
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- ./services/clock.yaml
|
||||||
|
|
||||||
services:
|
services:
|
||||||
_defaults:
|
_defaults:
|
||||||
autowire: true
|
autowire: true
|
||||||
@ -118,3 +121,7 @@ services:
|
|||||||
lazy: true
|
lazy: true
|
||||||
arguments:
|
arguments:
|
||||||
$jobs: !tagged_iterator chill_main.cron_job
|
$jobs: !tagged_iterator chill_main.cron_job
|
||||||
|
|
||||||
|
Chill\MainBundle\Service\EntityInfo\ViewEntityInfoManager:
|
||||||
|
arguments:
|
||||||
|
$vienEntityInfoProviders: !tagged_iterator chill_main.entity_info_provider
|
||||||
|
4
src/Bundle/ChillMainBundle/config/services/clock.yaml
Normal file
4
src/Bundle/ChillMainBundle/config/services/clock.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# temporary, waiting for symfony 6.0 to load clock
|
||||||
|
services:
|
||||||
|
Symfony\Component\Clock\NativeClock: ~
|
||||||
|
Symfony\Component\Clock\ClockInterface: '@Symfony\Component\Clock\NativeClock'
|
@ -67,3 +67,7 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
tags:
|
tags:
|
||||||
- {name: console.command }
|
- {name: console.command }
|
||||||
|
|
||||||
|
Chill\MainBundle\Command\SynchronizeEntityInfoViewsCommand:
|
||||||
|
tags:
|
||||||
|
- {name: console.command}
|
||||||
|
@ -564,6 +564,7 @@ export:
|
|||||||
_as_string: Adresse formattée
|
_as_string: Adresse formattée
|
||||||
confidential: Adresse confidentielle ?
|
confidential: Adresse confidentielle ?
|
||||||
isNoAddress: Adresse incomplète ?
|
isNoAddress: Adresse incomplète ?
|
||||||
|
steps: Escaliers
|
||||||
_lat: Latitude
|
_lat: Latitude
|
||||||
_lon: Longitude
|
_lon: Longitude
|
||||||
|
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\AccompanyingPeriod\Lifecycle;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Cron\CronJobInterface;
|
||||||
|
use Chill\MainBundle\Entity\CronJobExecution;
|
||||||
|
use Symfony\Component\Clock\ClockInterface;
|
||||||
|
|
||||||
|
readonly class AccompanyingPeriodStepChangeCronjob implements CronJobInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private ClockInterface $clock,
|
||||||
|
private AccompanyingPeriodStepChangeRequestor $requestor,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canRun(?CronJobExecution $cronJobExecution): bool
|
||||||
|
{
|
||||||
|
$now = $this->clock->now();
|
||||||
|
|
||||||
|
if ($now->sub(new \DateInterval('P1D')) < $cronJobExecution->getLastStart()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array((int) $now->format('H'), [1, 2, 3, 4, 5, 6], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey(): string
|
||||||
|
{
|
||||||
|
return 'accompanying-period-step-change';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
($this->requestor)();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\AccompanyingPeriod\Lifecycle;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
|
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||||
|
|
||||||
|
#[AsMessageHandler]
|
||||||
|
class AccompanyingPeriodStepChangeMessageHandler implements MessageHandlerInterface
|
||||||
|
{
|
||||||
|
private const LOG_PREFIX = '[accompanying period step change message handler] ';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||||
|
private AccompanyingPeriodStepChanger $changer,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(AccompanyingPeriodStepChangeRequestMessage $message): void
|
||||||
|
{
|
||||||
|
if (null === $period = $this->accompanyingPeriodRepository->find($message->getPeriodId())) {
|
||||||
|
throw new \RuntimeException(self::LOG_PREFIX . 'Could not find period with this id: '. $message->getPeriodId());
|
||||||
|
}
|
||||||
|
|
||||||
|
($this->changer)($period, $message->getTransition());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\AccompanyingPeriod\Lifecycle;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message which will request a change in the step of accompanying period
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodStepChangeRequestMessage
|
||||||
|
{
|
||||||
|
private int $periodId;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
AccompanyingPeriod|int $period,
|
||||||
|
private string $transition,
|
||||||
|
) {
|
||||||
|
if (is_int($period)) {
|
||||||
|
$this->periodId = $period;
|
||||||
|
} else {
|
||||||
|
if (null !== $id = $period->getId()) {
|
||||||
|
$this->periodId = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException("This AccompanyingPeriod does not have and id yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPeriodId(): int
|
||||||
|
{
|
||||||
|
return $this->periodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTransition(): string
|
||||||
|
{
|
||||||
|
return $this->transition;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\AccompanyingPeriod\Lifecycle;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodInfoRepositoryInterface;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather all the accompanying period which needs a change in step
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodStepChangeRequestor
|
||||||
|
{
|
||||||
|
private \DateInterval $intervalForShortInactive;
|
||||||
|
|
||||||
|
private \DateInterval $intervalForLongInactive;
|
||||||
|
|
||||||
|
private bool $isMarkInactive;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private AccompanyingPeriodInfoRepositoryInterface $accompanyingPeriodInfoRepository,
|
||||||
|
private LoggerInterface $logger,
|
||||||
|
private MessageBusInterface $messageBus,
|
||||||
|
ParameterBagInterface $parameterBag,
|
||||||
|
) {
|
||||||
|
$config = $parameterBag->get('chill_person')['accompanying_period_lifecycle_delays'];
|
||||||
|
$this->isMarkInactive = $config['mark_inactive'];
|
||||||
|
$this->intervalForShortInactive = new \DateInterval($config['mark_inactive_short_after']);
|
||||||
|
$this->intervalForLongInactive = new \DateInterval($config['mark_inactive_long_after']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(): void
|
||||||
|
{
|
||||||
|
if (!$this->isMarkInactive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the oldest ones first
|
||||||
|
foreach (
|
||||||
|
$olders = $this->accompanyingPeriodInfoRepository->findAccompanyingPeriodIdInactiveAfter(
|
||||||
|
$this->intervalForLongInactive,
|
||||||
|
[AccompanyingPeriod::STEP_CONFIRMED, AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT]
|
||||||
|
) as $accompanyingPeriodId
|
||||||
|
) {
|
||||||
|
$this->logger->debug('request mark period as inactive_short', ['period' => $accompanyingPeriodId]);
|
||||||
|
$this->messageBus->dispatch(new AccompanyingPeriodStepChangeRequestMessage($accompanyingPeriodId, 'mark_inactive_long'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// the newest
|
||||||
|
foreach (
|
||||||
|
$this->accompanyingPeriodInfoRepository->findAccompanyingPeriodIdInactiveAfter(
|
||||||
|
$this->intervalForShortInactive,
|
||||||
|
[AccompanyingPeriod::STEP_CONFIRMED]
|
||||||
|
) as $accompanyingPeriodId
|
||||||
|
) {
|
||||||
|
if (in_array($accompanyingPeriodId, $olders, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->debug('request mark period as inactive_long', ['period' => $accompanyingPeriodId]);
|
||||||
|
$this->messageBus->dispatch(new AccompanyingPeriodStepChangeRequestMessage($accompanyingPeriodId, 'mark_inactive_short'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// a new event has been created => remove inactive long, or short
|
||||||
|
foreach (
|
||||||
|
$this->accompanyingPeriodInfoRepository->findAccompanyingPeriodIdActiveSince(
|
||||||
|
$this->intervalForShortInactive,
|
||||||
|
[AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT, AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG]
|
||||||
|
) as $accompanyingPeriodId
|
||||||
|
) {
|
||||||
|
$this->logger->debug('request mark period as active', ['period' => $accompanyingPeriodId]);
|
||||||
|
$this->messageBus->dispatch(new AccompanyingPeriodStepChangeRequestMessage($accompanyingPeriodId, 'mark_active'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\AccompanyingPeriod\Lifecycle;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Workflow\Registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the step of an accompanying period
|
||||||
|
*
|
||||||
|
* This should be invoked through scripts (not in the in context of an http request, or an
|
||||||
|
* action from a user).
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodStepChanger
|
||||||
|
{
|
||||||
|
private const LOG_PREFIX = '[AccompanyingPeriodStepChanger] ';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private EntityManagerInterface $entityManager,
|
||||||
|
private LoggerInterface $logger,
|
||||||
|
private Registry $workflowRegistry,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(AccompanyingPeriod $period, string $transition, ?string $workflowName = null): void
|
||||||
|
{
|
||||||
|
$workflow = $this->workflowRegistry->get($period, $workflowName);
|
||||||
|
|
||||||
|
if (!$workflow->can($period, $transition)) {
|
||||||
|
$this->logger->info(self::LOG_PREFIX . 'not able to apply the transition on period', [
|
||||||
|
'period_id' => $period->getId(),
|
||||||
|
'transition' => $transition
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$workflow->apply($period, $transition);
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->logger->info(self::LOG_PREFIX . 'could apply a transition', [
|
||||||
|
'period_id' => $period->getId(),
|
||||||
|
'transition' => $transition
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\PersonBundle;
|
namespace Chill\PersonBundle;
|
||||||
|
|
||||||
use Chill\PersonBundle\DependencyInjection\CompilerPass\AccompanyingPeriodTimelineCompilerPass;
|
use Chill\PersonBundle\DependencyInjection\CompilerPass\AccompanyingPeriodTimelineCompilerPass;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
use Chill\PersonBundle\Widget\PersonListWidgetFactory;
|
use Chill\PersonBundle\Widget\PersonListWidgetFactory;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
@ -26,5 +27,7 @@ class ChillPersonBundle extends Bundle
|
|||||||
->addWidgetFactory(new PersonListWidgetFactory());
|
->addWidgetFactory(new PersonListWidgetFactory());
|
||||||
|
|
||||||
$container->addCompilerPass(new AccompanyingPeriodTimelineCompilerPass());
|
$container->addCompilerPass(new AccompanyingPeriodTimelineCompilerPass());
|
||||||
|
$container->registerForAutoconfiguration(AccompanyingPeriodInfoUnionQueryPartInterface::class)
|
||||||
|
->addTag('chill_person.accompanying_period_info_part');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use Chill\MainBundle\DependencyInjection\MissingBundleException;
|
|||||||
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
||||||
use Chill\PersonBundle\Controller\HouseholdCompositionTypeApiController;
|
use Chill\PersonBundle\Controller\HouseholdCompositionTypeApiController;
|
||||||
use Chill\PersonBundle\Doctrine\DQL\AddressPart;
|
use Chill\PersonBundle\Doctrine\DQL\AddressPart;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter;
|
||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter;
|
||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
@ -1010,18 +1011,42 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
],
|
],
|
||||||
'initial_marking' => 'DRAFT',
|
'initial_marking' => 'DRAFT',
|
||||||
'places' => [
|
'places' => [
|
||||||
'DRAFT',
|
AccompanyingPeriod::STEP_DRAFT,
|
||||||
'CONFIRMED',
|
AccompanyingPeriod::STEP_CONFIRMED,
|
||||||
'CLOSED',
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||||
|
AccompanyingPeriod::STEP_CLOSED,
|
||||||
],
|
],
|
||||||
'transitions' => [
|
'transitions' => [
|
||||||
'confirm' => [
|
'confirm' => [
|
||||||
'from' => 'DRAFT',
|
'from' => AccompanyingPeriod::STEP_DRAFT,
|
||||||
'to' => 'CONFIRMED',
|
'to' => AccompanyingPeriod::STEP_CONFIRMED,
|
||||||
|
],
|
||||||
|
'mark_inactive_short' => [
|
||||||
|
'from' => AccompanyingPeriod::STEP_CONFIRMED,
|
||||||
|
'to' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||||
|
],
|
||||||
|
'mark_inactive_long' => [
|
||||||
|
'from' => [
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED,
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT
|
||||||
|
],
|
||||||
|
'to' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||||
|
],
|
||||||
|
'mark_active' => [
|
||||||
|
'from' => [
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||||
|
],
|
||||||
|
'to' => AccompanyingPeriod::STEP_CONFIRMED
|
||||||
],
|
],
|
||||||
'close' => [
|
'close' => [
|
||||||
'from' => 'CONFIRMED',
|
'from' => [
|
||||||
'to' => 'CLOSED',
|
AccompanyingPeriod::STEP_CONFIRMED,
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||||
|
],
|
||||||
|
'to' => AccompanyingPeriod::STEP_CLOSED,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -128,6 +128,15 @@ class Configuration implements ConfigurationInterface
|
|||||||
->info('Can we have more than one simultaneous accompanying period in the same time. Default false.')
|
->info('Can we have more than one simultaneous accompanying period in the same time. Default false.')
|
||||||
->defaultValue(false)
|
->defaultValue(false)
|
||||||
->end()
|
->end()
|
||||||
|
->arrayNode('accompanying_period_lifecycle_delays')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->info('Delays before marking an accompanying period as inactive')
|
||||||
|
->children()
|
||||||
|
->booleanNode('mark_inactive')->defaultTrue()->end()
|
||||||
|
->scalarNode('mark_inactive_short_after')->defaultValue('P6M')->end()
|
||||||
|
->scalarNode('mark_inactive_long_after')->defaultValue('P2Y')->end()
|
||||||
|
->end()
|
||||||
|
->end() // end of 'accompanying_period_lifecycle_delays
|
||||||
->end() // children of 'root', parent = root
|
->end() // children of 'root', parent = root
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -109,6 +109,24 @@ class AccompanyingPeriod implements
|
|||||||
*/
|
*/
|
||||||
public const STEP_CONFIRMED = 'CONFIRMED';
|
public const STEP_CONFIRMED = 'CONFIRMED';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark an accompanying period as confirmed, but inactive
|
||||||
|
*
|
||||||
|
* this means that the accompanying period **is**
|
||||||
|
* confirmed, but no activity (Activity, AccompanyingPeriod, ...)
|
||||||
|
* has been associated, or updated, within this accompanying period.
|
||||||
|
*/
|
||||||
|
public const STEP_CONFIRMED_INACTIVE_SHORT = 'CONFIRMED_INACTIVE_SHORT';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark an accompanying period as confirmed, but inactive
|
||||||
|
*
|
||||||
|
* this means that the accompanying period **is**
|
||||||
|
* confirmed, but no activity (Activity, AccompanyingPeriod, ...)
|
||||||
|
* has been associated, or updated, within this accompanying period.
|
||||||
|
*/
|
||||||
|
public const STEP_CONFIRMED_INACTIVE_LONG = 'CONFIRMED_INACTIVE_LONG';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark an accompanying period as "draft".
|
* Mark an accompanying period as "draft".
|
||||||
*
|
*
|
||||||
@ -340,6 +358,7 @@ class AccompanyingPeriod implements
|
|||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=32, nullable=true)
|
* @ORM\Column(type="string", length=32, nullable=true)
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
|
* @var AccompanyingPeriod::STEP_*
|
||||||
*/
|
*/
|
||||||
private string $step = self::STEP_DRAFT;
|
private string $step = self::STEP_DRAFT;
|
||||||
|
|
||||||
@ -712,11 +731,9 @@ class AccompanyingPeriod implements
|
|||||||
if ($this->getStep() === self::STEP_DRAFT) {
|
if ($this->getStep() === self::STEP_DRAFT) {
|
||||||
return [[self::STEP_DRAFT]];
|
return [[self::STEP_DRAFT]];
|
||||||
}
|
}
|
||||||
|
if (str_starts_with($this->getStep(), 'CONFIRM')) {
|
||||||
if ($this->getStep() === self::STEP_CONFIRMED) {
|
|
||||||
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getStep() === self::STEP_CLOSED) {
|
if ($this->getStep() === self::STEP_CLOSED) {
|
||||||
return [[self::STEP_DRAFT, self::STEP_CONFIRMED, self::STEP_CLOSED]];
|
return [[self::STEP_DRAFT, self::STEP_CONFIRMED, self::STEP_CLOSED]];
|
||||||
}
|
}
|
||||||
|
@ -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\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informations about AccompanyingPeriod
|
||||||
|
*
|
||||||
|
* This entity allow access to some basic information about the AccompanyingPeriod. It is
|
||||||
|
* populated from a SQL view, dynamically build from various sources.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* - get the user involved with an accompanying period
|
||||||
|
*
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table(name="view_chill_person_accompanying_period_info")
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodInfo
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
/**
|
||||||
|
* @var AccompanyingPeriod
|
||||||
|
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
|
||||||
|
*/
|
||||||
|
public readonly AccompanyingPeriod $accompanyingPeriod,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
* @ORM\Column(type="text")
|
||||||
|
* @ORM\Id
|
||||||
|
*/
|
||||||
|
public readonly string $relatedEntity,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
* @ORM\Id
|
||||||
|
*/
|
||||||
|
public readonly int $relatedEntityId,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var User
|
||||||
|
* @ORM\ManyToOne(targetEntity=User::class)
|
||||||
|
*/
|
||||||
|
public readonly ?User $user,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \DateTimeImmutable
|
||||||
|
* @ORM\Column(type="datetime_immutable")
|
||||||
|
*/
|
||||||
|
public readonly \DateTimeImmutable $infoDate,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
* @ORM\Column(type="json")
|
||||||
|
*/
|
||||||
|
public readonly array $metadata,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
* @ORM\Column(type="text")
|
||||||
|
*/
|
||||||
|
public readonly string $discriminator,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
@ -86,13 +86,19 @@ final class StepAggregator implements AggregatorInterface
|
|||||||
return function ($value): string {
|
return function ($value): string {
|
||||||
switch ($value) {
|
switch ($value) {
|
||||||
case AccompanyingPeriod::STEP_DRAFT:
|
case AccompanyingPeriod::STEP_DRAFT:
|
||||||
return $this->translator->trans('Draft');
|
return $this->translator->trans('course.draft');
|
||||||
|
|
||||||
case AccompanyingPeriod::STEP_CONFIRMED:
|
case AccompanyingPeriod::STEP_CONFIRMED:
|
||||||
return $this->translator->trans('Confirmed');
|
return $this->translator->trans('course.confirmed');
|
||||||
|
|
||||||
case AccompanyingPeriod::STEP_CLOSED:
|
case AccompanyingPeriod::STEP_CLOSED:
|
||||||
return $this->translator->trans('Closed');
|
return $this->translator->trans('course.closed');
|
||||||
|
|
||||||
|
case AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT:
|
||||||
|
return $this->translator->trans('course.inactive_short');
|
||||||
|
|
||||||
|
case AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG:
|
||||||
|
return $this->translator->trans('course.inactive_long');
|
||||||
|
|
||||||
case '_header':
|
case '_header':
|
||||||
return 'Step';
|
return 'Step';
|
||||||
|
@ -41,6 +41,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Doctrine\ORM\Query\Expr\Join;
|
use Doctrine\ORM\Query\Expr\Join;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
|
|
||||||
class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
||||||
@ -100,6 +101,8 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
|||||||
|
|
||||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
private UserHelper $userHelper;
|
private UserHelper $userHelper;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -113,6 +116,7 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
|||||||
SocialIssueRepository $socialIssueRepository,
|
SocialIssueRepository $socialIssueRepository,
|
||||||
SocialIssueRender $socialIssueRender,
|
SocialIssueRender $socialIssueRender,
|
||||||
TranslatableStringHelperInterface $translatableStringHelper,
|
TranslatableStringHelperInterface $translatableStringHelper,
|
||||||
|
TranslatorInterface $translator,
|
||||||
RollingDateConverterInterface $rollingDateConverter,
|
RollingDateConverterInterface $rollingDateConverter,
|
||||||
UserHelper $userHelper
|
UserHelper $userHelper
|
||||||
) {
|
) {
|
||||||
@ -126,6 +130,7 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
|||||||
$this->thirdPartyRender = $thirdPartyRender;
|
$this->thirdPartyRender = $thirdPartyRender;
|
||||||
$this->thirdPartyRepository = $thirdPartyRepository;
|
$this->thirdPartyRepository = $thirdPartyRepository;
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
$this->translator = $translator;
|
||||||
$this->rollingDateConverter = $rollingDateConverter;
|
$this->rollingDateConverter = $rollingDateConverter;
|
||||||
$this->userHelper = $userHelper;
|
$this->userHelper = $userHelper;
|
||||||
}
|
}
|
||||||
@ -250,6 +255,27 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case 'step':
|
||||||
|
return fn ($value) => match ($value) {
|
||||||
|
'_header' => 'export.list.acp.step',
|
||||||
|
null => '',
|
||||||
|
AccompanyingPeriod::STEP_DRAFT => $this->translator->trans('course.draft'),
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED => $this->translator->trans('course.confirmed'),
|
||||||
|
AccompanyingPeriod::STEP_CLOSED => $this->translator->trans('course.closed'),
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT => $this->translator->trans('course.inactive_short'),
|
||||||
|
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG => $this->translator->trans('course.inactive_long'),
|
||||||
|
default => $value,
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'intensity':
|
||||||
|
return fn ($value) => match ($value) {
|
||||||
|
'_header' => 'export.list.acp.intensity',
|
||||||
|
null => '',
|
||||||
|
AccompanyingPeriod::INTENSITY_OCCASIONAL => $this->translator->trans('occasional'),
|
||||||
|
AccompanyingPeriod::INTENSITY_REGULAR => $this->translator->trans('regular'),
|
||||||
|
default => $value,
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return static function ($value) use ($key) {
|
return static function ($value) use ($key) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\MainBundle\Form\Type\DateIntervalType;
|
||||||
|
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
||||||
|
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||||
|
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
||||||
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter accompanying course which have a row in AccompanyingPeriodInfo within the given
|
||||||
|
* interval
|
||||||
|
*/
|
||||||
|
final readonly class HavingAnAccompanyingPeriodInfoWithinDatesFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private RollingDateConverterInterface $rollingDateConverter,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('start_date', PickRollingDateType::class, [
|
||||||
|
'label' => 'export.filter.course.having_info_within_interval.start_date',
|
||||||
|
'data' => new RollingDate(RollingDate::T_TODAY),
|
||||||
|
])
|
||||||
|
->add('end_date', PickRollingDateType::class, [
|
||||||
|
'label' => 'export.filter.course.having_info_within_interval.end_date',
|
||||||
|
'data' => new RollingDate(RollingDate::T_TODAY),
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.course.having_info_within_interval.title';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAction($data, $format = 'string'): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'export.filter.course.having_info_within_interval.Only course with events between %startDate% and %endDate%',
|
||||||
|
[
|
||||||
|
'%startDate%' => $this->rollingDateConverter->convert($data['start_date'])->format('d-m-Y'),
|
||||||
|
'%endDate%' => $this->rollingDateConverter->convert($data['end_date'])->format('d-m-Y'),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data): void
|
||||||
|
{
|
||||||
|
$ai = 'having_ai_within_interval_acc_info';
|
||||||
|
$as = 'having_ai_within_interval_start_date';
|
||||||
|
$ae = 'having_ai_within_interval_end_date';
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->andWhere(
|
||||||
|
$qb->expr()->exists(
|
||||||
|
'SELECT 1 FROM ' . AccompanyingPeriodInfo::class . " {$ai} WHERE {$ai}.infoDate BETWEEN :{$as} AND :{$ae} AND IDENTITY({$ai}.accompanyingPeriod) = acp.id"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->setParameter($as, $this->rollingDateConverter->convert($data['start_date']), Types::DATETIME_IMMUTABLE)
|
||||||
|
->setParameter($ae, $this->rollingDateConverter->convert($data['end_date']), Types::DATETIME_IMMUTABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ACP_TYPE;
|
||||||
|
}
|
||||||
|
}
|
@ -32,9 +32,11 @@ class StepFilter implements FilterInterface
|
|||||||
private const P = 'acp_step_filter_date';
|
private const P = 'acp_step_filter_date';
|
||||||
|
|
||||||
private const STEPS = [
|
private const STEPS = [
|
||||||
'Draft' => AccompanyingPeriod::STEP_DRAFT,
|
'course.draft' => AccompanyingPeriod::STEP_DRAFT,
|
||||||
'Confirmed' => AccompanyingPeriod::STEP_CONFIRMED,
|
'course.confirmed' => AccompanyingPeriod::STEP_CONFIRMED,
|
||||||
'Closed' => AccompanyingPeriod::STEP_CLOSED,
|
'course.closed' => AccompanyingPeriod::STEP_CLOSED,
|
||||||
|
'course.inactive_short' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||||
|
'course.inactive_long' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||||
];
|
];
|
||||||
|
|
||||||
private RollingDateConverterInterface $rollingDateConverter;
|
private RollingDateConverterInterface $rollingDateConverter;
|
||||||
@ -96,7 +98,7 @@ class StepFilter implements FilterInterface
|
|||||||
'data' => self::DEFAULT_CHOICE,
|
'data' => self::DEFAULT_CHOICE,
|
||||||
])
|
])
|
||||||
->add('calc_date', PickRollingDateType::class, [
|
->add('calc_date', PickRollingDateType::class, [
|
||||||
'label' => 'export.acp.filter.by_step.date_calc',
|
'label' => 'export.filter.course.by_step.date_calc',
|
||||||
'data' => new RollingDate(RollingDate::T_TODAY),
|
'data' => new RollingDate(RollingDate::T_TODAY),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||||
|
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter course where a user is "working" on it
|
||||||
|
*
|
||||||
|
* Makes use of AccompanyingPeriodInfo
|
||||||
|
*/
|
||||||
|
readonly class UserWorkingOnCourseFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
private const AI_ALIAS = 'user_working_on_course_filter_acc_info';
|
||||||
|
private const AI_USERS = 'user_working_on_course_filter_users';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private UserRender $userRender,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('users', PickUserDynamicType::class, [
|
||||||
|
'multiple' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.course.by_user_working.title';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAction($data, $format = 'string'): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'export.filter.course.by_user_working.Filtered by user working on course: only %users%', [
|
||||||
|
'%users%' => implode(
|
||||||
|
', ',
|
||||||
|
array_map(
|
||||||
|
fn (User $u) => $this->userRender->renderString($u, []),
|
||||||
|
$data['users']
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data): void
|
||||||
|
{
|
||||||
|
$qb
|
||||||
|
->andWhere(
|
||||||
|
$qb->expr()->exists(
|
||||||
|
"SELECT 1 FROM " . AccompanyingPeriod\AccompanyingPeriodInfo::class . " " . self::AI_ALIAS . " " .
|
||||||
|
"WHERE " . self::AI_ALIAS . ".user IN (:" . self::AI_USERS .") AND IDENTITY(" . self::AI_ALIAS . ".accompanyingPeriod) = acp.id"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->setParameter(self::AI_USERS, $data['users'])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ACP_TYPE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
||||||
|
use DateInterval;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use LogicException;
|
||||||
|
use Symfony\Component\Clock\ClockInterface;
|
||||||
|
|
||||||
|
readonly class AccompanyingPeriodInfoRepository implements AccompanyingPeriodInfoRepositoryInterface
|
||||||
|
{
|
||||||
|
private EntityRepository $entityRepository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private ClockInterface $clock,
|
||||||
|
private EntityManagerInterface $em,
|
||||||
|
) {
|
||||||
|
$this->entityRepository = $em->getRepository($this->getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findAccompanyingPeriodIdInactiveAfter(DateInterval $interval, array $statuses = []): array
|
||||||
|
{
|
||||||
|
$query = $this->em->createQuery();
|
||||||
|
$baseDql = 'SELECT DISTINCT IDENTITY(ai.accompanyingPeriod) FROM '.AccompanyingPeriodInfo::class.' ai JOIN ai.accompanyingPeriod a WHERE NOT EXISTS
|
||||||
|
(SELECT 1 FROM ' . AccompanyingPeriodInfo::class . ' aiz WHERE aiz.infoDate > :after AND IDENTITY(aiz.accompanyingPeriod) = IDENTITY(ai.accompanyingPeriod))';
|
||||||
|
|
||||||
|
if ([] !== $statuses) {
|
||||||
|
$dql = $baseDql . ' AND a.step IN (:statuses)';
|
||||||
|
$query->setParameter('statuses', $statuses);
|
||||||
|
} else {
|
||||||
|
$dql = $baseDql;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->setDQL($dql)
|
||||||
|
->setParameter('after', $this->clock->now()->sub($interval))
|
||||||
|
->getSingleColumnResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findAccompanyingPeriodIdActiveSince(DateInterval $interval, array $statuses = []): array
|
||||||
|
{
|
||||||
|
$query = $this->em->createQuery();
|
||||||
|
$baseDql = 'SELECT DISTINCT IDENTITY(ai.accompanyingPeriod) FROM ' . AccompanyingPeriodInfo::class . ' ai
|
||||||
|
JOIN ai.accompanyingPeriod a WHERE ai.infoDate > :after';
|
||||||
|
|
||||||
|
if ([] !== $statuses) {
|
||||||
|
$dql = $baseDql . ' AND a.step IN (:statuses)';
|
||||||
|
$query->setParameter('statuses', $statuses);
|
||||||
|
} else {
|
||||||
|
$dql = $baseDql;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->setDQL($dql)
|
||||||
|
->setParameter('after', $this->clock->now()->sub($interval))
|
||||||
|
->getSingleColumnResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id): ?AccompanyingPeriodInfo
|
||||||
|
{
|
||||||
|
throw new LogicException("Calling an accompanying period info by his id does not make sense");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
return $this->entityRepository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||||
|
{
|
||||||
|
return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria): ?AccompanyingPeriodInfo
|
||||||
|
{
|
||||||
|
return $this->entityRepository->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodInfo::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodInfo;
|
||||||
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template-extends ObjectRepository<AccompanyingPeriodInfo>
|
||||||
|
*/
|
||||||
|
interface AccompanyingPeriodInfoRepositoryInterface extends ObjectRepository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return a list of id for inactive accompanying periods
|
||||||
|
*
|
||||||
|
* @param \DateInterval $interval
|
||||||
|
* @param list<AccompanyingPeriod::STEP_*> $statuses
|
||||||
|
* @return list<int>
|
||||||
|
*/
|
||||||
|
public function findAccompanyingPeriodIdInactiveAfter(\DateInterval $interval, array $statuses = []): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateInterval $interval
|
||||||
|
* @param list<AccompanyingPeriod::STEP_*> $statuses
|
||||||
|
* @return list<int>
|
||||||
|
*/
|
||||||
|
public function findAccompanyingPeriodIdActiveSince(\DateInterval $interval, array $statuses = []): array;
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
<scopes></scopes>
|
<scopes></scopes>
|
||||||
<referrer></referrer>
|
<referrer></referrer>
|
||||||
<resources></resources>
|
<resources></resources>
|
||||||
<start-date v-if="accompanyingCourse.step === 'CONFIRMED'"></start-date>
|
<start-date v-if="accompanyingCourse.step.startsWith('CONFIRMED')"></start-date>
|
||||||
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
||||||
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
|
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
|
||||||
|
|
||||||
|
@ -11,12 +11,22 @@
|
|||||||
{{ $t('course.step.draft') }}
|
{{ $t('course.step.draft') }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="accompanyingCourse.step === 'CONFIRMED'" class="text-md-end">
|
<span v-else-if="accompanyingCourse.step === 'CONFIRMED' || accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT' || accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'" class="text-md-end">
|
||||||
<span class="d-md-block mb-md-3">
|
<span v-if="accompanyingCourse.step === 'CONFIRMED'" class="d-md-block mb-md-3">
|
||||||
<span class="badge bg-primary">
|
<span class="badge bg-primary">
|
||||||
{{ $t('course.step.active') }}
|
{{ $t('course.step.active') }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
<span v-else-if="accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT'" class="d-md-block mb-md-3">
|
||||||
|
<span class="badge bg-chill-yellow text-primary">
|
||||||
|
{{ $t('course.step.inactive_short') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span v-else-if="accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'" class="d-md-block mb-md-3">
|
||||||
|
<span class="badge bg-chill-pink">
|
||||||
|
{{ $t('course.step.inactive_long') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
<span class="d-md-block">
|
<span class="d-md-block">
|
||||||
<span class="d-md-block ms-3 ms-md-0">
|
<span class="d-md-block ms-3 ms-md-0">
|
||||||
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
|
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
|
||||||
|
@ -21,7 +21,9 @@ const appMessages = {
|
|||||||
step: {
|
step: {
|
||||||
draft: "Brouillon",
|
draft: "Brouillon",
|
||||||
active: "En file active",
|
active: "En file active",
|
||||||
closed: "Cloturé"
|
closed: "Cloturé",
|
||||||
|
inactive_short: "Hors file active",
|
||||||
|
inactive_long: "Pré-archivé",
|
||||||
},
|
},
|
||||||
open_at: "ouvert le ",
|
open_at: "ouvert le ",
|
||||||
by: "par ",
|
by: "par ",
|
||||||
|
@ -52,11 +52,13 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if acp.step == 'DRAFT' %}
|
{% if acp.step == 'DRAFT' %}
|
||||||
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.draft'|trans }}">{{ 'course.draft'|trans }}</span>
|
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.draft'|trans|e('html_attr') }}">{{ 'course.draft'|trans }}</span>
|
||||||
{% endif %}
|
{% elseif acp.step == 'CLOSED' %}
|
||||||
|
<span class="badge bg-danger" style="font-size: 85%;" title="{{ 'course.closed'|trans|e('html_attr') }}">{{ 'course.closed'|trans }}</span>
|
||||||
{% if acp.step == 'CLOSED' %}
|
{% elseif acp.step == 'CONFIRMED_INACTIVE_SHORT' %}
|
||||||
<span class="badge bg-danger" style="font-size: 85%;" title="{{ 'course.closed'|trans }}">{{ 'course.closed'|trans }}</span>
|
<span class="badge bg-chill-yellow text-primary" style="font-size: 85%;" title="{{ 'course.inactive_short'|trans|e('html_attr') }}">{{ 'course.inactive_short'|trans }}</span>
|
||||||
|
{% elseif acp.step == 'CONFIRMED_INACTIVE_LONG' %}
|
||||||
|
<span class="badge bg-danger" style="font-size: 85%;" title="{{ 'course.inactive_long'|trans|e('html_attr') }}">{{ 'course.inactive_long'|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a list of different Query parts into a single query
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodInfoQueryBuilder
|
||||||
|
{
|
||||||
|
private const BASE_QUERY = <<<'SQL'
|
||||||
|
SELECT
|
||||||
|
{period_id_column} AS accompanyingperiod_id,
|
||||||
|
'{related_entity_column_id}' AS relatedentity,
|
||||||
|
{related_entity_id_column_id} AS relatedentityid,
|
||||||
|
{user_id} AS user_id,
|
||||||
|
{datetime} AS infodate,
|
||||||
|
'{discriminator}' AS discriminator,
|
||||||
|
{metadata} AS metadata
|
||||||
|
FROM {from_statement}
|
||||||
|
{where_statement}
|
||||||
|
SQL;
|
||||||
|
|
||||||
|
public function buildQuery(AccompanyingPeriodInfoUnionQueryPartInterface $query): string
|
||||||
|
{
|
||||||
|
return strtr(
|
||||||
|
self::BASE_QUERY,
|
||||||
|
[
|
||||||
|
'{period_id_column}' => $query->getAccompanyingPeriodIdColumn(),
|
||||||
|
'{related_entity_column_id}' => $query->getRelatedEntityColumn(),
|
||||||
|
'{related_entity_id_column_id}' => $query->getRelatedEntityIdColumn(),
|
||||||
|
'{user_id}' => $query->getUserIdColumn(),
|
||||||
|
'{datetime}' => $query->getDateTimeColumn(),
|
||||||
|
'{discriminator}' => $query->getDiscriminator(),
|
||||||
|
'{metadata}' => $query->getMetadataColumn(),
|
||||||
|
'{from_statement}' => $query->getFromStatement(),
|
||||||
|
'{where_statement}' => '' === $query->getWhereClause() ? '' : 'WHERE '.$query->getWhereClause(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodStartQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'a.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriod::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'a.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'a.openingDate';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_start';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return '\'{}\'::jsonb';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period a';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkEndQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'w.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWork::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'w.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapwr.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'w.endDate';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_end';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr on w.id = cpapwr.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'w.endDate IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkEvaluationDocumentUpdateQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapw.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWorkEvaluation::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.updatedby_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.updatedAt';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_evaluation_updated_at';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'e.updatedAt IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkEvaluationMaxQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapw.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWorkEvaluation::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapwr.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.maxDate';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_evaluation_start';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'e.maxDate IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkEvaluationStartQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapw.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWorkEvaluation::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapwr.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.startDate';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_evaluation_start';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkEvaluationUpdateQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapw.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWorkEvaluationDocument::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'doc.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'doc.updatedby_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'doc.updatedAt';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_evaluation_document_updated_at';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work_evaluation_document doc
|
||||||
|
JOIN chill_person_accompanying_period_work_evaluation e ON doc.accompanyingperiodworkevaluation_id = e.id
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'doc.updatedAt IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkEvaluationWarningDateQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapw.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWorkEvaluation::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapwr.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'e.maxDate';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_evaluation_max';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'e.maxDate IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodWorkStartQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'w.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return AccompanyingPeriodWork::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'w.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'cpapwr.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'w.startDate';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return "'{}'::jsonb";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'accompanying_period_work_start';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr on w.id = cpapwr.accompanyingperiodwork_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Service\EntityInfo;
|
||||||
|
|
||||||
|
interface AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return class-string
|
||||||
|
*/
|
||||||
|
public function getRelatedEntityColumn(): string;
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string;
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string;
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string;
|
||||||
|
|
||||||
|
public function getDiscriminator(): string;
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string;
|
||||||
|
|
||||||
|
public function getFromStatement(): string;
|
||||||
|
|
||||||
|
public function getWhereClause(): string;
|
||||||
|
}
|
@ -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\PersonBundle\Service\EntityInfo;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Service\EntityInfo\ViewEntityInfoProviderInterface;
|
||||||
|
|
||||||
|
class AccompanyingPeriodViewEntityInfoProvider implements ViewEntityInfoProviderInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
/**
|
||||||
|
* @var AccompanyingPeriodInfoUnionQueryPartInterface[]
|
||||||
|
*/
|
||||||
|
private iterable $unions,
|
||||||
|
private AccompanyingPeriodInfoQueryBuilder $builder,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewQuery(): string
|
||||||
|
{
|
||||||
|
return implode(
|
||||||
|
' UNION ',
|
||||||
|
array_map(
|
||||||
|
fn (AccompanyingPeriodInfoUnionQueryPartInterface $part) => $this->builder->buildQuery($part),
|
||||||
|
iterator_to_array($this->unions)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewName(): string
|
||||||
|
{
|
||||||
|
return 'view_chill_person_accompanying_period_info';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AccompanyingPeriod\Lifecycle;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\CronJobExecution;
|
||||||
|
use Chill\PersonBundle\AccompanyingPeriod\Lifecycle\AccompanyingPeriodStepChangeCronjob;
|
||||||
|
use Chill\PersonBundle\AccompanyingPeriod\Lifecycle\AccompanyingPeriodStepChangeRequestor;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
|
use Symfony\Component\Clock\MockClock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodStepChangeCronjobTest extends TestCase
|
||||||
|
{
|
||||||
|
use ProphecyTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideRunTimes
|
||||||
|
*/
|
||||||
|
public function testCanRun(string $datetime, \DateTimeImmutable $lastExecutionStart, bool $canRun): void
|
||||||
|
{
|
||||||
|
$requestor = $this->prophesize(AccompanyingPeriodStepChangeRequestor::class);
|
||||||
|
$clock = new MockClock($datetime);
|
||||||
|
|
||||||
|
$cronJob = new AccompanyingPeriodStepChangeCronjob($clock, $requestor->reveal());
|
||||||
|
$cronJobExecution = (new CronJobExecution($cronJob->getKey()))->setLastStart($lastExecutionStart);
|
||||||
|
|
||||||
|
$this->assertEquals($canRun, $cronJob->canRun($cronJobExecution));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideRunTimes(): iterable
|
||||||
|
{
|
||||||
|
// can run, during the night
|
||||||
|
yield ['2023-01-15T01:00:00+02:00', new \DateTimeImmutable('2023-01-14T00:00:00+02:00'), true];
|
||||||
|
|
||||||
|
// can not run, not during the night
|
||||||
|
yield ['2023-01-15T10:00:00+02:00', new \DateTimeImmutable('2023-01-14T00:00:00+02:00'), false];
|
||||||
|
|
||||||
|
// can not run: not enough elapsed time
|
||||||
|
yield ['2023-01-15T01:00:00+02:00', new \DateTimeImmutable('2023-01-15T00:30:00+02:00'), false];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -40,6 +40,8 @@ final class StepFilterTest extends AbstractFilterTest
|
|||||||
return [
|
return [
|
||||||
['accepted_steps' => AccompanyingPeriod::STEP_DRAFT],
|
['accepted_steps' => AccompanyingPeriod::STEP_DRAFT],
|
||||||
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED],
|
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED],
|
||||||
|
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG],
|
||||||
|
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT],
|
||||||
['accepted_steps' => AccompanyingPeriod::STEP_CLOSED],
|
['accepted_steps' => AccompanyingPeriod::STEP_CLOSED],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -98,3 +98,7 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
resource: '../Workflow/'
|
resource: '../Workflow/'
|
||||||
|
|
||||||
|
Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodViewEntityInfoProvider:
|
||||||
|
arguments:
|
||||||
|
$unions: !tagged_iterator chill_person.accompanying_period_info_part
|
||||||
|
@ -25,6 +25,11 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
|
|
||||||
|
Chill\PersonBundle\AccompanyingPeriod\Lifecycle\:
|
||||||
|
resource: './../../AccompanyingPeriod/Lifecycle'
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
Chill\PersonBundle\AccompanyingPeriod\Events\UserRefEventSubscriber:
|
Chill\PersonBundle\AccompanyingPeriod\Events\UserRefEventSubscriber:
|
||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
|
@ -128,6 +128,13 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export_filter, alias: accompanyingcourse_creator_job_filter }
|
- { name: chill.export_filter, alias: accompanyingcourse_creator_job_filter }
|
||||||
|
|
||||||
|
Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\UserWorkingOnCourseFilter:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: accompanyingcourse_user_working_on_filter }
|
||||||
|
|
||||||
|
Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\HavingAnAccompanyingPeriodInfoWithinDatesFilter:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: accompanyingcourse_info_within_filter }
|
||||||
|
|
||||||
## Aggregators
|
## Aggregators
|
||||||
chill.person.export.aggregator_referrer_scope:
|
chill.person.export.aggregator_referrer_scope:
|
||||||
|
@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Person;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20230427102309 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Apply steps on confirmed and inactive accompanying periods';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// create a table to store "infos" temporarily (will be store in the view)
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
CREATE TEMPORARY TABLE acc_period_info AS
|
||||||
|
SELECT a.id AS accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod'::text AS relatedentity,
|
||||||
|
a.id AS relatedentityid,
|
||||||
|
NULL::integer AS user_id,
|
||||||
|
a.openingdate AS infodate,
|
||||||
|
'accompanying_period_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period a
|
||||||
|
UNION
|
||||||
|
SELECT w.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||||
|
w.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
w.enddate AS infodate,
|
||||||
|
'accompanying_period_work_end'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE w.enddate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
e.updatedby_id AS user_id,
|
||||||
|
e.updatedat AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_updated_at'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
WHERE e.updatedat IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.maxdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE e.maxdate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.startdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument'::text AS relatedentity,
|
||||||
|
doc.id AS relatedentityid,
|
||||||
|
doc.updatedby_id AS user_id,
|
||||||
|
doc.updatedat AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_document_updated_at'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation_document doc
|
||||||
|
JOIN chill_person_accompanying_period_work_evaluation e ON doc.accompanyingperiodworkevaluation_id = e.id
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
WHERE doc.updatedat IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.maxdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_max'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE e.maxdate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT w.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||||
|
w.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
w.startdate AS infodate,
|
||||||
|
'accompanying_period_work_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
UNION
|
||||||
|
SELECT activity.accompanyingperiod_id,
|
||||||
|
'Chill\ActivityBundle\Entity\Activity'::text AS relatedentity,
|
||||||
|
activity.id AS relatedentityid,
|
||||||
|
au.user_id,
|
||||||
|
activity.date AS infodate,
|
||||||
|
'activity_date'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM activity
|
||||||
|
LEFT JOIN activity_user au ON activity.id = au.activity_id
|
||||||
|
WHERE activity.accompanyingperiod_id IS NOT NULL;
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
// create a table to store oldest inactives
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
CREATE TEMPORARY TABLE inactive_long AS
|
||||||
|
SELECT a.accompanyingperiod_id, MAX(infodate) AS last_date
|
||||||
|
FROM acc_period_info a JOIN chill_person_accompanying_period acp ON acp.id = a.accompanyingperiod_id
|
||||||
|
WHERE
|
||||||
|
NOT EXISTS (SELECT 1 FROM acc_period_info WHERE infodate > (NOW() - '2 years'::interval) AND acc_period_info.accompanyingperiod_id = a.accompanyingperiod_id)
|
||||||
|
AND acp.step LIKE 'CONFIRMED'
|
||||||
|
GROUP BY accompanyingperiod_id;
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
UPDATE chill_person_accompanying_period_step_history SET enddate = GREATEST(last_date + '2 years'::interval, startdate)
|
||||||
|
FROM inactive_long WHERE inactive_long.accompanyingperiod_id = period_id AND enddate IS NULL;
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
INSERT INTO chill_person_accompanying_period_step_history (id, period_id, enddate, startdate, step, createdat, updatedat)
|
||||||
|
SELECT nextval('chill_person_accompanying_period_step_history_id_seq'), period_id, NULL, sq.g, 'CONFIRMED_INACTIVE_LONG', NOW(), NOW()
|
||||||
|
FROM (SELECT GREATEST(MAX(startdate), MAX(enddate)) AS g, period_id FROM chill_person_accompanying_period_step_history GROUP BY period_id) AS sq
|
||||||
|
JOIN inactive_long ON sq.period_id = inactive_long.accompanyingperiod_id
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
UPDATE chill_person_accompanying_period a SET step = 'CONFIRMED_INACTIVE_LONG' FROM inactive_long inactive WHERE a.id = inactive.accompanyingperiod_id;
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
DROP TABLE inactive_long
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
CREATE TEMPORARY TABLE inactive_long AS
|
||||||
|
SELECT a.accompanyingperiod_id, MAX(infodate) AS last_date
|
||||||
|
FROM acc_period_info a JOIN chill_person_accompanying_period acp ON acp.id = a.accompanyingperiod_id
|
||||||
|
WHERE
|
||||||
|
NOT EXISTS (SELECT 1 FROM acc_period_info WHERE infodate > (NOW() - '6 months'::interval) AND acc_period_info.accompanyingperiod_id = a.accompanyingperiod_id)
|
||||||
|
AND acp.step LIKE 'CONFIRMED'
|
||||||
|
GROUP BY accompanyingperiod_id;
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
UPDATE chill_person_accompanying_period_step_history SET enddate = GREATEST(last_date + '6 months'::interval, startdate)
|
||||||
|
FROM inactive_long WHERE inactive_long.accompanyingperiod_id = period_id AND enddate IS NULL;
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
INSERT INTO chill_person_accompanying_period_step_history (id, period_id, enddate, startdate, step, createdat, updatedat)
|
||||||
|
SELECT nextval('chill_person_accompanying_period_step_history_id_seq'), period_id, NULL, sq.g, 'CONFIRMED_INACTIVE_SHORT', NOW(), NOW()
|
||||||
|
FROM (SELECT GREATEST(MAX(startdate), MAX(enddate)) AS g, period_id FROM chill_person_accompanying_period_step_history GROUP BY period_id) AS sq
|
||||||
|
JOIN inactive_long ON sq.period_id = inactive_long.accompanyingperiod_id
|
||||||
|
SQL);
|
||||||
|
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
UPDATE chill_person_accompanying_period a SET step = 'CONFIRMED_INACTIVE_SHORT' FROM inactive_long inactive WHERE a.id = inactive.accompanyingperiod_id;
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->throwIrreversibleMigrationException();
|
||||||
|
}
|
||||||
|
}
|
@ -57,7 +57,7 @@ Add new phone: Ajouter un numéro de téléphone
|
|||||||
Remove phone: Supprimer
|
Remove phone: Supprimer
|
||||||
'Notes on contact information': 'Remarques sur les informations de contact'
|
'Notes on contact information': 'Remarques sur les informations de contact'
|
||||||
'Remarks': 'Remarques'
|
'Remarks': 'Remarques'
|
||||||
'Spoken languages': 'Langues parlées'
|
Spoken languages': 'Langues parlées'
|
||||||
'Unknown spoken languages': 'Langues parlées inconnues'
|
'Unknown spoken languages': 'Langues parlées inconnues'
|
||||||
Male: Homme
|
Male: Homme
|
||||||
Female: Femme
|
Female: Femme
|
||||||
@ -237,8 +237,12 @@ No referrer: Pas d'agent traitant
|
|||||||
Some peoples does not belong to any household currently. Add them to an household soon: Certains usagers n'appartiennent à aucun ménage actuellement. Renseignez leur ménage dès que possible.
|
Some peoples does not belong to any household currently. Add them to an household soon: Certains usagers n'appartiennent à aucun ménage actuellement. Renseignez leur ménage dès que possible.
|
||||||
Add to household now: Ajouter à un ménage
|
Add to household now: Ajouter à un ménage
|
||||||
Any resource for this accompanying course: Aucun interlocuteur privilégié pour ce parcours
|
Any resource for this accompanying course: Aucun interlocuteur privilégié pour ce parcours
|
||||||
course.draft: Brouillon
|
course:
|
||||||
course.closed: Clôturé
|
draft: Brouillon
|
||||||
|
closed: Clôturé
|
||||||
|
inactive_short: Hors file active
|
||||||
|
inactive_long: Pré-archivé
|
||||||
|
confirmed: Confirmé
|
||||||
Origin: Origine de la demande
|
Origin: Origine de la demande
|
||||||
Delete accompanying period: Supprimer le parcours d'accompagnement
|
Delete accompanying period: Supprimer le parcours d'accompagnement
|
||||||
Are you sure you want to remove the accompanying period "%id%" ?: Êtes-vous sûr de vouloir supprimer le parcours d'accompagnement %id% ?
|
Are you sure you want to remove the accompanying period "%id%" ?: Êtes-vous sûr de vouloir supprimer le parcours d'accompagnement %id% ?
|
||||||
@ -1072,6 +1076,16 @@ export:
|
|||||||
Status: Statut
|
Status: Statut
|
||||||
|
|
||||||
course:
|
course:
|
||||||
|
having_info_within_interval:
|
||||||
|
title: Filter les parcours ayant reçu une intervention entre deux dates
|
||||||
|
start_date: Début de la période
|
||||||
|
end_date: Fin de la période
|
||||||
|
Only course with events between %startDate% and %endDate%: Seulement les parcours ayant reçu une intervention entre le %startDate% et le %endDate%
|
||||||
|
by_user_working:
|
||||||
|
title: Filter les parcours par intervenant
|
||||||
|
'Filtered by user working on course: only %users%': 'Filtré par intervenants sur le parcours: seulement %users%'
|
||||||
|
by_step:
|
||||||
|
date_calc: Date de prise en compte du statut
|
||||||
by_user_scope:
|
by_user_scope:
|
||||||
Computation date for referrer: Date à laquelle le référent était actif
|
Computation date for referrer: Date à laquelle le référent était actif
|
||||||
by_referrer:
|
by_referrer:
|
||||||
@ -1095,12 +1109,15 @@ export:
|
|||||||
id: Identifiant du parcours
|
id: Identifiant du parcours
|
||||||
openingDate: Date d'ouverture du parcours
|
openingDate: Date d'ouverture du parcours
|
||||||
closingDate: Date de fermeture du parcours
|
closingDate: Date de fermeture du parcours
|
||||||
|
closingMotive: Motif de cloture
|
||||||
|
job: Métier
|
||||||
confidential: Confidentiel
|
confidential: Confidentiel
|
||||||
emergency: Urgent
|
emergency: Urgent
|
||||||
intensity: Intensité
|
intensity: Intensité
|
||||||
createdAt: Créé le
|
createdAt: Créé le
|
||||||
updatedAt: Dernière mise à jour le
|
updatedAt: Dernière mise à jour le
|
||||||
acpOrigin: Origine du parcours
|
acpOrigin: Origine du parcours
|
||||||
|
origin: Origine du parcourse
|
||||||
acpClosingMotive: Motif de fermeture
|
acpClosingMotive: Motif de fermeture
|
||||||
acpJob: Métier du parcours
|
acpJob: Métier du parcours
|
||||||
createdBy: Créé par
|
createdBy: Créé par
|
||||||
@ -1120,6 +1137,8 @@ export:
|
|||||||
acprequestorPerson: Nom du demandeur usager
|
acprequestorPerson: Nom du demandeur usager
|
||||||
scopes: Services
|
scopes: Services
|
||||||
socialIssues: Problématiques sociales
|
socialIssues: Problématiques sociales
|
||||||
|
requestorPerson: Demandeur (personne)
|
||||||
|
requestorThirdParty: Demandeur (tiers)
|
||||||
eval:
|
eval:
|
||||||
List of evaluations: Liste des évaluations
|
List of evaluations: Liste des évaluations
|
||||||
Generate a list of evaluations, filtered on different parameters: Génère une liste des évaluations, filtrée sur différents paramètres.
|
Generate a list of evaluations, filtered on different parameters: Génère une liste des évaluations, filtrée sur différents paramètres.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user