mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch '103b-document-page-julie' into '103-document-page'
103b document page julie See merge request Chill-Projet/chill-bundles!551
This commit is contained in:
commit
68c850026b
@ -15,6 +15,7 @@ use Chill\ActivityBundle\Entity\Activity;
|
|||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\ORM\Query\Expr;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,225 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
|
use Chill\DocStoreBundle\Entity\PersonDocument;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\Providers\PersonDocumentGenericDocProvider;
|
||||||
|
use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface;
|
||||||
|
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface;
|
||||||
|
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\HttpKernel\HttpCache\Store;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
class PersonActivityDocumentACLAwareRepository implements PersonDocumentACLAwareRepositoryInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private EntityManagerInterface $em,
|
||||||
|
private CenterResolverManagerInterface $centerResolverManager,
|
||||||
|
private AuthorizationHelperForCurrentUserInterface $authorizationHelperForCurrentUser,
|
||||||
|
private Security $security)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildQueryByPerson(Person $person): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->em->getRepository(PersonDocument::class)->createQueryBuilder('d');
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->where($qb->expr()->eq('d.person', ':person'))
|
||||||
|
->setParameter('person', $person);
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface
|
||||||
|
{
|
||||||
|
$query = $this->buildBaseFetchQueryForPerson($person, $startDate, $endDate, $content);
|
||||||
|
|
||||||
|
return $this->addFetchQueryByPersonACL($query, $person);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildBaseFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery
|
||||||
|
{
|
||||||
|
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
|
||||||
|
$activityMetadata = $this->em->getClassMetadata(Activity::class);
|
||||||
|
|
||||||
|
$query = new FetchQuery(
|
||||||
|
PersonDocumentGenericDocProvider::KEY,
|
||||||
|
sprintf('jsonb_build_object(\'id\', stored_obj.%s, \'activity_id\', activity.%s)', $storedObjectMetadata->getSingleIdentifierColumnName(), $activityMetadata->getSingleIdentifierColumnName()),
|
||||||
|
sprintf('stored_obj.%s', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
sprintf('%s AS stored_obj', $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName())
|
||||||
|
);
|
||||||
|
|
||||||
|
$query->addJoinClause(
|
||||||
|
'JOIN public.activity_storedobject activity_doc ON activity_doc.storedobject_id = stored_obj.id'
|
||||||
|
);
|
||||||
|
|
||||||
|
$query->addJoinClause(
|
||||||
|
'JOIN public.activity activity ON activity.id = activity_doc.activity_id'
|
||||||
|
);
|
||||||
|
|
||||||
|
// add documents of activities from parcours context
|
||||||
|
$or = [];
|
||||||
|
$orParams = [];
|
||||||
|
$orTypes = [];
|
||||||
|
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
|
||||||
|
if (!$this->security->isGranted(ActivityVoter::SEE, $participation->getAccompanyingPeriod())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$or[] = sprintf(
|
||||||
|
'(activity.%s = ? AND stored_obj.%s BETWEEN ?::date AND COALESCE(?::date, \'infinity\'::date))',
|
||||||
|
$activityMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod'),
|
||||||
|
$storedObjectMetadata->getColumnName('createdAt')
|
||||||
|
);
|
||||||
|
$orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(),
|
||||||
|
DateTimeImmutable::createFromInterface($participation->getStartDate()),
|
||||||
|
null === $participation->getEndDate() ? null : DateTimeImmutable::createFromInterface($participation->getEndDate())];
|
||||||
|
$orTypes = [...$orTypes, Types::INTEGER, Types::DATE_IMMUTABLE, Types::DATE_IMMUTABLE];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] === $or) {
|
||||||
|
$query->addWhereClause('TRUE = FALSE');
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->addWhereClause(sprintf('(%s)', implode(' OR ', $or)), $orParams, $orTypes);
|
||||||
|
|
||||||
|
/* $query->addWhereClause(
|
||||||
|
'activity.person_id = ?',
|
||||||
|
[$person->getId()],
|
||||||
|
[Types::INTEGER]
|
||||||
|
);*/
|
||||||
|
|
||||||
|
if (null !== $startDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('stored_obj.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$startDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $endDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('stored_obj.%s < ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$endDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $content) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
'stored_obj.title ilike ?',
|
||||||
|
['%' . $content . '%'],
|
||||||
|
[Types::STRING]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function countByPerson(Person $person): int
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByPerson($person)->select('COUNT(d)');
|
||||||
|
|
||||||
|
$this->addACL($qb, $person);
|
||||||
|
|
||||||
|
return $qb->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByPerson(Person $person, array $orderBy = [], int $limit = 20, int $offset = 0): array
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByPerson($person)->select('d');
|
||||||
|
|
||||||
|
$this->addACL($qb, $person);
|
||||||
|
|
||||||
|
foreach ($orderBy as $field => $order) {
|
||||||
|
$qb->addOrderBy('d.' . $field, $order);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->setFirstResult($offset)->setMaxResults($limit);
|
||||||
|
|
||||||
|
return $qb->getQuery()->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addACL(QueryBuilder $qb, Person $person): void
|
||||||
|
{
|
||||||
|
$reachableScopes = [];
|
||||||
|
|
||||||
|
foreach ($this->centerResolverManager->resolveCenters($person) as $center) {
|
||||||
|
$reachableScopes = [
|
||||||
|
...$reachableScopes,
|
||||||
|
...$this->authorizationHelperForCurrentUser
|
||||||
|
->getReachableScopes(
|
||||||
|
ActivityVoter::SEE,
|
||||||
|
$center
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] === $reachableScopes) {
|
||||||
|
$qb->andWhere("'FALSE' = 'TRUE'");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->andWhere($qb->expr()->in('d.scope', ':scopes'))
|
||||||
|
->setParameter('scopes', $reachableScopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addFetchQueryByPersonACL(FetchQuery $fetchQuery, Person $person): FetchQuery
|
||||||
|
{
|
||||||
|
$activityMetadata = $this->em->getClassMetadata(Activity::class);
|
||||||
|
|
||||||
|
$reachableScopes = [];
|
||||||
|
|
||||||
|
foreach ($this->centerResolverManager->resolveCenters($person) as $center) {
|
||||||
|
$reachableScopes = [
|
||||||
|
...$reachableScopes,
|
||||||
|
...$this->authorizationHelperForCurrentUser->getReachableScopes(ActivityVoter::SEE, $center)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] === $reachableScopes) {
|
||||||
|
$fetchQuery->addWhereClause('FALSE = TRUE');
|
||||||
|
|
||||||
|
return $fetchQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fetchQuery->addWhereClause(
|
||||||
|
sprintf(
|
||||||
|
'activity.%s IN (%s)',
|
||||||
|
$activityMetadata->getSingleAssociationJoinColumnName('scope'),
|
||||||
|
implode(', ', array_fill(0, count($reachableScopes), '?'))
|
||||||
|
),
|
||||||
|
array_map(static fn (Scope $s) => $s->getId(), $reachableScopes),
|
||||||
|
array_fill(0, count($reachableScopes), Types::INTEGER)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $fetchQuery;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
|
||||||
|
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
|
||||||
|
{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
|
||||||
|
|
||||||
|
{% set person_id = null %}
|
||||||
|
{% if activity.person %}
|
||||||
|
{% set person_id = activity.person.id %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set accompanying_course_id = null %}
|
||||||
|
{% if activity.accompanyingPeriod %}
|
||||||
|
{% set accompanying_course_id = activity.accompanyingPeriod.id %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="item-bloc activity-item{% if itemBlocClass is defined %} {{ itemBlocClass }}{% endif %}">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-col" style="width: unset">
|
||||||
|
{% if document.isPending %}
|
||||||
|
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
||||||
|
{% elseif document.isFailure %}
|
||||||
|
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="denomination h2">
|
||||||
|
{{ document.title }}
|
||||||
|
</div>
|
||||||
|
{% if document.hasTemplate %}
|
||||||
|
<div>
|
||||||
|
<p>{{ document.template.name|localize_translatable_string }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-col">
|
||||||
|
<div class="container">
|
||||||
|
<div class="dates row text-end">
|
||||||
|
<span>{{ document.createdAt|format_date('short') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col">
|
||||||
|
<h2 class="badge-title">
|
||||||
|
<span class="title_label"></span>
|
||||||
|
<span class="title_action">
|
||||||
|
{{ activity.type.name | localize_translatable_string }}
|
||||||
|
{% if activity.emergency %}
|
||||||
|
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col item-meta">
|
||||||
|
{{ mmm.createdBy(document) }}
|
||||||
|
</div>
|
||||||
|
<ul class="item-col record_actions flex-shrink-1">
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) %}
|
||||||
|
<li>
|
||||||
|
{{ document|chill_document_button_group(document.title, is_granted('CHILL_ACTIVITY_UPDATE', activity), {small: false}) }}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_SEE', activity)%}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-show"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_activity_activity_edit', {'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-edit"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,98 @@
|
|||||||
|
<?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\GenericDoc\Providers;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Mapping\MappingException;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
final class AccompanyingPeriodActivityGenericDocProvider implements GenericDocForAccompanyingPeriodProviderInterface
|
||||||
|
{
|
||||||
|
public const KEY = 'accompanying_period_activity_document';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private EntityManagerInterface $em,
|
||||||
|
private Security $security
|
||||||
|
){
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
|
||||||
|
{
|
||||||
|
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
|
||||||
|
$activityMetadata = $this->em->getClassMetadata(Activity::class);
|
||||||
|
|
||||||
|
$query = new FetchQuery(
|
||||||
|
self::KEY,
|
||||||
|
sprintf("jsonb_build_object('id', doc_obj.%s, 'activity_id', activity.%s)", $storedObjectMetadata->getSingleIdentifierColumnName(), $activityMetadata->getSingleIdentifierColumnName()),
|
||||||
|
'doc_obj.'.$storedObjectMetadata->getColumnName('createdAt'),
|
||||||
|
$storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName().' AS doc_obj'
|
||||||
|
);
|
||||||
|
|
||||||
|
$query->addJoinClause(
|
||||||
|
'JOIN public.activity_storedobject activity_doc ON activity_doc.storedobject_id = doc_obj.id'
|
||||||
|
);
|
||||||
|
|
||||||
|
$query->addJoinClause(
|
||||||
|
'JOIN public.activity activity ON activity.id = activity_doc.activity_id'
|
||||||
|
);
|
||||||
|
|
||||||
|
$query->addWhereClause(
|
||||||
|
'activity.accompanyingperiod_id = ?',
|
||||||
|
[$accompanyingPeriod->getId()],
|
||||||
|
[Types::INTEGER]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (null !== $startDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_obj.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$startDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $endDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_obj.%s < ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$endDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $content) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
'doc_obj.title ilike ?',
|
||||||
|
['%' . $content . '%'],
|
||||||
|
[Types::STRING]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccompanyingPeriod $accompanyingPeriod
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool
|
||||||
|
{
|
||||||
|
return $this->security->isGranted(ActivityVoter::SEE, $accompanyingPeriod);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Service\GenericDoc\Providers;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Repository\PersonActivityDocumentACLAwareRepository;
|
||||||
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\GenericDocForPersonProviderInterface;
|
||||||
|
use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
final class PersonActivityGenericDocProvider implements GenericDocForPersonProviderInterface
|
||||||
|
{
|
||||||
|
public const KEY = 'person_activity_document';
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
private PersonActivityDocumentACLAwareRepository $personActivityDocumentACLAwareRepository;
|
||||||
|
|
||||||
|
public function __construct(Security $security, PersonActivityDocumentACLAwareRepository $personActivityDocumentACLAwareRepository
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->security = $security;
|
||||||
|
$this->personActivityDocumentACLAwareRepository = $personActivityDocumentACLAwareRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
|
||||||
|
{
|
||||||
|
return $this->personActivityDocumentACLAwareRepository->buildFetchQueryForPerson(
|
||||||
|
$person,
|
||||||
|
$startDate,
|
||||||
|
$endDate,
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Person $person
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAllowedForPerson(Person $person): bool
|
||||||
|
{
|
||||||
|
return $this->security->isGranted(ActivityVoter::SEE, $person);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Service\GenericDoc\Renderers;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityRepository;
|
||||||
|
use Chill\ActivityBundle\Service\GenericDoc\Providers\AccompanyingPeriodActivityGenericDocProvider;
|
||||||
|
use Chill\ActivityBundle\Service\GenericDoc\Providers\PersonActivityGenericDocProvider;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\Twig\GenericDocRendererInterface;
|
||||||
|
use Chill\DocStoreBundle\Repository\StoredObjectRepository;
|
||||||
|
|
||||||
|
final class AccompanyingPeriodActivityGenericDocRenderer implements GenericDocRendererInterface
|
||||||
|
{
|
||||||
|
private StoredObjectRepository $objectRepository;
|
||||||
|
|
||||||
|
private ActivityRepository $activityRepository;
|
||||||
|
|
||||||
|
public function __construct(StoredObjectRepository $storedObjectRepository, ActivityRepository $activityRepository)
|
||||||
|
{
|
||||||
|
$this->objectRepository = $storedObjectRepository;
|
||||||
|
$this->activityRepository = $activityRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(GenericDocDTO $genericDocDTO, $options = []): bool
|
||||||
|
{
|
||||||
|
return $genericDocDTO->key === AccompanyingPeriodActivityGenericDocProvider::KEY || $genericDocDTO->key === PersonActivityGenericDocProvider::KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string
|
||||||
|
{
|
||||||
|
return '@ChillActivity/GenericDoc/activity_document.html.twig';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'activity' => $this->activityRepository->find($genericDocDTO->identifiers['activity_id']),
|
||||||
|
'document' => $this->objectRepository->find($genericDocDTO->identifiers['id'])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,3 +38,6 @@ services:
|
|||||||
|
|
||||||
Chill\ActivityBundle\Service\EntityInfo\:
|
Chill\ActivityBundle\Service\EntityInfo\:
|
||||||
resource: '../Service/EntityInfo/'
|
resource: '../Service/EntityInfo/'
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Service\GenericDoc\:
|
||||||
|
resource: '../Service/GenericDoc/'
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
|
||||||
|
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
|
||||||
|
{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
|
||||||
|
|
||||||
|
{% set c = document.calendar %}
|
||||||
|
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-col" style="width: unset">
|
||||||
|
{% if document.storedObject.isPending %}
|
||||||
|
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
||||||
|
{% elseif document.storedObject.isFailure %}
|
||||||
|
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="denomination h2">
|
||||||
|
{{ document.storedObject.title }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ 'chill_calendar.Document'|trans }}
|
||||||
|
</div>
|
||||||
|
{% if document.storedObject.hasTemplate %}
|
||||||
|
<div>
|
||||||
|
<p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-col">
|
||||||
|
<div class="container">
|
||||||
|
<div class="dates row text-end">
|
||||||
|
<span>{{ document.storedObject.createdAt|format_date('short') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col">
|
||||||
|
<p class="date-label">
|
||||||
|
{% if c.endDate.diff(c.startDate).days >= 1 %}
|
||||||
|
{{ c.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ c.endDate|format_datetime('short', 'short') }}
|
||||||
|
{% else %}
|
||||||
|
{{ c.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ c.endDate|format_datetime('none', 'short') }}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col item-meta">
|
||||||
|
{{ mmm.createdBy(document) }}
|
||||||
|
</div>
|
||||||
|
<ul class="item-col record_actions flex-shrink-1">
|
||||||
|
{% if is_granted('CHILL_CALENDAR_DOC_SEE', document) %}
|
||||||
|
<li>
|
||||||
|
{{ document.storedObject|chill_document_button_group(document.storedObject.title, is_granted('CHILL_CALENDAR_CALENDAR_EDIT', c)) }}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', c) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', {'id': c.id, 'docId': document.id}) }}" class="btn btn-edit"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Service\GenericDoc\Providers;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CalendarDoc;
|
||||||
|
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Mapping\MappingException;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
final class AccompanyingPeriodCalendarGenericDocProvider implements GenericDocForAccompanyingPeriodProviderInterface
|
||||||
|
{
|
||||||
|
public const KEY = 'accompanying_period_calendar_document';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private Security $security,
|
||||||
|
private EntityManagerInterface $em
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws MappingException
|
||||||
|
*/
|
||||||
|
public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
|
||||||
|
{
|
||||||
|
$classMetadata = $this->em->getClassMetadata(CalendarDoc::class);
|
||||||
|
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
|
||||||
|
$calendarMetadata = $this->em->getClassMetadata(Calendar::class);
|
||||||
|
|
||||||
|
$query = new FetchQuery(
|
||||||
|
self::KEY,
|
||||||
|
sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')),
|
||||||
|
'cd.'.$storedObjectMetadata->getColumnName('createdAt'),
|
||||||
|
$classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd'
|
||||||
|
);
|
||||||
|
$query->addJoinClause(
|
||||||
|
sprintf('JOIN %s doc_store ON doc_store.%s = cd.%s',
|
||||||
|
$storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(),
|
||||||
|
$storedObjectMetadata->getColumnName('id'),
|
||||||
|
$classMetadata->getSingleAssociationJoinColumnName('storedObject')
|
||||||
|
));
|
||||||
|
|
||||||
|
$query->addJoinClause(
|
||||||
|
sprintf('JOIN %s calendar ON calendar.%s = cd.%s',
|
||||||
|
$calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(),
|
||||||
|
$calendarMetadata->getColumnName('id'),
|
||||||
|
$classMetadata->getSingleAssociationJoinColumnName('calendar')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('calendar.%s = ?',
|
||||||
|
$calendarMetadata->getAssociationMapping('accompanyingPeriod')['joinColumns'][0]['name']),
|
||||||
|
[$accompanyingPeriod->getId()],
|
||||||
|
[Types::INTEGER]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (null !== $startDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_store.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$startDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $endDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_store.%s < ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$endDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $content) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_store.%s ilike ?', $storedObjectMetadata->getColumnName('title')),
|
||||||
|
['%' . $content . '%'],
|
||||||
|
[Types::STRING]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool
|
||||||
|
{
|
||||||
|
return $this->security->isGranted(CalendarVoter::SEE, $accompanyingPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
<?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\CalendarBundle\Service\GenericDoc\Providers;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CalendarDoc;
|
||||||
|
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\GenericDocForPersonProviderInterface;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Mapping\MappingException;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
final class PersonCalendarGenericDocProvider implements GenericDocForPersonProviderInterface
|
||||||
|
{
|
||||||
|
public const KEY = 'person_calendar_document';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private Security $security,
|
||||||
|
private EntityManagerInterface $em
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function addWhereClausesToQuery(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery
|
||||||
|
{
|
||||||
|
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
|
||||||
|
|
||||||
|
if (null !== $startDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_store.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$startDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $endDate) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_store.%s < ?', $storedObjectMetadata->getColumnName('createdAt')),
|
||||||
|
[$endDate],
|
||||||
|
[Types::DATE_IMMUTABLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $content) {
|
||||||
|
$query->addWhereClause(
|
||||||
|
sprintf('doc_store.%s ilike ?', $storedObjectMetadata->getColumnName('title')),
|
||||||
|
['%' . $content . '%'],
|
||||||
|
[Types::STRING]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws MappingException
|
||||||
|
*/
|
||||||
|
public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
|
||||||
|
{
|
||||||
|
$classMetadata = $this->em->getClassMetadata(CalendarDoc::class);
|
||||||
|
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
|
||||||
|
$calendarMetadata = $this->em->getClassMetadata(Calendar::class);
|
||||||
|
|
||||||
|
$query = new FetchQuery(
|
||||||
|
self::KEY,
|
||||||
|
sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')),
|
||||||
|
'cd.'.$storedObjectMetadata->getColumnName('createdAt'),
|
||||||
|
$classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd'
|
||||||
|
);
|
||||||
|
$query->addJoinClause(
|
||||||
|
sprintf('JOIN %s doc_store ON doc_store.%s = cd.%s',
|
||||||
|
$storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(),
|
||||||
|
$storedObjectMetadata->getColumnName('id'),
|
||||||
|
$classMetadata->getSingleAssociationJoinColumnName('storedObject')
|
||||||
|
));
|
||||||
|
|
||||||
|
$query->addJoinClause(
|
||||||
|
sprintf('JOIN %s calendar ON calendar.%s = cd.%s',
|
||||||
|
$calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(),
|
||||||
|
$calendarMetadata->getColumnName('id'),
|
||||||
|
$classMetadata->getSingleAssociationJoinColumnName('calendar')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// get the documents associated with accompanying periods in which person participates
|
||||||
|
$or = [];
|
||||||
|
$orParams = [];
|
||||||
|
$orTypes = [];
|
||||||
|
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
|
||||||
|
if (!$this->security->isGranted(CalendarVoter::SEE, $participation->getAccompanyingPeriod())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$or[] = sprintf(
|
||||||
|
'(calendar.%s = ? AND cd.%s BETWEEN ?::date AND COALESCE(?::date, \'infinity\'::date))',
|
||||||
|
$calendarMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod'),
|
||||||
|
$storedObjectMetadata->getColumnName('createdAt')
|
||||||
|
);
|
||||||
|
$orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(),
|
||||||
|
DateTimeImmutable::createFromInterface($participation->getStartDate()),
|
||||||
|
null === $participation->getEndDate() ? null : DateTimeImmutable::createFromInterface($participation->getEndDate())];
|
||||||
|
$orTypes = [...$orTypes, Types::INTEGER, Types::DATE_IMMUTABLE, Types::DATE_IMMUTABLE];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] === $or) {
|
||||||
|
$query->addWhereClause('TRUE = FALSE');
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $query->addWhereClause(sprintf('(%s)', implode(' OR ', $or)), $orParams, $orTypes);
|
||||||
|
|
||||||
|
return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Person $person
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAllowedForPerson(Person $person): bool
|
||||||
|
{
|
||||||
|
return $this->security->isGranted(CalendarVoter::SEE, $person);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?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\CalendarBundle\Service\GenericDoc\Renderers;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Repository\CalendarDocRepository;
|
||||||
|
use Chill\CalendarBundle\Service\GenericDoc\Providers\AccompanyingPeriodCalendarGenericDocProvider;
|
||||||
|
use Chill\CalendarBundle\Service\GenericDoc\Providers\PersonCalendarGenericDocProvider;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
|
||||||
|
use Chill\DocStoreBundle\GenericDoc\Twig\GenericDocRendererInterface;
|
||||||
|
|
||||||
|
final class AccompanyingPeriodCalendarGenericDocRenderer implements GenericDocRendererInterface
|
||||||
|
{
|
||||||
|
private CalendarDocRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(CalendarDocRepository $calendarDocRepository)
|
||||||
|
{
|
||||||
|
$this->repository = $calendarDocRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(GenericDocDTO $genericDocDTO, $options = []): bool
|
||||||
|
{
|
||||||
|
return $genericDocDTO->key === AccompanyingPeriodCalendarGenericDocProvider::KEY || $genericDocDTO->key === PersonCalendarGenericDocProvider::KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string
|
||||||
|
{
|
||||||
|
return '@ChillCalendar/GenericDoc/calendar_document.html.twig';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'document' => $this->repository->find($genericDocDTO->identifiers['id'])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,7 @@ crud:
|
|||||||
title_edit: Modifier le motif d'annulation
|
title_edit: Modifier le motif d'annulation
|
||||||
|
|
||||||
chill_calendar:
|
chill_calendar:
|
||||||
|
Document: Document d'un rendez-vous
|
||||||
form:
|
form:
|
||||||
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
|
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
|
||||||
Create for referrer: Créer pour le référent
|
Create for referrer: Créer pour le référent
|
||||||
@ -65,6 +66,7 @@ chill_calendar:
|
|||||||
Document outdated: La date et l'heure du rendez-vous ont été modifiés après la création du document
|
Document outdated: La date et l'heure du rendez-vous ont été modifiés après la création du document
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
remote_ms_graph:
|
remote_ms_graph:
|
||||||
freebusy_statuses:
|
freebusy_statuses:
|
||||||
busy: Occupé
|
busy: Occupé
|
||||||
@ -145,3 +147,9 @@ CHILL_CALENDAR_CALENDAR_EDIT: Modifier les rendez-vous
|
|||||||
CHILL_CALENDAR_CALENDAR_DELETE: Supprimer les rendez-vous
|
CHILL_CALENDAR_CALENDAR_DELETE: Supprimer les rendez-vous
|
||||||
CHILL_CALENDAR_CALENDAR_SEE: Voir les rendez-vous
|
CHILL_CALENDAR_CALENDAR_SEE: Voir les rendez-vous
|
||||||
|
|
||||||
|
|
||||||
|
generic_doc:
|
||||||
|
filter:
|
||||||
|
keys:
|
||||||
|
accompanying_period_calendar_document: Document des rendez-vous
|
||||||
|
person_calendar_document: Document des rendez-vous de la personne
|
||||||
|
@ -160,7 +160,7 @@ class DocumentAccompanyingCourseController extends AbstractController
|
|||||||
|
|
||||||
$this->addFlash('success', $this->translator->trans('The document is successfully registered'));
|
$this->addFlash('success', $this->translator->trans('The document is successfully registered'));
|
||||||
|
|
||||||
return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]);
|
return $this->redirectToRoute('chill_docstore_generic-doc_by-period_index', ['id' => $course->getId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($form->isSubmitted() && !$form->isValid()) {
|
if ($form->isSubmitted() && !$form->isValid()) {
|
||||||
|
@ -1236,3 +1236,4 @@ generic_doc:
|
|||||||
filter:
|
filter:
|
||||||
keys:
|
keys:
|
||||||
accompanying_period_work_evaluation_document: Document des actions d'accompagnement
|
accompanying_period_work_evaluation_document: Document des actions d'accompagnement
|
||||||
|
person_document: Documents de la personne
|
||||||
|
Loading…
x
Reference in New Issue
Block a user