Compare commits

..

11 Commits

Author SHA1 Message Date
0b7651f519 FIX changes to repository: using ACLAware instead of deprecated method 2023-03-07 10:56:03 +01:00
033e1f9aa1 FEATURE [filters][parameters] filter working, but still using deprecated method from ActivityRepository 2023-03-03 13:06:43 +01:00
08df1c4ac8 FEATURE [repository] add parameters for filter data - typing error still for userjob 2023-03-03 12:23:07 +01:00
8d6cd0cf63 FEATURE [activity][filter] filter form created to list activities within the parcours and person context 2023-03-03 09:44:18 +01:00
f762f35386 FEATURE [repository] method added to repository to alter query using filters - not done 2023-03-03 09:44:18 +01:00
3cc56e7431 FEATURE [activity][filter] filter form created to list activities within the parcours and person context 2023-03-03 09:44:18 +01:00
243e148c00 Merge branch 'issue719_filter_activities' of gitlab.com:Chill-Projet/chill-bundles into issue719_filter_activities 2023-02-23 15:25:11 +01:00
382d3ddd42 FEATURE [activity][filter] filter form created to list activities within the parcours and person context 2023-02-23 15:22:10 +01:00
7fd823f1ee FEATURE [repository] method added to repository to alter query using filters - not done 2023-02-16 14:14:27 +01:00
1c80e0b5f5 FEATURE [activity][filter] filter form created to list activities within the parcours and person context 2023-02-16 14:14:27 +01:00
3923a13b30 FEATURE [activity][filter] filter form created to list activities within the parcours and person context 2023-02-15 16:27:34 +01:00
85 changed files with 706 additions and 608 deletions

View File

@@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Form\ActivityFilterType;
use Chill\ActivityBundle\Form\ActivityType;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
use Chill\ActivityBundle\Repository\ActivityRepository;
@@ -294,6 +295,10 @@ final class ActivityController extends AbstractController
[$person, $accompanyingPeriod] = $this->getEntity($request);
$form = $this->createForm(ActivityFilterType::class);
$form->handleRequest($request);
if ($person instanceof Person) {
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $person);
$activities = $this->activityACLAwareRepository
@@ -309,15 +314,43 @@ final class ActivityController extends AbstractController
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod);
$activities = $this->activityACLAwareRepository
->findByAccompanyingPeriod($accompanyingPeriod, ActivityVoter::SEE, 0, null, ['date' => 'DESC', 'id' => 'DESC']);
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$activities = $this->activityACLAwareRepository
->findByAccompanyingPeriod(
$accompanyingPeriod,
ActivityVoter::SEE,
0,
$data['dateTo'],
$data['dateFrom'],
$data['jobs']->getValues(),
$data['types']->getValues(),
$data['onlyMe'],
null,
['date' => 'DESC', 'id' => 'DESC']
);
} else {
$activities = $this->activityACLAwareRepository
->findByAccompanyingPeriod(
$accompanyingPeriod,
ActivityVoter::SEE,
0,
null,
null,
[],
[],
false,
null,
['date' => 'DESC', 'id' => 'DESC']
);
}
}
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
return $this->render(
$view,
[
'form' => $form->createView(),
'activities' => $activities,
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,

View File

@@ -257,10 +257,12 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
/**
* Add a social issue.
*
* Note: the social issue consistency (the fact that only youngest social issues
* Note: the social issue consistency (the fact that only yougest social issues
* are kept) is processed by an entity listener:
*
* @see{\Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodSocialIssueConsistencyEntityListener}
*
* @return $this
*/
public function addSocialIssue(SocialIssue $socialIssue): self
{
@@ -268,10 +270,6 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
$this->socialIssues[] = $socialIssue;
}
if ($this->getAccompanyingPeriod() !== null) {
$this->getAccompanyingPeriod()->addSocialIssue($socialIssue);
}
return $this;
}
@@ -552,10 +550,6 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
{
$this->accompanyingPeriod = $accompanyingPeriod;
foreach ($this->getSocialIssues() as $issue) {
$this->accompanyingPeriod->addSocialIssue($issue);
}
return $this;
}

View File

@@ -50,7 +50,7 @@ class LocationFilter implements FilterInterface
{
$builder->add('accepted_location', PickUserLocationType::class, [
'multiple' => true,
'label' => 'pick location',
'label' => 'pick location'
]);
}

View File

@@ -0,0 +1,107 @@
<?php
namespace Chill\ActivityBundle\Form;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
use Chill\ActivityBundle\Entity\ActivityType;
class ActivityFilterType extends AbstractType
{
private TranslatableStringHelperInterface $translatableString;
protected TranslatorInterface $translator;
public function __construct(TranslatableStringHelperInterface $translatableString, TranslatorInterface $translator)
{
$this->translatableString = $translatableString;
$this->translator = $translator;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('types', EntityType::class, [
'class' => ActivityType::class,
'label' => 'Activity type',
'multiple' => true,
'query_builder' => static function (EntityRepository $er) {
$qb = $er->createQueryBuilder('t');
$qb->andWhere($qb->expr()->eq('t.active', "'TRUE'"));
return $qb;
},
'choice_label' => function (ActivityType $t) {
return $this->translatableString->localize($t->getName());
},
'required' => false,
])
->add('jobs', EntityType::class, [
'class' => UserJob::class,
'label' => 'user job',
'multiple' => true,
'query_builder' => static function (EntityRepository $er) {
$qb = $er->createQueryBuilder('j');
$qb->andWhere($qb->expr()->eq('j.active', "'TRUE'"));
return $qb;
},
'choice_label' => function (UserJob $j) {
return $this->translatableString->localize($j->getLabel());
},
'required' => false,
])
->add('dateFrom', ChillDateType::class, [
'label' => 'Activities after this date',
'required' => false,
])
->add('dateTo', ChillDateType::class, [
'label' => 'Activities before this date',
'required' => false,
])
->add('onlyMe', CheckboxType::class, [
'label' => 'My activities only',
'required' => false,
]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$form = $event->getForm();
$dateFrom = $form->get('dateFrom')->getData();
$dateTo = $form->get('dateTo')->getData();
// check that date_from is before date_to
if (
(null !== $dateFrom && null !== $dateTo)
&& $dateFrom >= $dateTo
) {
$form->get('dateTo')->addError(new FormError(
$this->translator->trans('This date should be after '
. 'the date given in "Implied in an activity after '
. 'this date" field')
));
}
});
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
]);
}
}

View File

