mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +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",
|
||||
"spomky-labs/base64url": "^2.0",
|
||||
"symfony/browser-kit": "^4.4",
|
||||
"symfony/clock": "^6.2",
|
||||
"symfony/css-selector": "^4.4",
|
||||
"symfony/expression-language": "^4.4",
|
||||
"symfony/form": "^4.4",
|
||||
|
203
docs/source/development/entity-info.rst
Normal file
203
docs/source/development/entity-info.rst
Normal file
@ -0,0 +1,203 @@
|
||||
|
||||
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||
A copy of the license is included in the section entitled "GNU
|
||||
Free Documentation License".
|
||||
|
||||
.. _entity-info:
|
||||
|
||||
Stats about event on entity in php world
|
||||
########################################
|
||||
|
||||
It is necessary to be able to gather information about events for some entities:
|
||||
|
||||
- when the event has been done;
|
||||
- who did it;
|
||||
- ...
|
||||
|
||||
Those "infos" are not linked with right management, like describe in :ref:`timelines`.
|
||||
|
||||
|
||||
“infos” for some stats and info about an entity
|
||||
-----------------------------------------------
|
||||
|
||||
Building an info means:
|
||||
|
||||
- create an Entity, and map this entity to a SQL view (not a regular table);
|
||||
- use the framework to build this entity dynamically.
|
||||
|
||||
A framework api is built to be able to build multiple “infos” entities
|
||||
through “union” views:
|
||||
|
||||
- use a command ``bin/console chill:db:sync-views`` to synchronize view (create view if it does not exists, or update
|
||||
views when new SQL parts are added in the UNION query. Internally, this command call a new ``ViewEntityInfoManager``,
|
||||
which iterate over available views to build the SQL;
|
||||
- one can create a new “view entity info” by implementing a
|
||||
``ViewEntityInfoProviderInterface``
|
||||
- this implementation of the interface is free to create another
|
||||
interface for building each part of the UNION query. This interface
|
||||
is created for AccompanyingPeriodInfo:
|
||||
``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``
|
||||
|
||||
So, converting new “events” into rows for ``AccompanyingPeriodInfo`` is
|
||||
just implementing this interface!
|
||||
|
||||
Implementation for AccompanyingPeriod (``AccompanyingPeriod/AccompanyingPeriodInfo``)
|
||||
-------------------------------------------------------------------------------------
|
||||
|
||||
A class is created for computing some statistical info for an
|
||||
AccompanyingPeriod: ``AccompanyingPeriod/AccompanyingPeriodInfo``. This
|
||||
contains information about “something happens”, who did it and when.
|
||||
|
||||
Having those info in table answer some questions like:
|
||||
|
||||
- when is the last and the first action (AccompanyingPeriodWork,
|
||||
Activity, AccompanyingPeriodWorkEvaluation, …) on the period;
|
||||
- who is “acting” on the period, and when is the last “action” for each
|
||||
user.
|
||||
|
||||
The AccompanyingPeriod info is mapped to a SQL view, not a table. The
|
||||
sql view is built dynamically (see below), and gather infos from
|
||||
ActivityBundle, PersonBundle, CalendarBundle, … It is possible to create
|
||||
custom bundle and add info on this view.
|
||||
|
||||
.. code:: php
|
||||
|
||||
/**
|
||||
*
|
||||
* @ORM\Entity()
|
||||
* @ORM\Table(name="view_chill_person_accompanying_period_info") <==== THIS IS A VIEW, NOT A TABLE
|
||||
*/
|
||||
class AccompanyingPeriodInfo
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
Why do we need this ?
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For multiple jobs in PHP world:
|
||||
|
||||
- moving the accompanying period to another steps when inactive,
|
||||
automatically;
|
||||
- listing all the users which are intervening on the action on a new
|
||||
“Liste des intervenants” page;
|
||||
- filtering on exports
|
||||
|
||||
Later, we will launch automatic anonymise for accompanying period and
|
||||
all related entities through this information.
|
||||
|
||||
How is built the SQL views which is mapped to “info” entities ?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The AccompanyingPeriodInfo entity is mapped by a SQL view (not a regular
|
||||
table).
|
||||
|
||||
The sql view is built dynamically, it is a SQL view like this, for now (April 2023):
|
||||
|
||||
.. code:: sql
|
||||
|
||||
create view view_chill_person_accompanying_period_info
|
||||
(accompanyingperiod_id, relatedentity, relatedentityid, user_id, infodate, discriminator, metadata) as
|
||||
SELECT w.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||
w.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
w.enddate AS infodate,
|
||||
'accompanying_period_work_end'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work w
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||
WHERE w.enddate IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
e.updatedby_id AS user_id,
|
||||
e.updatedat AS infodate,
|
||||
'accompanying_period_work_evaluation_updated_at'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
WHERE e.updatedat IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
e.maxdate AS infodate,
|
||||
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||
WHERE e.maxdate IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
e.startdate AS infodate,
|
||||
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument'::text AS relatedentity,
|
||||
doc.id AS relatedentityid,
|
||||
doc.updatedby_id AS user_id,
|
||||
doc.updatedat AS infodate,
|
||||
'accompanying_period_work_evaluation_document_updated_at'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation_document doc
|
||||
JOIN chill_person_accompanying_period_work_evaluation e ON doc.accompanyingperiodworkevaluation_id = e.id
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
WHERE doc.updatedat IS NOT NULL
|
||||
UNION
|
||||
SELECT cpapw.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||
e.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
e.maxdate AS infodate,
|
||||
'accompanying_period_work_evaluation_max'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work_evaluation e
|
||||
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||
WHERE e.maxdate IS NOT NULL
|
||||
UNION
|
||||
SELECT w.accompanyingperiod_id,
|
||||
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||
w.id AS relatedentityid,
|
||||
cpapwr.user_id,
|
||||
w.startdate AS infodate,
|
||||
'accompanying_period_work_start'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM chill_person_accompanying_period_work w
|
||||
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||
UNION
|
||||
SELECT activity.accompanyingperiod_id,
|
||||
'Chill\ActivityBundle\Entity\Activity'::text AS relatedentity,
|
||||
activity.id AS relatedentityid,
|
||||
au.user_id,
|
||||
activity.date AS infodate,
|
||||
'activity_date'::text AS discriminator,
|
||||
'{}'::jsonb AS metadata
|
||||
FROM activity
|
||||
LEFT JOIN activity_user au ON activity.id = au.activity_id
|
||||
WHERE activity.accompanyingperiod_id IS NOT NULL;
|
||||
|
||||
As you can see, the view gather multiple SELECT queries and bind them
|
||||
with UNION.
|
||||
|
||||
Each SELECT query is built dynamically, through a class implementing an
|
||||
interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``, `like
|
||||
here <https://gitlab.com/Chill-Projet/chill-bundles/-/blob/master/src/Bundle/ChillPersonBundle/Service/EntityInfo/AccompanyingPeriodInfoQueryPart/AccompanyingPeriodWorkEndQueryPartForAccompanyingPeriodInfo.php>`__
|
||||
|
||||
To add new `SELECT` query in different `UNION` parts in the sql view, create a
|
||||
service and implements this interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``.
|
@ -35,6 +35,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
|
||||
manual/index.rst
|
||||
Assets <assets.rst>
|
||||
Cron Jobs <cronjob.rst>
|
||||
Info about entities <entity-info.rst>
|
||||
|
||||
Layout and UI
|
||||
**************
|
||||
|
@ -6,6 +6,8 @@
|
||||
A copy of the license is included in the section entitled "GNU
|
||||
Free Documentation License".
|
||||
|
||||
.. _timelines:
|
||||
|
||||
Timelines
|
||||
*********
|
||||
|
||||
@ -18,24 +20,24 @@ Concept
|
||||
From an user point of view
|
||||
--------------------------
|
||||
|
||||
Chill has two objectives :
|
||||
Chill has two objectives :
|
||||
|
||||
* make the administrative tasks more lightweight ;
|
||||
* help social workers to have all information they need to work
|
||||
|
||||
To reach this second objective, Chill provides a special view: **timeline**. On a timeline view, information is gathered and shown on a single page, from the most recent event to the oldest one.
|
||||
|
||||
The information gathered is linked to a *context*. This *context* may be, for instance :
|
||||
The information gathered is linked to a *context*. This *context* may be, for instance :
|
||||
|
||||
* a person : events linked to this person are shown on the page ;
|
||||
* a center: events linked to a center are shown. They may concern different peoples ;
|
||||
* ...
|
||||
* ...
|
||||
|
||||
In other word, the *context* is the kind of argument that will be used in the event's query.
|
||||
|
||||
Let us recall that only the data the user has allowed to see should be shown.
|
||||
|
||||
.. seealso::
|
||||
.. seealso::
|
||||
|
||||
`The issue where the subject was first discussed <https://redmine.champs-libres.coop/issues/224>`_
|
||||
|
||||
@ -43,30 +45,30 @@ Let us recall that only the data the user has allowed to see should be shown.
|
||||
For developers
|
||||
--------------
|
||||
|
||||
The `Main` bundle provides interfaces and services to help to build timelines.
|
||||
The `Main` bundle provides interfaces and services to help to build timelines.
|
||||
|
||||
If a bundle wants to *push* information in a timeline, it should be create a service which implements `Chill\MainBundle\Timeline\TimelineProviderInterface`, and tag is with `chill.timeline` and arguments defining the supported context (you may use multiple `chill.timeline` tags in order to support multiple context with a single service/class).
|
||||
|
||||
If a bundle wants to provide a new context for a timeline, the service `chill.main.timeline_builder` will helps to gather timeline's services supporting the defined context, and run queries across the models.
|
||||
If a bundle wants to provide a new context for a timeline, the service `chill.main.timeline_builder` will helps to gather timeline's services supporting the defined context, and run queries across the models.
|
||||
|
||||
.. _understanding-queries :
|
||||
|
||||
Understanding queries
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Due to the fact that timelines should show only the X last events from Y differents tables, queries for a timeline may consume a lot of resources: at first on the database, and then on the ORM part, which will have to deserialize DB data to PHP classes, which may not be used if they are not part of the "last X events".
|
||||
Due to the fact that timelines should show only the X last events from Y differents tables, queries for a timeline may consume a lot of resources: at first on the database, and then on the ORM part, which will have to deserialize DB data to PHP classes, which may not be used if they are not part of the "last X events".
|
||||
|
||||
To avoid such load on database, the objects are queried in two steps :
|
||||
To avoid such load on database, the objects are queried in two steps :
|
||||
|
||||
1. An UNION request which gather the last X events, ordered by date. The data retrieved are the ID, the date, and a string key: a type. This type discriminates the data type.
|
||||
2. The PHP objects are queried by ID, the type helps the program to link id with the kind of objects.
|
||||
2. The PHP objects are queried by ID, the type helps the program to link id with the kind of objects.
|
||||
|
||||
Those methods should ensure that only X PHP objects will be gathered and build by the ORM.
|
||||
|
||||
What does the master timeline builder service ?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When the service `chill.main.timeline_builder` is instanciated, the service is informed of each service taggued with `chill.timeline` tags. Then,
|
||||
When the service `chill.main.timeline_builder` is instanciated, the service is informed of each service taggued with `chill.timeline` tags. Then,
|
||||
|
||||
1. The service build an UNION query by assembling column and tables names provided by the `fetchQuery` result ;
|
||||
2. The UNION query is run, the result contains an id and a type for each row (see :ref:`above <understanding-queries>`)
|
||||
@ -84,7 +86,7 @@ To push events on a timeline :
|
||||
Implementing the TimelineProviderInterface
|
||||
------------------------------------------
|
||||
|
||||
The has the following signature :
|
||||
The has the following signature :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@ -92,19 +94,19 @@ The has the following signature :
|
||||
|
||||
interface TimelineProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $context
|
||||
* @param mixed[] $args the argument to the context.
|
||||
* @return TimelineSingleQuery
|
||||
* @throw \LogicException if the context is not supported
|
||||
*/
|
||||
public function fetchQuery($context, array $args);
|
||||
|
||||
|
||||
/**
|
||||
* Indicate if the result type may be handled by the service
|
||||
*
|
||||
*
|
||||
* @param string $type the key present in the SELECT query
|
||||
* @return boolean
|
||||
*/
|
||||
@ -113,42 +115,42 @@ The has the following signature :
|
||||
/**
|
||||
* fetch entities from db into an associative array. The keys **MUST BE**
|
||||
* the id
|
||||
*
|
||||
* All ids returned by all SELECT queries
|
||||
*
|
||||
* All ids returned by all SELECT queries
|
||||
* (@see TimeLineProviderInterface::fetchQuery) and with the type
|
||||
* supported by the provider (@see TimelineProviderInterface::supportsType)
|
||||
* will be passed as argument.
|
||||
*
|
||||
*
|
||||
* @param array $ids an array of id
|
||||
* @return mixed[] an associative array of entities, with id as key
|
||||
*/
|
||||
public function getEntities(array $ids);
|
||||
|
||||
|
||||
/**
|
||||
* return an associative array with argument to render the entity
|
||||
* in an html template, which will be included in the timeline page
|
||||
*
|
||||
*
|
||||
* The result must have the following key :
|
||||
*
|
||||
*
|
||||
* - `template` : the template FQDN
|
||||
* - `template_data`: the data required by the template
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
*
|
||||
* ```
|
||||
* array(
|
||||
* array(
|
||||
* 'template' => 'ChillMyBundle:timeline:template.html.twig',
|
||||
* 'template_data' => array(
|
||||
* 'accompanyingPeriod' => $entity,
|
||||
* 'person' => $args['person']
|
||||
* 'accompanyingPeriod' => $entity,
|
||||
* 'person' => $args['person']
|
||||
* )
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* `$context` and `$args` are defined by the bundle which will call the timeline
|
||||
* rendering.
|
||||
*
|
||||
* rendering.
|
||||
*
|
||||
* @param type $entity
|
||||
* @param type $context
|
||||
* @param array $args
|
||||
@ -156,7 +158,7 @@ The has the following signature :
|
||||
* @throws \LogicException if the context is not supported
|
||||
*/
|
||||
public function getEntityTemplate($entity, $context, array $args);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -176,7 +178,7 @@ The parameters should be replaced into the query by :code:`?`. They will be repl
|
||||
|
||||
`$context` and `$args` are defined by the bundle which will call the timeline rendering. You may use them to build a different query depending on this context.
|
||||
|
||||
For instance, if the context is `'person'`, the args will be this array :
|
||||
For instance, if the context is `'person'`, the args will be this array :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@ -197,7 +199,7 @@ You should find in the bundle documentation which contexts are arguments the bun
|
||||
|
||||
.. note::
|
||||
|
||||
We encourage to use `ClassMetaData` to define column names arguments. If you change your column names, changes will be reflected automatically during the execution of your code.
|
||||
We encourage to use `ClassMetaData` to define column names arguments. If you change your column names, changes will be reflected automatically during the execution of your code.
|
||||
|
||||
Example of an implementation :
|
||||
|
||||
@ -215,13 +217,13 @@ Example of an implementation :
|
||||
*/
|
||||
class TimelineReportProvider implements TimelineProviderInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @var EntityManager
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
|
||||
public function __construct(EntityManager $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
@ -230,9 +232,9 @@ Example of an implementation :
|
||||
public function fetchQuery($context, array $args)
|
||||
{
|
||||
$this->checkContext($context);
|
||||
|
||||
|
||||
$metadata = $this->em->getClassMetadata('ChillReportBundle:Report');
|
||||
|
||||
|
||||
return TimelineSingleQuery::fromArray([
|
||||
'id' => $metadata->getColumnName('id'),
|
||||
'type' => 'report',
|
||||
@ -254,11 +256,11 @@ Example of an implementation :
|
||||
The `supportsType` function
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This function indicate to the master `chill.main.timeline_builder` service (which orchestrate the build of UNION queries) that the service supports the type indicated in the result's array of the `fetchQuery` function.
|
||||
This function indicate to the master `chill.main.timeline_builder` service (which orchestrate the build of UNION queries) that the service supports the type indicated in the result's array of the `fetchQuery` function.
|
||||
|
||||
The implementation of our previous example will be :
|
||||
The implementation of our previous example will be :
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: php
|
||||
|
||||
|
||||
namespace Chill\ReportBundle\Timeline;
|
||||
@ -272,7 +274,7 @@ The implementation of our previous example will be :
|
||||
//...
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsType($type)
|
||||
@ -304,12 +306,12 @@ The results **must be** an array where the id given by the UNION query (remember
|
||||
{
|
||||
$reports = $this->em->getRepository('ChillReportBundle:Report')
|
||||
->findBy(array('id' => $ids));
|
||||
|
||||
|
||||
$result = array();
|
||||
foreach($reports as $report) {
|
||||
$result[$report->getId()] = $report;
|
||||
}
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -318,9 +320,9 @@ The results **must be** an array where the id given by the UNION query (remember
|
||||
The `getEntityTemplate` function
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is where the master service will collect information to render the entity.
|
||||
This is where the master service will collect information to render the entity.
|
||||
|
||||
The result must be an associative array with :
|
||||
The result must be an associative array with :
|
||||
|
||||
- **template** is the FQDN of the template ;
|
||||
- **template_data** is an associative array where keys are the variables'names for this template, and values are the values.
|
||||
@ -332,8 +334,8 @@ Example :
|
||||
array(
|
||||
'template' => 'ChillMyBundle:timeline:template.html.twig',
|
||||
'template_data' => array(
|
||||
'period' => $entity,
|
||||
'person' => $args['person']
|
||||
'period' => $entity,
|
||||
'person' => $args['person']
|
||||
)
|
||||
);
|
||||
|
||||
@ -349,7 +351,7 @@ Create a timeline with his own context
|
||||
|
||||
You have to create a Controller which will execute the service `chill.main.timeline_builder`. Using the `Chill\MainBundle\Timeline\TimelineBuilder::getTimelineHTML` function, you will get an HTML representation of the timeline, which you may include with twig `raw` filter.
|
||||
|
||||
Example :
|
||||
Example :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
|
@ -151,6 +151,7 @@ This script will :
|
||||
|
||||
# mount into to container
|
||||
./docker-php.sh
|
||||
bin/console chill:db:sync-views
|
||||
# and load fixtures
|
||||
bin/console doctrine:migrations:migrate
|
||||
|
||||
@ -161,7 +162,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
|
||||
|
||||
# mount into to container
|
||||
./docker-php.sh
|
||||
# and load fixtures
|
||||
# and load fixtures (do not this for production)
|
||||
bin/console doctrine:fixtures:load --purge-with-truncate
|
||||
|
||||
There are several users available:
|
||||
@ -204,8 +205,10 @@ How to create the database schema (= run migrations) ?
|
||||
# if a container is running
|
||||
./docker-php.sh
|
||||
bin/console doctrine:migrations:migrate
|
||||
bin/console chill:db:sync-views
|
||||
# if not
|
||||
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
|
||||
docker-compose run --user $(id -u) php bin/console chill:db:sync-views
|
||||
|
||||
|
||||
How to read the email sent by the program ?
|
||||
@ -236,6 +239,23 @@ How to open a terminal in the project
|
||||
# if not
|
||||
docker-compose run --user $(id -u) php /bin/bash
|
||||
|
||||
How to run cron-jobs ?
|
||||
======================
|
||||
|
||||
Some command must be executed in :ref:`cron jobs <cronjob>`. To execute them:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# if a container is running
|
||||
./docker-php.sh
|
||||
bin/console chill:cron-job:execute
|
||||
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||
bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||
# if not
|
||||
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute
|
||||
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||
|
||||
How to run composer ?
|
||||
=====================
|
||||
|
||||
|
@ -38,6 +38,14 @@ This should be adapted to your needs:
|
||||
|
||||
* Think about how you will backup your database. Some adminsys find easier to store database outside of docker, which might be easier to administrate or replicate.
|
||||
|
||||
Run migrations on each update
|
||||
=============================
|
||||
|
||||
Every time you start a new version, you should apply update the sql schema:
|
||||
|
||||
- running ``bin/console doctrine:migration:migrate`` to run sql migration;
|
||||
- synchonizing sql views to the last state: ``bin/console chill:db:sync-views``
|
||||
|
||||
Cron jobs
|
||||
=========
|
||||
|
||||
|
@ -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/'
|
||||
|
||||
Chill\ActivityBundle\Service\DocGenerator\:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
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\Resolver\CenterResolverInterface;
|
||||
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
|
||||
use Chill\MainBundle\Service\EntityInfo\ViewEntityInfoProviderInterface;
|
||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
||||
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
|
||||
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
|
||||
@ -62,6 +63,8 @@ class ChillMainBundle extends Bundle
|
||||
->addTag('chill_main.workflow_handler');
|
||||
$container->registerForAutoconfiguration(CronJobInterface::class)
|
||||
->addTag('chill_main.cron_job');
|
||||
$container->registerForAutoconfiguration(ViewEntityInfoProviderInterface::class)
|
||||
->addTag('chill_main.entity_info_provider');
|
||||
|
||||
$container->addCompilerPass(new SearchableServicesCompilerPass());
|
||||
$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();
|
||||
|
||||
if (
|
||||
$object instanceof TrackCreationInterface
|
||||
&& $this->security->getUser() instanceof User
|
||||
) {
|
||||
$object->setCreatedBy($this->security->getUser());
|
||||
if ($object instanceof TrackCreationInterface) {
|
||||
$object->setCreatedAt(new DateTimeImmutable('now'));
|
||||
|
||||
if ($this->security->getUser() instanceof User) {
|
||||
$object->setCreatedBy($this->security->getUser());
|
||||
}
|
||||
}
|
||||
|
||||
$this->onUpdate($object);
|
||||
@ -61,12 +61,12 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
|
||||
|
||||
protected function onUpdate(object $object): void
|
||||
{
|
||||
if (
|
||||
$object instanceof TrackUpdateInterface
|
||||
&& $this->security->getUser() instanceof User
|
||||
) {
|
||||
$object->setUpdatedBy($this->security->getUser());
|
||||
if ($object instanceof TrackUpdateInterface) {
|
||||
$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:
|
||||
# cl_chill_main.example.class: Chill\MainBundle\Example
|
||||
|
||||
imports:
|
||||
- ./services/clock.yaml
|
||||
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
@ -118,3 +121,7 @@ services:
|
||||
lazy: true
|
||||
arguments:
|
||||
$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
|
||||
tags:
|
||||
- {name: console.command }
|
||||
|
||||
Chill\MainBundle\Command\SynchronizeEntityInfoViewsCommand:
|
||||
tags:
|
||||
- {name: console.command}
|
||||
|
@ -564,6 +564,7 @@ export:
|
||||
_as_string: Adresse formattée
|
||||
confidential: Adresse confidentielle ?
|
||||
isNoAddress: Adresse incomplète ?
|
||||
steps: Escaliers
|
||||
_lat: Latitude
|
||||
_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;
|
||||
|
||||
use Chill\PersonBundle\DependencyInjection\CompilerPass\AccompanyingPeriodTimelineCompilerPass;
|
||||
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||
use Chill\PersonBundle\Widget\PersonListWidgetFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
@ -26,5 +27,7 @@ class ChillPersonBundle extends Bundle
|
||||
->addWidgetFactory(new PersonListWidgetFactory());
|
||||
|
||||
$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\PersonBundle\Controller\HouseholdCompositionTypeApiController;
|
||||
use Chill\PersonBundle\Doctrine\DQL\AddressPart;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
@ -1010,18 +1011,42 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
],
|
||||
'initial_marking' => 'DRAFT',
|
||||
'places' => [
|
||||
'DRAFT',
|
||||
'CONFIRMED',
|
||||
'CLOSED',
|
||||
AccompanyingPeriod::STEP_DRAFT,
|
||||
AccompanyingPeriod::STEP_CONFIRMED,
|
||||
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||
AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||
AccompanyingPeriod::STEP_CLOSED,
|
||||
],
|
||||
'transitions' => [
|
||||
'confirm' => [
|
||||
'from' => 'DRAFT',
|
||||
'to' => 'CONFIRMED',
|
||||
'from' => AccompanyingPeriod::STEP_DRAFT,
|
||||
'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' => [
|
||||
'from' => 'CONFIRMED',
|
||||
'to' => 'CLOSED',
|
||||
'from' => [
|
||||
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.')
|
||||
->defaultValue(false)
|
||||
->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
|
||||
;
|
||||
|
||||
|
@ -109,6 +109,24 @@ class AccompanyingPeriod implements
|
||||
*/
|
||||
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".
|
||||
*
|
||||
@ -340,6 +358,7 @@ class AccompanyingPeriod implements
|
||||
/**
|
||||
* @ORM\Column(type="string", length=32, nullable=true)
|
||||
* @Groups({"read"})
|
||||
* @var AccompanyingPeriod::STEP_*
|
||||
*/
|
||||
private string $step = self::STEP_DRAFT;
|
||||
|
||||
@ -712,11 +731,9 @@ class AccompanyingPeriod implements
|
||||
if ($this->getStep() === self::STEP_DRAFT) {
|
||||
return [[self::STEP_DRAFT]];
|
||||
}
|
||||
|
||||
if ($this->getStep() === self::STEP_CONFIRMED) {
|
||||
if (str_starts_with($this->getStep(), 'CONFIRM')) {
|
||||
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
||||
}
|
||||
|
||||
if ($this->getStep() === 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 {
|
||||
switch ($value) {
|
||||
case AccompanyingPeriod::STEP_DRAFT:
|
||||
return $this->translator->trans('Draft');
|
||||
return $this->translator->trans('course.draft');
|
||||
|
||||
case AccompanyingPeriod::STEP_CONFIRMED:
|
||||
return $this->translator->trans('Confirmed');
|
||||
return $this->translator->trans('course.confirmed');
|
||||
|
||||
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':
|
||||
return 'Step';
|
||||
|
@ -41,6 +41,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use function strlen;
|
||||
|
||||
class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
||||
@ -100,6 +101,8 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
private UserHelper $userHelper;
|
||||
|
||||
public function __construct(
|
||||
@ -113,6 +116,7 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
||||
SocialIssueRepository $socialIssueRepository,
|
||||
SocialIssueRender $socialIssueRender,
|
||||
TranslatableStringHelperInterface $translatableStringHelper,
|
||||
TranslatorInterface $translator,
|
||||
RollingDateConverterInterface $rollingDateConverter,
|
||||
UserHelper $userHelper
|
||||
) {
|
||||
@ -126,6 +130,7 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
|
||||
$this->thirdPartyRender = $thirdPartyRender;
|
||||
$this->thirdPartyRepository = $thirdPartyRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
$this->translator = $translator;
|
||||
$this->rollingDateConverter = $rollingDateConverter;
|
||||
$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:
|
||||
return static function ($value) use ($key) {
|
||||
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 STEPS = [
|
||||
'Draft' => AccompanyingPeriod::STEP_DRAFT,
|
||||
'Confirmed' => AccompanyingPeriod::STEP_CONFIRMED,
|
||||
'Closed' => AccompanyingPeriod::STEP_CLOSED,
|
||||
'course.draft' => AccompanyingPeriod::STEP_DRAFT,
|
||||
'course.confirmed' => AccompanyingPeriod::STEP_CONFIRMED,
|
||||
'course.closed' => AccompanyingPeriod::STEP_CLOSED,
|
||||
'course.inactive_short' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT,
|
||||
'course.inactive_long' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG,
|
||||
];
|
||||
|
||||
private RollingDateConverterInterface $rollingDateConverter;
|
||||
@ -96,7 +98,7 @@ class StepFilter implements FilterInterface
|
||||
'data' => self::DEFAULT_CHOICE,
|
||||
])
|
||||
->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),
|
||||
]);
|
||||
}
|
||||
|
@ -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>
|
||||
<referrer></referrer>
|
||||
<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>
|
||||
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
|
||||
|
||||
|
@ -11,12 +11,22 @@
|
||||
{{ $t('course.step.draft') }}
|
||||
</span>
|
||||
</span>
|
||||
<span v-else-if="accompanyingCourse.step === 'CONFIRMED'" class="text-md-end">
|
||||
<span class="d-md-block mb-md-3">
|
||||
<span v-else-if="accompanyingCourse.step === 'CONFIRMED' || accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT' || accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'" class="text-md-end">
|
||||
<span v-if="accompanyingCourse.step === 'CONFIRMED'" class="d-md-block mb-md-3">
|
||||
<span class="badge bg-primary">
|
||||
{{ $t('course.step.active') }}
|
||||
</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 ms-3 ms-md-0">
|
||||
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
|
||||
|
@ -21,7 +21,9 @@ const appMessages = {
|
||||
step: {
|
||||
draft: "Brouillon",
|
||||
active: "En file active",
|
||||
closed: "Cloturé"
|
||||
closed: "Cloturé",
|
||||
inactive_short: "Hors file active",
|
||||
inactive_long: "Pré-archivé",
|
||||
},
|
||||
open_at: "ouvert le ",
|
||||
by: "par ",
|
||||
|
@ -52,11 +52,13 @@
|
||||
{% endif %}
|
||||
|
||||
{% if acp.step == 'DRAFT' %}
|
||||
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.draft'|trans }}">{{ 'course.draft'|trans }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if acp.step == 'CLOSED' %}
|
||||
<span class="badge bg-danger" style="font-size: 85%;" title="{{ 'course.closed'|trans }}">{{ 'course.closed'|trans }}</span>
|
||||
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.draft'|trans|e('html_attr') }}">{{ 'course.draft'|trans }}</span>
|
||||
{% elseif acp.step == 'CLOSED' %}
|
||||
<span class="badge bg-danger" style="font-size: 85%;" title="{{ 'course.closed'|trans|e('html_attr') }}">{{ 'course.closed'|trans }}</span>
|
||||
{% elseif acp.step == 'CONFIRMED_INACTIVE_SHORT' %}
|
||||
<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 %}
|
||||
</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 [
|
||||
['accepted_steps' => AccompanyingPeriod::STEP_DRAFT],
|
||||
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED],
|
||||
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG],
|
||||
['accepted_steps' => AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT],
|
||||
['accepted_steps' => AccompanyingPeriod::STEP_CLOSED],
|
||||
];
|
||||
}
|
||||
|
@ -98,3 +98,7 @@ services:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
resource: '../Workflow/'
|
||||
|
||||
Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodViewEntityInfoProvider:
|
||||
arguments:
|
||||
$unions: !tagged_iterator chill_person.accompanying_period_info_part
|
||||
|
@ -25,6 +25,11 @@ services:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\PersonBundle\AccompanyingPeriod\Lifecycle\:
|
||||
resource: './../../AccompanyingPeriod/Lifecycle'
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\PersonBundle\AccompanyingPeriod\Events\UserRefEventSubscriber:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
@ -128,6 +128,13 @@ services:
|
||||
tags:
|
||||
- { 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
|
||||
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
|
||||
'Notes on contact information': 'Remarques sur les informations de contact'
|
||||
'Remarks': 'Remarques'
|
||||
'Spoken languages': 'Langues parlées'
|
||||
Spoken languages': 'Langues parlées'
|
||||
'Unknown spoken languages': 'Langues parlées inconnues'
|
||||
Male: Homme
|
||||
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.
|
||||
Add to household now: Ajouter à un ménage
|
||||
Any resource for this accompanying course: Aucun interlocuteur privilégié pour ce parcours
|
||||
course.draft: Brouillon
|
||||
course.closed: Clôturé
|
||||
course:
|
||||
draft: Brouillon
|
||||
closed: Clôturé
|
||||
inactive_short: Hors file active
|
||||
inactive_long: Pré-archivé
|
||||
confirmed: Confirmé
|
||||
Origin: Origine de la demande
|
||||
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% ?
|
||||
@ -1072,6 +1076,16 @@ export:
|
||||
Status: Statut
|
||||
|
||||
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:
|
||||
Computation date for referrer: Date à laquelle le référent était actif
|
||||
by_referrer:
|
||||
@ -1095,12 +1109,15 @@ export:
|
||||
id: Identifiant du parcours
|
||||
openingDate: Date d'ouverture du parcours
|
||||
closingDate: Date de fermeture du parcours
|
||||
closingMotive: Motif de cloture
|
||||
job: Métier
|
||||
confidential: Confidentiel
|
||||
emergency: Urgent
|
||||
intensity: Intensité
|
||||
createdAt: Créé le
|
||||
updatedAt: Dernière mise à jour le
|
||||
acpOrigin: Origine du parcours
|
||||
origin: Origine du parcourse
|
||||
acpClosingMotive: Motif de fermeture
|
||||
acpJob: Métier du parcours
|
||||
createdBy: Créé par
|
||||
@ -1120,6 +1137,8 @@ export:
|
||||
acprequestorPerson: Nom du demandeur usager
|
||||
scopes: Services
|
||||
socialIssues: Problématiques sociales
|
||||
requestorPerson: Demandeur (personne)
|
||||
requestorThirdParty: Demandeur (tiers)
|
||||
eval:
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user