@@ -22,14 +22,15 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Security;
use function count;
use function in_array;
@@ -63,21 +64,31 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte
$this->security = $security;
}
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
{
$user = $this->security->getUser();
$center = $this->centerResolverDispatcher->resolveCenter($period);
/* public function findByAccompanyingPeriod(
AccompanyingPeriod $period,
string $role,
?int $start = 0,
?DateTime $before = null,
?DateTime $after = null,
?array $userJob = [],
?array $activityTypes = [],
bool $onlyMe = false,
?int $limit = 1000,
?array $orderBy = []
): array {
$user = $this->security->getUser();
$center = $this->centerResolverDispatcher->resolveCenter($period);
if (0 === count($orderBy)) {
$orderBy = ['date' => 'DESC'];
}
if (0 === count($orderBy)) {
$orderBy = ['date' => 'DESC'];
}
$scopes = $this->authorizationHelper
->getReachableCircles($user, $role, $center);
$scopes = $this->authorizationHelper
->getReachableCircles($user, $role, $center);
return $this->em->getRepository(Activity::class)
->findByAccompanyingPeriod($period, $scopes, true, $limit, $start, $orderBy);
}
return $this->em->getRepository(Activity::class)
->findByAccompanyingPeriod($period, $scopes, true, $before, $after, $userJob, $activityTypes, $onlyMe, $limit, $start, $orderBy);
}*/
public function findByAccompanyingPeriodSimplified(AccompanyingPeriod $period, ?int $limit = 1000): array
{
@@ -199,6 +210,62 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte
];
}
/**
* @return Activity[]
*/
private function findByAccompanyingPeriod(
AccompanyingPeriod $period,
string $role,
?int $start = 0,
?DateTime $before = null,
?DateTime $after = null,
?array $userJob = [],
?array $activityTypes = [],
bool $onlyMe = false,
?int $limit = 100,
?int $offset = 0,
?array $orderBy = ['date' => 'desc']
): array {
$qb = $this->createQueryBuilder('a');
$qb->select('a');
$user = $this->security->getUser();
$center = $this->centerResolverDispatcher->resolveCenter($period);
if (0 === count($orderBy)) {
$orderBy = ['date' => 'DESC'];
}
$scopes = $this->authorizationHelper
->getReachableCircles($user, $role, $center);
$qb
->where(
$qb->expr()->orX(
$qb->expr()->in('a.scope', ':scopes'),
$qb->expr()->isNull('a.scope')
)
)
->setParameter('scopes', $scopes);
$qb
->andWhere(
$qb->expr()->eq('a.accompanyingPeriod', ':period')
)
->setParameter('period', $period);
//Add filter queries
$this->repository->addQueryFilters($qb, $userJob, $activityTypes, $after, $before, $onlyMe);
foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.' . $k, $dir);
}
$qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery()->getResult();
}
private function getFromClauseCenter(array $args): string
{
$metadataActivity = $this->em->getClassMetadata(Activity::class);

View File

@@ -11,15 +11,29 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use DateTime;
interface ActivityACLAwareRepositoryInterface
{
/**
* @return Activity[]|array
*/
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array;
public function findByAccompanyingPeriod(
AccompanyingPeriod $period,
string $role,
?int $start = 0,
?DateTime $before = null,
?DateTime $after = null,
?array $userJob = [],
?array $activityTypes = [],
bool $onlyMe = false,
?int $limit = 1000,
?int $offset = 0,
?array $orderBy = []
): array;
/**
* Return a list of activities, simplified as array (not object).

View File

@@ -12,10 +12,16 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\MainBundle\Entity\UserJob;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Security;
use function count;
/**
* @method Activity|null find($id, $lockMode = null, $lockVersion = null)
@@ -25,9 +31,58 @@ use Doctrine\Persistence\ManagerRegistry;
*/
class ActivityRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
private Security $security;
public function __construct(ManagerRegistry $registry, Security $security)
{
parent::__construct($registry, Activity::class);
$this->security = $security;
}
/**
* @param array|UserJob $jobs
* @param array|ActivityType $types
* @param DateTime $dateFrom
* @param DateTime $dateTo
*/
public function addQueryFilters(QueryBuilder $qb, array $jobs, array $types, ?DateTime $dateFrom, ?DateTime $dateTo, bool $onlyMe): QueryBuilder
{
if (0 < count($jobs)) {
//TODO check for jobs of all users involved
$qb->innerJoin('a.user', 'u');
$qb->andWhere($qb->expr()->in('u.userJob', ':jobs'))
->setParameter('jobs', $jobs);
}
if (0 < count($types)) {
$qb->andWhere($qb->expr()->in('a.activityType', ':types'))
->setParameter('types', $types);
}
if (null !== $dateFrom && null !== $dateTo) {
$qb->andWhere($qb->expr()->between(
'a.date',
':date_from',
':date_to'
))
->setParameter('date_from', $dateFrom)
->setParameter('date_to', $dateTo);
} elseif (null !== $dateFrom && null === $dateTo) {
$qb->andWhere($qb->expr()->gt('a.date', ':date_from'))
->setParameter('date_from', $dateFrom);
} elseif (null === $dateFrom && null !== $dateTo) {
$qb->andWhere($qb->expr()->lt('a.date', ':date_to'))
->setParameter('date_to', $dateTo);
}
if (true === $onlyMe) {
$currentUser = $this->security->getUser();
$qb->andWhere($qb->expr()->eq('a.user', ':currentUser'))
->setParameter('currentUser', $currentUser);
}
return $qb;
}
/**
@@ -35,8 +90,19 @@ class ActivityRepository extends ServiceEntityRepository
*
* @return Activity[]
*/
public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array
{
public function findByAccompanyingPeriod(
AccompanyingPeriod $period,
array $scopes,
?bool $allowNullScope = false,
?DateTime $before = null,
?DateTime $after = null,
?array $userJob = [],
array $activityTypes = [],
bool $onlyMe = false,
?int $limit = 100,
?int $offset = 0,
array $orderBy = ['date' => 'desc']
): array {
$qb = $this->createQueryBuilder('a');
$qb->select('a');
@@ -61,6 +127,9 @@ class ActivityRepository extends ServiceEntityRepository
)
->setParameter('period', $period);
//Add filter queries
$this->addQueryFilters($qb, $userJob, $activityTypes, $after, $before, $onlyMe);
foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.' . $k, $dir);
}

View File

@@ -88,11 +88,3 @@ div.flex-bloc.concerned-groups {
font-size: 120%;
}
}
/// DOCUMENT LIST IN ACTIVITY ITEM
li.document-list-item {
display: flex;
width: 100%;
justify-content: space-between;
margin-bottom: 0.3rem;
}

View File

@@ -68,7 +68,7 @@
<div class="wl-col title"><h3>{{ 'Referrer'|trans }}</h3></div>
<div class="wl-col list">
<p class="wl-item">
<span class="badge-user">{{ activity.user|chill_entity_render_box }}</span>
{{ activity.user|chill_entity_render_box }}
</p>
</div>
</div>
@@ -137,42 +137,19 @@
{{ activity.comment|chill_entity_render_box({
'disable_markdown': false,
'limit_lines': 3,
'metadata': false,
'metadata': false
}) }}
</div>
</div>
{% endif %}
{% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) and activity.privateComment.hasCommentForUser(app.user) %}
<div class="wl-row">
<div class="wl-col title">
<h3>{{ 'Private comment'|trans }}</h3>
</div>
<div class="wl-col list">
<section class="chill-entity entity-comment-embeddable">
<blockquote class="chill-user-quote private-quote">
{{ activity.privateComment.comments[app.user.id]|chill_markdown_to_html }}
</blockquote>
</section>
</div>
</div>
{% endif %}
{% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) and activity.documents|length > 0 %}
<div class="wl-row">
<div class="wl-col title">
<h3>{{ 'Documents'|trans }}</h3>
</div>
<div class="wl-col list">
<ul>
{% for d in activity.documents %}
<li class="document-list-item">{{ d.title|chill_print_or_message('document.Any title') }} {{ d|chill_document_button_group(d.title, is_granted('CHILL_ACTIVITY_UPDATE', activity), {small: true}) }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{# Only if ACL SEE_DETAILS AND/OR only on template SHOW ??
durationTime
travelTime
comment
documents
attendee
#}
</div>
</div>

View File

@@ -8,13 +8,11 @@
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}
@@ -29,7 +27,49 @@
{% set accompanying_course_id = accompanyingCourse.id %}
{% endif %}
<h1>{{ 'Activity list' |trans }}</h1>
<h1>{{ 'Activity list'|trans }}</h1>
{# TODO: form error messages not displaying #}
<p>{{ form_errors(form) }}</p>
{{ form_start(form) }}
<div class="row">
<div class="col-md-4">
{{ form_label(form.types ) }}
{{ form_widget(form.types, {'attr': {'class': 'select2'}}) }}
</div>
<div class="col-md-4">
{{ form_label(form.jobs) }}
{{ form_widget(form.jobs, {'attr': {'class': 'select2'}}) }}
</div>
<div class="row">
<div class="col-md-4">
{{ form_label(form.dateFrom) }}
{{ form_widget(form.dateFrom) }}
</div>
<div class="col-md-4">
{{ form_label(form.dateTo) }}
{{ form_widget(form.dateTo) }}
</div>
</div>
<div class="row">
<div class="col-md-4">
{{ form_label(form.onlyMe) }}
{{ form_widget(form.onlyMe) }}
</div>
</div>
</div>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save change-icon">
<i class="fa fa-filter"></i> Filtrer
</button>
</li>
</ul>
{{ form_end(form) }}
{# </div>#}
{% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'accompanyingCourse'} %}

View File

@@ -23,13 +23,11 @@
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}

View File

@@ -41,7 +41,7 @@
{% if activity.user and t.userVisible %}
<li>
<span class="item-key">{{ 'Referrer'|trans ~ ': ' }}</span>
<span class="badge-user">{{ activity.user|chill_entity_render_box }}</span>
<b>{{ activity.user|chill_entity_render_box}}</b>
</li>
{% endif %}

View File

@@ -35,9 +35,7 @@
<div class="item-row separator">
<dl class="chill_view_data">
<dt class="inline">{{ 'Referrer'|trans|capitalize }}</dt>
<dd>
<span class="badge-user">{{ entity.user|chill_entity_render_box }}</span>
</dd>
<dd>{{ entity.user|chill_entity_render_box }}</dd>
{%- if entity.scope -%}
<dt class="inline">{{ 'Scope'|trans }}</dt>
@@ -170,7 +168,7 @@
{% if entity.documents|length > 0 %}
<ul>
{% for d in entity.documents %}
<li class="document-list-item">{{ d.title|chill_print_or_message('document.Any title') }} {{ d|chill_document_button_group(d.title, is_granted('CHILL_ACTIVITY_UPDATE', entity), {small: true}) }}</li>
<li>{{ d.title }} {{ d|chill_document_button_group() }}</li>
{% endfor %}
</ul>
{% else %}

View File

@@ -152,7 +152,7 @@ class ActivityContext implements
$options = $template->getOptions();
$data = [];
$data = array_merge($data, $this->baseContextData->getData($contextGenerationData['creator'] ?? null));
$data = array_merge($data, $this->baseContextData->getData());
$data['activity'] = $this->normalizer->normalize($entity, 'docgen', ['docgen:expects' => Activity::class, 'groups' => 'docgen:read']);
$data['course'] = $this->normalizer->normalize($entity->getAccompanyingPeriod(), 'docgen', ['docgen:expects' => AccompanyingPeriod::class, 'groups' => 'docgen:read']);

View File

@@ -1,5 +1,8 @@
---
services:
Chill\ActivityBundle\Form\ActivityFilterType:
autowire: true
autoconfigure: true
Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategoryType:
autowire: true
autoconfigure: true

View File

@@ -284,6 +284,8 @@ Filter acp which has no activity: Filtrer les parcours qui nont pas dactiv
Filtered acp which has no activities: Filtrer les parcours sans activité associée
Group acp by activity number: Grouper les parcours par nombre dactivité
My activities only: Mes échanges uniquement
#aggregators
Activity type: Type d'activité
Activity user: Utilisateur lié à l'activité

View File

@@ -1,18 +1,10 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\AsideActivityBundle\Export\Export;
use Chill\AsideActivityBundle\Entity\AsideActivity;
use Chill\AsideActivityBundle\Export\Declarations;
use Chill\AsideActivityBundle\Form\AsideActivityCategoryType;
use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository;
use Chill\AsideActivityBundle\Security\AsideActivityVoter;
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
@@ -24,32 +16,32 @@ use Chill\MainBundle\Export\Helper\UserHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use DateTimeInterface;
use Closure;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
final class ListAsideActivity implements ListInterface, GroupedExportInterface
{
private EntityManagerInterface $em;
private UserHelper $userHelper;
private DateTimeHelper $dateTimeHelper;
private ScopeRepositoryInterface $scopeRepository;
private CenterRepositoryInterface $centerRepository;
private AsideActivityCategoryRepository $asideActivityCategoryRepository;
private CategoryRender $categoryRender;
private CenterRepositoryInterface $centerRepository;
private DateTimeHelper $dateTimeHelper;
private EntityManagerInterface $em;
private ScopeRepositoryInterface $scopeRepository;
private TranslatableStringHelperInterface $translatableStringHelper;
private UserHelper $userHelper;
public function __construct(
EntityManagerInterface $em,
DateTimeHelper $dateTimeHelper,
@@ -84,6 +76,11 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
return 'export.aside_activity.List of aside activities';
}
public function getTitle()
{
return 'export.aside_activity.List of aside activities';
}
public function getGroup(): string
{
return 'export.Exports of aside activities';
@@ -94,16 +91,15 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
switch ($key) {
case 'id':
case 'note':
return static function ($value) use ($key) {
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.aside_activity.' . $key;
}
return $value ?? '';
};
case 'duration':
return static function ($value) use ($key) {
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.aside_activity.' . $key;
}
@@ -112,7 +108,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
return '';
}
if ($value instanceof DateTimeInterface) {
if ($value instanceof \DateTimeInterface) {
return $value->format('H:i:s');
}
@@ -122,7 +118,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
case 'createdAt':
case 'updatedAt':
case 'date':
return $this->dateTimeHelper->getLabel('export.aside_activity.' . $key);
return $this->dateTimeHelper->getLabel('export.aside_activity.'.$key);
case 'agent_id':
case 'creator_id':
@@ -169,7 +165,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
};
default:
throw new LogicException('this key is not supported : ' . $key);
throw new \LogicException('this key is not supported : ' . $key);
}
}
@@ -186,7 +182,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
'aside_activity_type',
'date',
'duration',
'note',
'note'
];
}
@@ -199,11 +195,6 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
}
public function getTitle()
{
return 'export.aside_activity.List of aside activities';
}
public function getType(): string
{
return Declarations::ASIDE_ACTIVITY_TYPE;
@@ -213,7 +204,8 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
{
$qb = $this->em->createQueryBuilder()
->from(AsideActivity::class, 'aside')
->leftJoin('aside.agent', 'agent');
->leftJoin('aside.agent', 'agent')
;
$qb
->addSelect('aside.id AS id')
@@ -226,7 +218,8 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
->addSelect('IDENTITY(aside.type) AS aside_activity_type')
->addSelect('aside.date')
->addSelect('aside.duration')
->addSelect('aside.note');
->addSelect('aside.note')
;
return $qb;
}

View File

@@ -17,6 +17,7 @@ use Chill\MainBundle\Form\Type\Export\FilterType;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;

View File

@@ -15,6 +15,7 @@ use Chill\AsideActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\MainBundle\Templating\Entity\UserRender;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;

View File

@@ -30,7 +30,7 @@ class ChargeKindType extends AbstractType
])
->add('kind', TextType::class, [
'label' => 'budget.admin.form.Charge_kind_key',
'help' => 'budget.admin.form.This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document',
'help' => 'budget.admin.form.This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document'
])
->add('ordering', NumberType::class)
->add('isActive', CheckboxType::class, [

View File

@@ -30,7 +30,7 @@ class ResourceKindType extends AbstractType
])
->add('kind', TextType::class, [
'label' => 'budget.admin.form.Resource_kind_key',
'help' => 'budget.admin.form.This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document',
'help' => 'budget.admin.form.This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document'
])
->add('ordering', NumberType::class)
->add('isActive', CheckboxType::class, [

View File

@@ -49,7 +49,8 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
->where($qb->expr()->eq('c.isActive', 'true'))
->orderBy('c.ordering', 'ASC')
->getQuery()
->getResult();
->getResult()
;
}
/**

View File

@@ -28,6 +28,8 @@ interface ChargeKindRepositoryInterface extends ObjectRepository
*/
public function findAllActive(): array;
public function findOneByKind(string $kind): ?ChargeKind;
/**
* @return ChargeType[]
*/
@@ -43,7 +45,5 @@ interface ChargeKindRepositoryInterface extends ObjectRepository
public function findOneBy(array $criteria): ?ChargeKind;
public function findOneByKind(string $kind): ?ChargeKind;
public function getClassName(): string;
}

View File

@@ -49,7 +49,8 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
->where($qb->expr()->eq('r.isActive', 'true'))
->orderBy('r.ordering', 'ASC')
->getQuery()
->getResult();
->getResult()
;
}
/**

View File

@@ -34,7 +34,7 @@ class ResourceRepository extends EntityRepository
//->andWhere('c.startDate < :date')
// TODO: there is a misconception here, the end date must be lower or null. startDate are never null
//->andWhere('c.startDate < :date OR c.startDate IS NULL');
;
;
if (null !== $sort) {
$qb->orderBy($sort);

View File

@@ -13,7 +13,9 @@ namespace Chill\BudgetBundle\Service\Summary;
use Chill\BudgetBundle\Entity\ChargeKind;
use Chill\BudgetBundle\Entity\ResourceKind;
use Chill\BudgetBundle\Repository\ChargeKindRepository;
use Chill\BudgetBundle\Repository\ChargeKindRepositoryInterface;
use Chill\BudgetBundle\Repository\ResourceKindRepository;
use Chill\BudgetBundle\Repository\ResourceKindRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\Household\Household;

View File

@@ -20,15 +20,12 @@ use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person;
use DateTimeImmutable;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use ReflectionClass;
use RuntimeException;
/**
* @internal
@@ -50,9 +47,10 @@ final class SummaryBudgetTest extends TestCase
],
]);
$queryCharges->setParameters(Argument::type('array'))
->will(static function ($args, $query) {
->will(function ($args, $query) {
return $query;
});
})
;
$queryResources = $this->prophesize(AbstractQuery::class);
$queryResources->getResult()->willReturn([
@@ -63,23 +61,23 @@ final class SummaryBudgetTest extends TestCase
],
]);
$queryResources->setParameters(Argument::type('array'))
->will(static function ($args, $query) {
->will(function ($args, $query) {
return $query;
});
})
;
$em = $this->prophesize(EntityManagerInterface::class);
$em->createNativeQuery(Argument::type('string'), Argument::type(Query\ResultSetMapping::class))
->will(static function ($args) use ($queryResources, $queryCharges) {
->will(function ($args) use ($queryResources, $queryCharges) {
if (false !== strpos($args[0], 'chill_budget.resource')) {
return $queryResources->reveal();
}
if (false !== strpos($args[0], 'chill_budget.charge')) {
return $queryCharges->reveal();
}
throw new RuntimeException('this query does not have a stub counterpart: ' . $args[0]);
});
throw new \RuntimeException('this query does not have a stub counterpart: '.$args[0]);
})
;
$chargeRepository = $this->prophesize(ChargeKindRepositoryInterface::class);
$chargeRepository->findAll()->willReturn([
@@ -100,23 +98,24 @@ final class SummaryBudgetTest extends TestCase
$resourceRepository->findOneByKind('misc')->willReturn($misc);
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($arg) {
$translatableStringHelper->localize(Argument::type('array'))->will(function ($arg) {
return $arg[0]['fr'];
});
$person = new Person();
$personReflection = new ReflectionClass($person);
$personReflection = new \ReflectionClass($person);
$personIdReflection = $personReflection->getProperty('id');
$personIdReflection->setAccessible(true);
$personIdReflection->setValue($person, 1);
$household = new Household();
$householdReflection = new ReflectionClass($household);
$householdReflection = new \ReflectionClass($household);
$householdId = $householdReflection->getProperty('id');
$householdId->setAccessible(true);
$householdId->setValue($household, 1);
$householdMember = (new HouseholdMember())->setPerson($person)
->setStartDate(new DateTimeImmutable('1 month ago'));
->setStartDate(new \DateTimeImmutable('1 month ago'))
;
$household->addMember($householdMember);
$summaryBudget = new SummaryBudget(

View File

@@ -2,13 +2,6 @@
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\Budget;
use Doctrine\DBAL\Schema\Schema;
@@ -16,12 +9,6 @@ use Doctrine\Migrations\AbstractMigration;
final class Version20230209161546 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->addSql('DROP INDEX resource_kind_unique_type_idx');
$this->addSql('DROP INDEX charge_kind_unique_type_idx');
}
public function getDescription(): string
{
return 'Budget: add unique constraint on kind for charge_kind and resource_kind';
@@ -34,4 +21,10 @@ final class Version20230209161546 extends AbstractMigration
$this->addSql('CREATE UNIQUE INDEX resource_kind_unique_type_idx ON chill_budget.resource_type (kind);');
$this->addSql('CREATE UNIQUE INDEX charge_kind_unique_type_idx ON chill_budget.charge_type (kind);');
}
public function down(Schema $schema): void
{
$this->addSql('DROP INDEX resource_kind_unique_type_idx');
$this->addSql('DROP INDEX charge_kind_unique_type_idx');
}
}

View File

@@ -2,8 +2,8 @@ Budget: Budget
Resource: Inkomsten
Charge: Onkosten
Budget for %name%: Budget van %name%
Budget for household %household%: Budget van huishouden
Current budget household members: Actuele budget van leden huishouden
Budget for household %household%: Budget van gezin
Current budget household members: Actuele budget van gezinsleden
Show budget of %name%: Toon budget van %name%
See complete budget: Toon volledige budget
Hide budget: Verbergen

View File

@@ -22,7 +22,6 @@ use Chill\MainBundle\Entity\User;
use DateTimeImmutable;
use LogicException;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use function array_key_exists;
@@ -75,18 +74,9 @@ class MapCalendarToUser
public function getDefaultUserCalendar(string $idOrUserPrincipalName): ?array
{
try {
$value = $this->machineHttpClient->request('GET', "users/{$idOrUserPrincipalName}/calendars", [
'query' => ['$filter' => 'isDefaultCalendar eq true'],
])->toArray()['value'];
} catch (ClientExceptionInterface $e) {
$this->logger->error('[MapCalendarToUser] Error while listing calendars for a user', [
'http_status_code' => $e->getResponse()->getStatusCode(),
'id_user' => $idOrUserPrincipalName,
]);
return null;
}
$value = $this->machineHttpClient->request('GET', "users/{$idOrUserPrincipalName}/calendars", [
'query' => ['$filter' => 'isDefaultCalendar eq true'],
])->toArray()['value'];
return $value[0] ?? null;
}

View File

@@ -34,7 +34,6 @@ use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -65,8 +64,6 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
private OnBehalfOfUserHttpClient $userHttpClient;
private Security $security;
public function __construct(
CalendarRepository $calendarRepository,
CalendarRangeRepository $calendarRangeRepository,
@@ -77,8 +74,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
OnBehalfOfUserHttpClient $userHttpClient,
RemoteEventConverter $remoteEventConverter,
TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator,
Security $security
UrlGeneratorInterface $urlGenerator
) {
$this->calendarRepository = $calendarRepository;
$this->calendarRangeRepository = $calendarRangeRepository;
@@ -90,7 +86,6 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
$this->translator = $translator;
$this->urlGenerator = $urlGenerator;
$this->userHttpClient = $userHttpClient;
$this->security = $security;
}
public function countEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): int
@@ -138,24 +133,6 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
public function isReady(): bool
{
$user = $this->security->getUser();
if (!$user instanceof User) {
// this is not a user from chill. This is not the role of this class to
// restrict access, so we will just say that we do not have to do anything more
// here...
return true;
}
if (null === $this->mapCalendarToUser->getUserId($user)) {
// this user is not mapped with remote calendar. The user will have to wait for
// the next calendar subscription iteration
$this->logger->debug('mark user ready for msgraph calendar as he does not have any mapping', [
'userId' => $user->getId(),
]);
return true;
}
return $this->tokenStorage->hasToken();
}

View File

@@ -156,7 +156,7 @@ final class CalendarContext implements CalendarContextInterface
$options = $this->getOptions($template);
$data = array_merge(
$this->baseContextData->getData($contextGenerationData['creator'] ?? null),
$this->baseContextData->getData(),
[
'calendar' => $this->normalizer->normalize($entity, 'docgen', ['docgen:expects' => Calendar::class, 'groups' => ['docgen:read']]),
]

View File

@@ -205,7 +205,7 @@ final class CalendarContextTest extends TestCase
?NormalizerInterface $normalizer = null
): CalendarContext {
$baseContext = $this->prophesize(BaseContextData::class);
$baseContext->getData(null)->willReturn(['base_context' => 'data']);
$baseContext->getData()->willReturn(['base_context' => 'data']);
$personRender = $this->prophesize(PersonRender::class);
$personRender->renderString(Argument::type(Person::class), [])->willReturn('person name');

View File

@@ -39,7 +39,6 @@ use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use function strlen;
use const JSON_PRETTY_PRINT;
final class DocGeneratorTemplateController extends AbstractController
{
@@ -256,7 +255,7 @@ final class DocGeneratorTemplateController extends AbstractController
// if is test, render the data or generate the doc
if ($isTest && isset($form) && $form['show_data']->getData()) {
return $this->render('@ChillDocGenerator/Generator/debug_value.html.twig', [
'datas' => json_encode($context->getData($template, $entity, $contextGenerationData), JSON_PRETTY_PRINT),
'datas' => json_encode($context->getData($template, $entity, $contextGenerationData), JSON_PRETTY_PRINT)
]);
} elseif ($isTest) {
$generated = $this->generator->generateDocFromTemplate(

View File

@@ -21,14 +21,18 @@ class BaseContextData
{
private NormalizerInterface $normalizer;
public function __construct(NormalizerInterface $normalizer)
private Security $security;
public function __construct(Security $security, NormalizerInterface $normalizer)
{
$this->security = $security;
$this->normalizer = $normalizer;
}
public function getData(?User $user = null): array
public function getData(): array
{
$data = [];
$user = $this->security->getUser();
$data['creator'] = $this->normalizer->normalize(
$user instanceof User ? $user : null,

View File

@@ -9,7 +9,6 @@ use Chill\DocGeneratorBundle\GeneratorDriver\DriverInterface;
use Chill\DocGeneratorBundle\GeneratorDriver\Exception\TemplateException;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\File\File;
@@ -56,8 +55,7 @@ class Generator implements GeneratorInterface
array $contextGenerationDataNormalized,
?StoredObject $destinationStoredObject = null,
bool $isTest = false,
?File $testFile = null,
?User $creator = null
?File $testFile = null
): ?string {
if ($destinationStoredObject instanceof StoredObject && StoredObject::STATUS_PENDING !== $destinationStoredObject->getStatus()) {
$this->logger->info(self::LOG_PREFIX.'Aborting generation of an already generated document');
@@ -82,7 +80,6 @@ class Generator implements GeneratorInterface
$contextGenerationDataNormalized = array_merge(
$contextGenerationDataNormalized,
['creator' => $creator],
$context instanceof DocGeneratorContextWithPublicFormInterface ?
$context->contextGenerationDataDenormalize($template, $entity, $contextGenerationDataNormalized)
: []

View File

@@ -1,34 +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\DocGeneratorBundle\Service\Generator;
use RuntimeException;
use Throwable;
class GeneratorException extends RuntimeException
class GeneratorException extends \RuntimeException
{
/**
* @var list<string>
*/
private array $errors;
public function __construct(array $errors = [], ?Throwable $previous = null)
public function __construct(array $errors = [], \Throwable $previous = null)
{
$this->errors = $errors;
parent::__construct(
'Could not generate the document',
15252,
$previous
);
parent::__construct("Could not generate the document", 15252,
$previous);
}
/**

View File

@@ -4,7 +4,6 @@ namespace Chill\DocGeneratorBundle\Service\Generator;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Entity\User;
use Symfony\Component\HttpFoundation\File\File;
interface GeneratorInterface
@@ -23,7 +22,6 @@ interface GeneratorInterface
array $contextGenerationDataNormalized,
?StoredObject $destinationStoredObject = null,
bool $isTest = false,
?File $testFile = null,
?User $creator = null
?File $testFile = null
): ?string;
}

View File

@@ -1,22 +1,11 @@
<?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\DocGeneratorBundle\Service\Generator;
use RuntimeException;
class ObjectReadyException extends RuntimeException
class ObjectReadyException extends \RuntimeException
{
public function __construct()
{
parent::__construct('object is already ready', 6698856);
parent::__construct("object is already ready", 6698856);
}
}

View File

@@ -1,26 +1,14 @@
<?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\DocGeneratorBundle\Service\Generator;
use RuntimeException;
class RelatedEntityNotFoundException extends RuntimeException
class RelatedEntityNotFoundException extends \RuntimeException
{
public function __construct(string $relatedEntityClass, int $relatedEntityId, ?Throwable $previous = null)
public function __construct(string $relatedEntityClass, int $relatedEntityId, Throwable $previous = null)
{
parent::__construct(
sprintf('Related entity not found: %s, %s', $relatedEntityClass, $relatedEntityId),
sprintf("Related entity not found: %s, %s", $relatedEntityClass, $relatedEntityId),
99876652,
$previous
);
$previous);
}
}

View File

@@ -6,9 +6,7 @@ use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
use Chill\DocGeneratorBundle\Service\Generator\Generator;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\StoredObjectRepository;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
@@ -25,28 +23,18 @@ class RequestGenerationHandler implements MessageHandlerInterface
private Generator $generator;
private LoggerInterface $logger;
private UserRepositoryInterface $userRepository;
public const AUTHORIZED_TRIALS = 5;
private const LOG_PREFIX = '[docgen message handler] ';
public function __construct(
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
EntityManagerInterface $entityManager,
Generator $generator,
LoggerInterface $logger,
StoredObjectRepository $storedObjectRepository,
UserRepositoryInterface $userRepository
StoredObjectRepository $storedObjectRepository
) {
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
$this->entityManager = $entityManager;
$this->generator = $generator;
$this->logger = $logger;
$this->storedObjectRepository = $storedObjectRepository;
$this->userRepository = $userRepository;
}
public function __invoke(RequestGenerationMessage $message)
@@ -63,8 +51,6 @@ class RequestGenerationHandler implements MessageHandlerInterface
throw new UnrecoverableMessageHandlingException('maximum number of retry reached');
}
$creator = $this->userRepository->find($message->getCreatorId());
$destinationStoredObject->addGenerationTrial();
$this->entityManager->createQuery('UPDATE '.StoredObject::class.' s SET s.generationTrialsCounter = s.generationTrialsCounter + 1 WHERE s.id = :id')
->setParameter('id', $destinationStoredObject->getId())
@@ -74,16 +60,7 @@ class RequestGenerationHandler implements MessageHandlerInterface
$template,
$message->getEntityId(),
$message->getContextGenerationData(),
$destinationStoredObject,
false,
null,
$creator
$destinationStoredObject
);
$this->logger->info(self::LOG_PREFIX.'Request generation finished', [
'template_id' => $message->getTemplateId(),
'destination_stored_object' => $message->getDestinationStoredObjectId(),
'duration_int' => (new \DateTimeImmutable('now'))->getTimestamp() - $message->getCreatedAt()->getTimestamp(),
]);
}
}

View File

@@ -18,8 +18,6 @@ class RequestGenerationMessage
private array $contextGenerationData;
private \DateTimeImmutable $createdAt;
public function __construct(
User $creator,
DocGeneratorTemplate $template,
@@ -32,7 +30,6 @@ class RequestGenerationMessage
$this->entityId = $entityId;
$this->destinationStoredObjectId = $destinationStoredObject->getId();
$this->contextGenerationData = $contextGenerationData;
$this->createdAt = new \DateTimeImmutable('now');
}
public function getCreatorId(): int
@@ -59,9 +56,4 @@ class RequestGenerationMessage
{
return $this->contextGenerationData;
}
public function getCreatedAt(): \DateTimeImmutable
{
return $this->createdAt;
}
}

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="'ready' === props.storedObject.status" class="btn-group">
<div v-if="'ready' === props.storedObject.status" class="dropdown">
<button :class="Object.assign({'btn': true, 'btn-outline-primary': true, 'dropdown-toggle': true, 'btn-sm': props.small})" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Actions
</button>

View File

@@ -38,11 +38,13 @@ async function download_and_open(event: Event): Promise<void> {
button.href = window.URL.createObjectURL(raw);
button.type = props.storedObject.type;
button.download = props.filename || 'document';
if (props.filename !== undefined) {
button.download = props.filename || 'document';
const ext = mime.getExtension(props.storedObject.type);
if (null !== ext) {
button.download = button.download + '.' + ext;
const ext = mime.getExtension(props.storedObject.type);
if (null !== ext) {
button.download = button.download + '.' + ext;
}
}
}

View File

@@ -19,9 +19,6 @@ The document is successfully registered: Le document est enregistré
The document is successfully updated: Le document est mis à jour
Any description: Aucune description
document:
Any title: Aucun titre
# delete
Delete document ?: Supprimer le document ?
Are you sure you want to remove this document ?: Êtes-vous sûr·e de vouloir supprimer ce document ?
@@ -76,4 +73,4 @@ CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE: Créer un document
CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE: Supprimer un document
CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE: Voir les documents
CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS: Voir les détails d'un document
CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE: Modifier un document
CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE: Modifier un document

View File

@@ -28,7 +28,7 @@ class LocationController extends CRUDController
protected function customizeQuery(string $action, Request $request, $query): void
{
$query->where('e.availableForUsers = TRUE');
$query->where('e.availableForUsers = "TRUE"');
}
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Export;
use Closure;
use Doctrine\ORM\QueryBuilder;
/**

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Export\Helper;
use DateTime;
use DateTimeInterface;
use Exception;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -36,7 +35,7 @@ class DateTimeHelper
return '';
}
if ($value instanceof DateTimeInterface) {
if ($value instanceof \DateTimeInterface) {
return $value;
}

View File

@@ -17,7 +17,6 @@ use Chill\MainBundle\Repository\RegroupmentRepository;
use Exception;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\FormInterface;
use function array_key_exists;
use function count;
class ExportPickCenterDataMapper implements DataMapperInterface
@@ -30,7 +29,7 @@ class ExportPickCenterDataMapper implements DataMapperInterface
*
* @throws Exception
*
* @return void
* @return mixed
*/
public function mapDataToForms($data, $forms)
{
@@ -73,12 +72,10 @@ class ExportPickCenterDataMapper implements DataMapperInterface
$centers[spl_object_hash($center)] = $center;
}
if (array_key_exists('regroupment', $forms)) {
foreach ($forms['regroupment']->getData() as $regroupment) {
/** @var Regroupment $regroupment */
foreach ($regroupment->getCenters() as $center) {
$centers[spl_object_hash($center)] = $center;
}
foreach ($forms['regroupment']->getData() as $regroupment) {
/** @var Regroupment $regroupment */
foreach ($regroupment->getCenters() as $center) {
$centers[spl_object_hash($center)] = $center;
}
}

View File

@@ -233,7 +233,7 @@ export default {
// console.log('data original', data);
data.parent = {type: "thirdparty", id: this.parent.id};
data.civility = data.civility !== null ? {type: 'chill_main_civility', id: data.civility.id} : null;
data.profession = data.profession !== '' ? data.profession : '';
data.profession = data.profession !== null ? {type: 'third_party_profession', id: data.profession.id} : null;
} else {
type = this.$refs.castNew.radioType;
data = this.$refs.castNew.castDataByType();
@@ -241,8 +241,8 @@ export default {
if (typeof data.civility !== 'undefined' && null !== data.civility) {
data.civility = data.civility !== null ? {type: 'chill_main_civility', id: data.civility.id} : null;
}
if (typeof data.profession !== 'undefined' && '' !== data.profession) {
data.profession = data.profession !== '' ? data.profession : '';
if (typeof data.profession !== 'undefined' && null !== data.profession) {
data.profession = data.profession !== null ? {type: 'third_party_profession', id: data.profession.id} : null;
}
// console.log('onthefly data', data);
}

View File

@@ -72,7 +72,7 @@
</div>
</div>
<div class="item-row column">
<table class="obj-res-eval smallfont my-3">
<table class="obj-res-eval my-3">
<thead>
<tr><th class="obj"><h4 class="title_label">Objectif - motif - dispositif</h4></th>
<th class="res"><h4 class="title_label">Résultats - orientations</h4></th>

View File

@@ -253,8 +253,8 @@ No options availables. Your report is fully configured.: Geen beschikbare opties
Ungrouped exports: Overige expor
#export download
Download export: Downloaden van rapport
Waiting for your report: Wachten op je rapport
Download export: Téléchargement du rapport
Waiting for your report: En attente de votre rapport
Download your report: Télécharger votre rapport
Problem during download: Problème durant le téléchargement
# sans valeur

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;

View File

@@ -20,6 +20,9 @@ div.accompanying-course-work {
margin: 0;
}
}
td {
font-size: 85%;
}
td.obj,
td.res {
width: 50%;
@@ -34,10 +37,6 @@ div.accompanying-course-work {
}
}
.smallfont table.obj-res-eval {
font-size: 85%;
}
ul {
&.goal_title,
&.result_list,

View File

@@ -2,29 +2,6 @@
<div class="vue-component">
<h2><a id="section-80"></a>{{ $t('referrer.title') }}</h2>
<teleport to="body">
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="cancelChange">
<template v-slot:header>
<h3 class="modal-title">{{ $t('confirm.title') }}</h3>
</template>
<template v-slot:body-head>
<div class="modal-body">
<p v-html="$t('confirm.sure_referrer', { referrer: this.value.text })"></p>
</div>
</template>
<template v-slot:footer>
<button class="btn btn-save"
@click.prevent="this.confirmReferrer">
{{ $t('confirm.ok_referrer')}}
</button>
</template>
</modal>
</teleport>
<div>
<label class="col-form-label" for="selectJob">
@@ -58,8 +35,6 @@
:searchable="true"
:placeholder="$t('referrer.placeholder')"
v-model="value"
@select="updateReferrer"
@remove="removeReferrer"
:options="users"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
@@ -103,24 +78,16 @@ import VueMultiselect from 'vue-multiselect';
import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods';
import {mapState, mapGetters} from 'vuex';
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
export default {
name: "Referrer",
components: {
UserRenderBoxBadge,
VueMultiselect,
Modal
},
data() {
return {
jobs: [],
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
},
value: this.$store.state.accompanyingCourse.user,
confirmed: false
jobs: []
}
},
computed: {
@@ -151,6 +118,22 @@ export default {
});
}
},
value: {
get() {
return this.$store.state.accompanyingCourse.user;
},
set(value) {
console.log('set referrer', value);
this.$store.dispatch('updateReferrer', value)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
}
},
},
mounted() {
this.getJobs();
@@ -158,7 +141,6 @@ export default {
methods: {
updateReferrer(value) {
this.value = value;
this.toggleModal();
},
getJobs() {
const url = '/api/1.0/main/user-job.json';
@@ -177,38 +159,12 @@ export default {
const url = `/api/1.0/main/whoami.json`;
makeFetch('GET', url)
.then(user => {
// this.value = user
this.updateReferrer(user);
this.value = user
})
},
toggleModal() {
this.modal.showModal = !this.modal.showModal;
},
confirmReferrer() {
this.$store.dispatch('updateReferrer', this.value)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
this.toggleModal()
},
removeReferrer() {
console.log('remove option')
this.$store.dispatch('updateReferrer', null)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
},
cancelChange() {
this.value = this.$store.state.accompanyingCourse.user
this.toggleModal()
/*.catch((error) => {
commit('catchError', error);
this.$toast.open({message: error.body})
})*/
}
}
}

View File

@@ -178,7 +178,7 @@ export default {
body.civility = {type: 'chill_main_civility', id: payload.data.civility.id};
}
if (null !== payload.data.profession) {
body.profession = payload.data.profession;
body.profession = {type: 'third_party_profession', id: payload.data.profession.id};
}
// console.log('body', body);

View File

@@ -139,10 +139,8 @@ const appMessages = {
set_a_scope: "indiquez au moins un service",
sure: "Êtes-vous sûr ?",
sure_description: "Une fois le changement confirmé, il ne sera plus possible de le remettre à l'état de brouillon !",
sure_referrer: "Êtes-vous sûr de vouloir assigner ce parcours à <b>{referrer}</b>",
ok: "Confirmer le parcours",
delete: "Supprimer le parcours",
ok_referrer: "Confirmer le référent",
no_suggested_referrer: "Il n'y a aucun référent qui puisse être suggéré pour ce parcours. Vérifiez la localisation du parcours, les métiers et service indiqués. Si les données sont correctes, vous pouvez confirmer ce parcours.",
one_suggested_referrer: "Un unique référent peut être suggéré pour ce parcours",
choose_suggested_referrer: "Voulez-vous le désigner directement ?",

View File

@@ -1,7 +1,7 @@
<template>
<div class="container tpartycontainer">
<div class="tparty-identification">
<span v-if="item.result.profession" class="profession">{{ item.result.profession }}</span>
<span v-if="item.result.profession" class="profession">{{ item.result.profession.name.fr }}</span>
<span class="name">
{{ item.result.text }}&nbsp;
</span>

View File

@@ -3,7 +3,6 @@
# - itemBlocClass: [uniq|colored|extended]
# - displayContent: [short|long] default: short
# - displayAction: [true|false] default: false
# - displayFontSmall: [true|false] default: false
#}
<div class="item-bloc{% if displayContent is defined %} {{ displayContent }}{% endif %}{% if itemBlocClass is defined %} {{ itemBlocClass }}{% endif %}">
@@ -84,7 +83,7 @@
{%- if w.referrers|length > 0 -%}
{% for u in w.referrers %}
<span class="wl-item">
<span class="badge-user">{{ u|chill_entity_render_box }}</span>
{{ u|chill_entity_render_box }}
{% if not loop.last %}, {% endif %}
</span>
{% endfor %}
@@ -111,7 +110,7 @@
</div>
{% if displayContent is not defined or displayContent == 'short' %}
<div class="item-row column{% if displayFontSmall is defined and displayFontSmall == true %} smallfont{% endif %}">
<div class="item-row column">
{% include 'ChillPersonBundle:AccompanyingCourseWork:_objectifs_results_evaluations.html.twig' with {
'displayContent': displayContent
} %}

View File

@@ -130,20 +130,27 @@
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
{% if e.documents|length > 0 %}
<table class="table mt-4 mx-auto">
<div class="download mb-4 container">
{% if e.documents|length > 0 %}
{% for d in e.documents %}
<tr class="border-0">
<td class="border-0">{{ d.title }}</td>
<td class="border-0">{{ mm.mimeIcon(d.storedObject.type) }}</td>
<td class="border-0 text-end">{{ d.storedObject|chill_document_button_group(d.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w), {'small': true}) }}</td>
</tr>
<div class="row">
<div class="col text-start">
{{ d.title }}
</div>
<div class="col-md-auto text-center">
{{ mm.mimeIcon(d.storedObject.type) }}
</div>
<div class="col col-lg-4 text-end">
{{ d.storedObject|chill_document_button_group(d.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w), {'small': true}) }}
</div>
</div>
{% endfor %}
</table>
{% else %}
<span class="chill-no-data-statement">{{ 'No document found'|trans }}</span>
{% endif %}
{% else %}
<span class="chill-no-data-statement">{{ 'No document found'|trans }}</span>
{% endif %}
</div>
{% endif %}
</td>

View File

@@ -25,7 +25,6 @@
{% include '@ChillPerson/AccompanyingCourseWork/_item.html.twig' with {
'displayAction': true,
'displayContent': 'short',
'displayFontSmall': true,
'itemBlocClass': ''
} %}
{% endfor %}

View File

@@ -33,10 +33,8 @@
<span class="item-key">{{ 'Referrers'|trans ~ ' : ' }}</span>
{% for u in w.referrers %}
<span class="badge-user">{{ u|chill_entity_render_box }}</span>
{% if not loop.last %}, {% endif %}
{% endfor %}
{% if w.referrers|length == 0 %}
<span class="chill-no-data-statement">{{ 'Not given'|trans }}</span>
{% endif %}
</li>
{% endif %}
<li class="associated-persons">

View File

@@ -3,7 +3,6 @@
#}{{ period.user.label }},
L'usager {{ oldPersonLocation|chill_entity_render_string }} a déménagé.
{{ app.user|chill_entity_render_string }} a enregistré ce déménagement.
Son adresse était utilisée pour localiser le parcours n°{{ period.id }}, dont vous êtes
le référent.

View File

@@ -69,7 +69,7 @@
</div>
<div class="wl-col list">
<div class="user">
<span class="badge-user">{{ acp.user|chill_entity_render_box }}</span>
{{ acp.user|chill_entity_render_box }}
</div>
</div>
</div>

View File

@@ -21,7 +21,7 @@
</h2>
</div>
<div class="item-row column">
<table class="obj-res-eval my-3">
<table class="obj-res-eval my-3" style="font-size: 110% !important;">
<thead>
<tr>
<th class="eval">

View File

@@ -49,7 +49,7 @@
</div>
</div>
<div class="item-row column">
<table class="obj-res-eval my-3">
<table class="obj-res-eval my-3" style="font-size: 110% !important;">
<thead>
<tr>
<th class="eval">

View File

@@ -76,17 +76,8 @@ class SimilarPersonMatcher
$qb->select('p')
->from(Person::class, 'p')
->join('p.centerHistory', 'center_history')
->where('SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) >= :precision')
->andWhere($qb->expr()->in('center_history.center', ':centers'))
->andWhere($qb->expr()->andX(
$qb->expr()->lte('center_history.startDate', 'CURRENT_DATE()'),
$qb->expr()->orX(
$qb->expr()->isNull('center_history.endDate'),
$qb->expr()->gt('center_history.endDate', 'CURRENT_DATE()')
)
))
;
->andWhere($qb->expr()->in('p.center', ':centers'));
$qb
->setParameter('fullName', $this->personRender->renderString($person, []))
@@ -126,6 +117,7 @@ class SimilarPersonMatcher
$qb->setParameter('fullName', $this->personRender->renderString($person, []));
}
dump($qb->getQuery());
return $qb->getQuery()->getResult();
}
}

View File

@@ -204,7 +204,7 @@ class AccompanyingPeriodContext implements
$options = $template->getOptions();
$data = [];
$data = array_merge($data, $this->baseContextData->getData($contextGenerationData['creator'] ?? null));
$data = array_merge($data, $this->baseContextData->getData());
$data['course'] = $this->normalizer->normalize($entity, 'docgen', ['docgen:expects' => AccompanyingPeriod::class, 'groups' => 'docgen:read']);
foreach (['mainPerson', 'person1', 'person2'] as $k) {

View File

@@ -165,7 +165,7 @@ final class PersonContext implements PersonContextInterface
}
$data = [];
$data = array_merge($data, $this->baseContextData->getData($contextGenerationData['creator'] ?? null));
$data = array_merge($data, $this->baseContextData->getData());
$data['person'] = $this->normalizer->normalize($entity, 'docgen', [
'docgen:expects' => Person::class,
'groups' => ['docgen:read'],

View File

@@ -24,36 +24,10 @@ use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
/**
* @internal
* @coversNothing
*/
final class ParticipationOverlapValidatorTest extends ConstraintValidatorTestCase
class ParticipationOverlapValidatorTest extends ConstraintValidatorTestCase
{
use ProphecyTrait;
/**
* @return mixed
*/
public function getConstraint()
{
return new ParticipationOverlap();
}
public function testOneParticipation()
{
$period = new AccompanyingPeriod();
$person = new Person();
$collection = new ArrayCollection([
new AccompanyingPeriodParticipation($period, $person),
]);
$this->validator->validate($collection, $this->getConstraint());
$this->assertNoViolation();
}
protected function createValidator()
{
$personRender = $this->prophesize(PersonRenderInterface::class);
@@ -63,4 +37,26 @@ final class ParticipationOverlapValidatorTest extends ConstraintValidatorTestCas
return new ParticipationOverlapValidator($personRender->reveal(), $thirdPartyRender->reveal());
}
public function testOneParticipation()
{
$period = new AccompanyingPeriod();
$person = new Person();
$collection = new ArrayCollection([
new AccompanyingPeriodParticipation($period, $person)
]);
$this->validator->validate($collection, $this->getConstraint());
$this->assertNoViolation();
}
/**
* @return mixed
*/
public function getConstraint()
{
return new ParticipationOverlap();
}
}

View File

@@ -54,7 +54,7 @@ class AccompanyingPeriodValidityValidator extends ConstraintValidator
$activities = $this->activityRepository->findBy(['accompanyingPeriod' => $period]);
foreach ($activities as $activity) {
$socialIssues = array_merge($socialIssues, $activity->getSocialIssues()->toArray());
$socialIssues = $activity->getSocialIssues()->toArray();
}
foreach ($period->getWorks() as $work) {
@@ -64,7 +64,7 @@ class AccompanyingPeriodValidityValidator extends ConstraintValidator
$socialIssuesByKey = [];
foreach ($socialIssues as $si) {
$socialIssuesByKey[spl_object_hash($si)] = $si;
$socialIssuesByKey[$si->getId()] = $si;
}
$periodIssuesWithAncestors = [];
@@ -75,7 +75,7 @@ class AccompanyingPeriodValidityValidator extends ConstraintValidator
$periodIssuesWithAncestors,
array_map(
static function (SocialIssue $si) {
return spl_object_hash($si);
return $si->getId();
},
$si->getAncestors(true)
)

View File

@@ -125,7 +125,7 @@ address_country_code: Landscode
'Alreay existing person': 'Reeds bestaand persoonsdossier'
'Add the person': 'Persoon toevoegen'
'Add the person and create an accompanying period': "Persoon & hulpverleningstraject aanmaken"
'Add the person and create a household': "Persoon & huishouden aanmaken"
'Add the person and create a household': "Persoon & gezin aanmaken"
Show person: Toon persoonsdossier
'Confirm the creation': 'Aanmaak dossier bevestigen'
'You will create this person': 'U zal het volgende dossier aanmaken'
@@ -177,9 +177,9 @@ An accompanying period ends: Een hulpverleningstraject loopt op zijn einde
An accompanying period starts: Een hulpverleningstraject gaat van start
Any accompanying periods are open: Geen enkel hulpverleningstraject open
An accompanying period is open: Een hulpverleningstraject staat open
Accompanying period list: Hulpverleningstrajecten
Accompanying period list: Hulpverleningstraject
Accompanying period list for person: Hulpverleningstrajecten van persoon
Accompanying period: Hulpverleningstrajecten
Accompanying period: Hulpverleningstraject
Any accompanying period: Geen enkel hulpverleningstraject
period: Hulpverleningstraject
New accompanying course: Nieuw hulpverleningstraject
@@ -215,8 +215,8 @@ No resources: "Geen hulpverlening partners"
Persons associated: Betrokken personen
Referrer: Doorverwijzer
Referrers: Doorverwijzers
Some peoples does not belong to any household currently. Add them to an household soon: Sommige personen maken nog geen deel uit van een huishouden. Voeg ze zo snel mogelijk aan huishouden toe.
Add to household now: Toevoegen aan een huishouden
Some peoples does not belong to any household currently. Add them to an household soon: Sommige personen maken nog geen deel uit van een gezin. Voeg ze zo snel mogelijk aan gezin toe.
Add to household now: Toevoegen aan een gezin
Any resource for this accompanying course: Geen enkele hulpverlening partner
course.draft: Ontwerp
course.closed: Afgesloten
@@ -458,7 +458,7 @@ Accompanying course location: Locatie van hulpverleningstraject
This course is located by: Locatie bij
This course has a temporarily location: Voorlopige locatie
Choose a person to locate by: Adres van persoon toewijzen
Associate at least one member with an household, and set an address to this household: Associeer minstens één betrokken persoon in dit hulpverleningstraject met een huishouden en wijs een adres toe aan dit huishouden.
Associate at least one member with an household, and set an address to this household: Associeer minstens één betrokken persoon in dit hulpverleningstraject met een gezin en wijs een adres toe aan dit gezin.
Locate by: Adres toewijzen
fix it: Aanvullen
accompanying_course:
@@ -480,23 +480,23 @@ accompanying_course_comment:
Read more: Meer lezen..
# Household
Household: Huishouden
Household: Gezin
Summary: Samenvatting
Members: Leden huishouden
Members: Gezinsleden
Addresses: Addressen
Move household: Nieuwe verhuis
Addresses history for household: Historiek adressen
Household accompanying period: Hulpverleningstrajecten van huishouden
Household summary: Samenvatting huishouden
Edit household address: Adres huishouden bijwerken
Show household: huishouden bekijken
Back to household: Terugkeren naar huishouden
Remove household composition: huishoudenssamenstelling verwijderen
Are you sure you want to remove this composition?: Bent u zeker deze huishoudenssamenstelling te willen verwijderen?
Concerns household n°%id%: Betrokken huishouden n°%id%
Composition: huishoudenssamenstelling
Household accompanying period: Hulpverleningstrajecten van gezin
Household summary: Samenvatting gezin
Edit household address: Adres gezin bijwerken
Show household: Gezin bekijken
Back to household: Terugkeren naar gezin
Remove household composition: Gezinssamenstelling verwijderen
Are you sure you want to remove this composition?: Bent u zeker deze gezinssamenstelling te willen verwijderen?
Concerns household n°%id%: Betrokken gezin n°%id%
Composition: Gezinssamenstelling
Budget: Budget
The composition has been successfully removed.: De huishoudenssamenstelling werd verwijdert.
The composition has been successfully removed.: De gezinssamenstelling werd verwijdert.
# accompanying course work
Accompanying Course Actions: Hulpverleningsmaatregelen
@@ -560,16 +560,16 @@ You are getting a notification for a period you are not allowed to see: De notif
This is the minimal period details: Hulpverleningstraject n°
household_composition:
No composition yet: Geen enkele huishoudenssamenstelling toegewezen
Compositions: huishoudenssamenstelling
No composition yet: Geen enkele gezinssamenstelling toegewezen
Compositions: Gezinssamenstelling
endDate: Einddatum
numberOfChildren: Aantal kinderen in het huishouden
Household composition: huishoudenssamenstelling
Composition added: Informatie over de huishoudenssamenstelling toegevoegd
Currently no composition: Geen enkele huishoudenssamenstelling toegewezen
Add a composition: Een huishoudenssamenstelling toevoegen
Update composition: huishoudenssamenstelling bijwerken
Create: Een nieuwe huishoudenssamenstelling toewijzen
numberOfChildren: Aantal kinderen in het gezin
Household composition: Gezinssamenstelling
Composition added: Informatie over de gezinssamenstelling toegevoegd
Currently no composition: Geen enkele gezinssamenstelling toegewezen
Add a composition: Een gezinssamenstelling toevoegen
Update composition: Gezinssamenstelling bijwerken
Create: Een nieuwe gezinssamenstelling toewijzen
# docgen
Linked evaluations: Gerelateerde evaluaties

View File

@@ -11,15 +11,12 @@ declare(strict_types=1);
namespace Chill\ReportBundle\Controller;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\ReportBundle\Entity\Report;
use Chill\ReportBundle\Form\ReportType;
use Chill\ReportBundle\Security\Authorization\ReportVoter;
use DateTime;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -28,7 +25,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Security;
use function count;
/**
@@ -51,25 +48,17 @@ class ReportController extends AbstractController
*/
protected $paginator;
private CenterResolverManagerInterface $centerResolverManager;
private Security $security;
/**
* ReportController constructor.
*/
public function __construct(
EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper,
PaginatorFactory $paginator,
CenterResolverManagerInterface $centerResolverManager,
Security $security
PaginatorFactory $paginator
) {
$this->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper;
$this->paginator = $paginator;
$this->centerResolverManager = $centerResolverManager;
$this->security = $security;
}
/**
@@ -131,7 +120,7 @@ class ReportController extends AbstractController
->trans('The form is not valid. The report has not been created !')
);
return $this->render('@ChillReport/Report/new.html.twig', [
return $this->render('ChillReportBundle:Report:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
'person' => $person,
@@ -151,7 +140,7 @@ class ReportController extends AbstractController
$em = $this->getDoctrine()->getManager();
/** @var Report $report */
$report = $em->getRepository(Report::class)->find($report_id);
$report = $em->getRepository('ChillReportBundle:Report')->find($report_id);
if (!$report) {
throw $this->createNotFoundException(
@@ -200,7 +189,7 @@ class ReportController extends AbstractController
$cFGroup = $em->getRepository(\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup::class)->find($cf_group_id);
$reports = $em->getRepository('ChillReportBundle:Report')->findByCFGroup($cFGroup);
$response = $this->render('@ChillReport/Report/export.csv.twig', [
$response = $this->render('ChillReportBundle:Report:export.csv.twig', [
'reports' => $reports,
'cf_group' => $cFGroup,
]);
@@ -229,9 +218,9 @@ class ReportController extends AbstractController
$reachableScopes = $this->authorizationHelper
->getReachableScopes(
$this->security->getUser(),
ReportVoter::SEE,
$this->centerResolverManager->resolveCenters($person)
$this->getUser(),
new Role('CHILL_REPORT_SEE'),
$person->getCenter()
);
$total = $em
@@ -309,7 +298,7 @@ class ReportController extends AbstractController
$form = $this->createCreateForm($entity, $person, $cFGroup);
return $this->render('@ChillReport/Report/new.html.twig', [
return $this->render('ChillReportBundle:Report:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
'person' => $person,
@@ -526,7 +515,7 @@ class ReportController extends AbstractController
$person = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)->find($person_id);
$entity = $em->getRepository(Report::class)->find($report_id);
$entity = $em->getRepository('ChillReportBundle:Report')->find($report_id);
if (!$entity || !$person) {
throw $this->createNotFoundException(
@@ -543,7 +532,7 @@ class ReportController extends AbstractController
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('@ChillReport/Report/view.html.twig', [
return $this->render('ChillReportBundle:Report:view.html.twig', [
'entity' => $entity,
'person' => $person,
]);
@@ -589,8 +578,8 @@ class ReportController extends AbstractController
),
'method' => 'PUT',
'cFGroup' => $entity->getCFGroup(),
//'role' => ReportVoter::UPDATE,
//'center' => $this->centerResolverManager->resolveCenters($entity->getPerson()),
'role' => new Role('CHILL_REPORT_UPDATE'),
'center' => $entity->getPerson()->getCenter(),
]);
}
}

View File

@@ -74,15 +74,15 @@ class ReportType extends AbstractType
'group' => $options['cFGroup'], ]
);
//$this->appendScopeChoices(
// $builder,
// $options['role'],
// $options['center'],
// $this->user,
// $this->authorizationHelper,
// $this->translatableStringHelper,
// $this->om
//);
$this->appendScopeChoices(
$builder,
$options['role'],
$options['center'],
$this->user,
$this->authorizationHelper,
$this->translatableStringHelper,
$this->om
);
}
public function configureOptions(OptionsResolver $resolver)
@@ -97,7 +97,7 @@ class ReportType extends AbstractType
$resolver->setAllowedTypes('cFGroup', 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup');
//$this->appendScopeChoicesOptions($resolver);
$this->appendScopeChoicesOptions($resolver);
}
/**

View File

@@ -25,9 +25,7 @@
{{ form_row(edit_form.user) }}
{{ form_row(edit_form.date) }}
{#
{{ form_row(edit_form.scope) }}
#}
{{ form_row(edit_form.cFData) }}
{{ form_widget(edit_form) }}

View File

@@ -1,5 +1,7 @@
services:
Chill\ReportBundle\Controller\ReportController:
autowire: true
autoconfigure: true
arguments:
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
$paginator: '@Chill\MainBundle\Pagination\PaginatorFactory'
tags: ['controller.service_arguments']

View File

@@ -151,6 +151,21 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte
],
],
],
[
'class' => \Chill\ThirdPartyBundle\Entity\ThirdPartyProfession::class,
// 'controller' => \Chill\MainBundle\Controller\ProfessionApiController::class,
'name' => 'profession',
'base_path' => '/api/1.0/thirdparty/professions',
'base_role' => 'ROLE_USER',
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
],
],
],
],
],
]);
}

View File

@@ -250,11 +250,14 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
/**
* [fr] Qualité.
* @ORM\Column(name="profession", type="text", nullable=false)
*
* @var ThirdPartyProfession
* @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdPartyProfession")
* ORM\JoinColumn(name="profession", referencedColumnName="id", nullable=true)
* @Groups({"read", "write", "docgen:read", "docgen:read:3party:parent"})
* @Context(normalizationContext={"groups": "docgen:read"}, groups={"docgen:read:3party:parent"})
*/
private string $profession = '';
private ?ThirdPartyProfession $profession = null;
/**
* @ORM\Column(name="telephone", type="phone_number", nullable=true)
@@ -488,9 +491,9 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
}
/**
* @return string
* @return ThirdPartyProfession
*/
public function getProfession(): string
public function getProfession(): ?ThirdPartyProfession
{
return $this->profession;
}
@@ -805,9 +808,12 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
return $this;
}
public function setProfession(?string $profession): self
/**
* @return $this
*/
public function setProfession(?ThirdPartyProfession $profession): ThirdParty
{
$this->profession = (string) $profession;
$this->profession = $profession;
return $this;
}

View File

@@ -20,10 +20,14 @@ use Chill\MainBundle\Form\Type\PickCivilityType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Entity\ThirdPartyProfession;
use Chill\ThirdPartyBundle\Form\Type\PickThirdPartyTypeCategoryType;
use Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter;
use Chill\ThirdPartyBundle\ThirdPartyType\ThirdPartyTypeManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
@@ -107,10 +111,18 @@ class ThirdPartyType extends AbstractType
'placeholder' => 'thirdparty.choose civility',
'required' => false,
])
->add('profession', TextType::class, [
->add('profession', EntityType::class, [
'label' => 'thirdparty.Profession',
'class' => ThirdPartyProfession::class,
'choice_label' => function (ThirdPartyProfession $profession): string {
return $this->translatableStringHelper->localize($profession->getName());
},
'query_builder' => static function (EntityRepository $er): QueryBuilder {
return $er->createQueryBuilder('p')
->where('p.active = true');
},
'placeholder' => 'thirdparty.choose profession',
'required' => false,
'empty_data' => '',
])
->add('contactDataAnonymous', CheckboxType::class, [
'required' => false,

View File

@@ -36,7 +36,7 @@
<ul class="list-content fa-ul">
<li v-if="getProfession.length > 0">
<i class="fa fa-li fa-id-card"></i>
<p><span>{{ getProfession[0] }}</span></p>
<p><span v-for="p in getProfession" :key="p" class="list-item list-professions">{{ p[0].toUpperCase() + p.slice(1).toLowerCase() }}</span></p>
</li>
<li v-if="hasParent">
<i class="fa fa-li fa-hand-o-right"></i>
@@ -136,14 +136,13 @@ export default {
getProfession() {
let profession = []
if (this.hasParent && this.thirdparty.profession) {
profession.push(this.thirdparty.profession)
profession.push(this.thirdparty.profession.name.fr)
return profession;
}
if (!this.hasParent && this.thirdparty.category) {
profession = this.thirdparty.category.map((category) => category.text);
}
return profession;
}
/* TODO need backend normalizer to serve children without circular reference

View File

@@ -73,13 +73,13 @@
<option v-for="civility in civilities" :key="civility.id" :value="civility">{{ civility.name.fr }}</option>
</select>
</div>
<div class="input-group mb-3 input-section">
<input class="form-control form-control-lg"
v-model="thirdparty.profession"
v-bind:placeholder="$t('thirdparty.profession')"
v-bind:aria-label="$t('thirdparty.profession')"
aria-describedby="profession" />
</div>
<div class="input-group mb-3 input-section">
<select class="form-select form-select-lg" id="profession"
v-model="thirdparty.profession">
<option selected disabled :value="null">{{ $t('thirdparty.profession') }}</option>
<option v-for="profession in professions" :key="profession.id" :value="profession">{{ profession.name.fr }}</option>
</select>
</div>
</div>
<div class="child-info">
<div class="input-section">
@@ -192,8 +192,9 @@ export default {
name: '',
telephone: '',
civility: null,
profession: '',
profession: null,
},
professions: [],
civilities: [],
addAddress: {
options: {
@@ -273,6 +274,18 @@ export default {
this.$toast.open({message: error.body})
})
},
loadProfessions() {
const url = `/api/1.0/thirdparty/professions.json`;
return makeFetch('GET', url)
.then(response => {
this.$data.professions = response.results;
return Promise.resolve();
})
.catch((error) => {
console.log(error)
this.$toast.open({message: error.body})
})
},
submitAddress(payload) {
console.log('submitAddress', payload);
if (typeof payload.addressId !== 'undefined') { // <--
@@ -298,6 +311,7 @@ export default {
},
mounted() {
let dependencies = [];
dependencies.push(this.loadProfessions());
dependencies.push(this.loadCivilities());
if (this.action !== 'create') {
if (this.id) {

View File

@@ -112,3 +112,14 @@ paths:
description: "OK"
422:
description: "Object with validation errors"
/1.0/thirdparty/professions.json:
get:
tags:
- thirdparty
summary: Return all thirdparty professions
responses:
200:
description: "ok"
401:
description: "Unauthorized"

View File

@@ -7,3 +7,7 @@ services:
Chill\ThirdPartyBundle\DataFixtures\ORM\LoadThirdPartyCategory:
tags:
- { 'name': doctrine.fixture.orm }
Chill\ThirdPartyBundle\DataFixtures\ORM\LoadThirdPartyProfession:
tags:
- { 'name': doctrine.fixture.orm }

View File

@@ -1,63 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\ThirdParty;
use Chill\ThirdPartyBundle\Entity\ThirdPartyProfession;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Types;
use Doctrine\Migrations\AbstractMigration;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
final class Version20230215175150 extends AbstractMigration implements ContainerAwareInterface
{
public ContainerInterface $container;
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_3party.third_party DROP profession');
// $this->addSql('ALTER TABLE chill_3party.third_party ADD profession_id INT DEFAULT NULL');
}
public function getDescription(): string
{
return 'Change profession to a string field and transfer values';
}
/**
* @return mixed
*/
public function setContainer(?ContainerInterface $container = null)
{
$this->container = $container;
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_3party.third_party ADD profession TEXT DEFAULT \'\' NOT NULL');
$em = $this->container->get('doctrine.orm.entity_manager');
$professions = $em->getRepository(ThirdPartyProfession::class)->findAll();
foreach ($professions as $p) {
$id = $p->getId();
$name = $p->getName()['fr'];
$this->addSql(
'UPDATE chill_3party.third_party SET profession = :profession
WHERE chill_3party.third_party.profession_id = :id;',
['profession' => $name, 'id' => $id],
['profession' => Types::STRING, 'id' => Types::INTEGER]
);
}
}
}

View File

@@ -18,7 +18,6 @@ use Chill\MainBundle\Entity\User;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Mime\Part\DataPart;
@@ -41,8 +40,6 @@ class Convert
private LoggerInterface $logger;
private RequestStack $requestStack;
private Security $security;
private StoredObjectManagerInterface $storedObjectManager;
@@ -52,14 +49,12 @@ class Convert
*/
public function __construct(
HttpClientInterface $httpClient,
RequestStack $requestStack,
Security $security,
StoredObjectManagerInterface $storedObjectManager,
LoggerInterface $logger,
ParameterBagInterface $parameters
) {
$this->httpClient = $httpClient;
$this->requestStack = $requestStack;
$this->security = $security;
$this->storedObjectManager = $storedObjectManager;
$this->logger = $logger;
@@ -73,10 +68,6 @@ class Convert
}
$content = $this->storedObjectManager->read($storedObject);
$query = [];
if (null !== $request = $this->requestStack->getCurrentRequest()) {
$query['lang'] = $request->getLocale();
}
try {
$url = sprintf('%s/cool/convert-to/pdf', $this->collaboraDomain);
@@ -85,7 +76,6 @@ class Convert
]);
$response = $this->httpClient->request('POST', $url, [
'headers' => $form->getPreparedHeaders()->toArray(),
'query' => $query,
'body' => $form->bodyToString(),
'timeout' => 10,
]);