Merge remote-tracking branch 'origin/master' into issue465_display_person_resources

This commit is contained in:
2022-02-17 21:17:40 +01:00
60 changed files with 995 additions and 424 deletions

View File

@@ -60,6 +60,7 @@ class UserRefEventSubscriber implements EventSubscriberInterface
{
if ($period->hasPreviousUser()
&& $period->getUser() !== $this->security->getUser()
&& null !== $period->getUser()
&& $period->getStep() !== AccompanyingPeriod::STEP_DRAFT
) {
$this->generateNotificationToUser($period);

View File

@@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Chill\MainBundle\Serializer\Normalizer\DiscriminatedObjectDenormalizer;
use Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestionInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
@@ -234,17 +235,19 @@ final class AccompanyingCourseApiController extends ApiController
$requestor = null;
$exceptions = [];
foreach ([Person::class, ThirdParty::class] as $class) {
try {
$requestor = $this->getSerializer()
->deserialize($request->getContent(), $class, $_format, []);
} catch (RuntimeException $e) {
$exceptions[] = $e;
}
try {
$requestor = $this->getSerializer()->deserialize(
$request->getContent(),
'@multi',
$_format,
[DiscriminatedObjectDenormalizer::ALLOWED_TYPES => [Person::class, ThirdParty::class]]
);
} catch (RuntimeException $e) {
$exceptions[] = $e;
}
if (null === $requestor) {
throw new BadRequestException('Could not find any person or requestor', 0, $exceptions[0]);
throw new BadRequestException('Could not find any person or thirdparty', 0, null);
}
$accompanyingPeriod->setRequestor($requestor);

View File

@@ -30,14 +30,14 @@ class UserAccompanyingPeriodController extends AbstractController
}
/**
* @Route("/{_locale}/accompanying-periods", name="chill_person_accompanying_period_user")
* @Route("/{_locale}/person/accompanying-periods/my", name="chill_person_accompanying_period_user")
*/
public function listAction(Request $request)
{
$total = $this->accompanyingPeriodRepository->countBy(['user' => $this->getUser()]);
$total = $this->accompanyingPeriodRepository->countBy(['user' => $this->getUser(), 'step' => ['CONFIRMED', 'CLOSED']]);
$pagination = $this->paginatorFactory->create($total);
$accompanyingPeriods = $this->accompanyingPeriodRepository->findBy(
['user' => $this->getUser()],
['user' => $this->getUser(), 'step' => ['CONFIRMED', 'CLOSED']],
['openingDate' => 'DESC'],
$pagination->getItemsPerPage(),
$pagination->getCurrentPageFirstItemNumber()
@@ -48,4 +48,24 @@ class UserAccompanyingPeriodController extends AbstractController
'pagination' => $pagination,
]);
}
/**
* @Route("/{_locale}/person/accompanying-periods/my/drafts", name="chill_person_accompanying_period_draft_user")
*/
public function listDraftsAction(Request $request)
{
$total = $this->accompanyingPeriodRepository->countBy(['user' => $this->getUser(), 'step' => 'DRAFT']);
$pagination = $this->paginatorFactory->create($total);
$accompanyingPeriods = $this->accompanyingPeriodRepository->findBy(
['createdBy' => $this->getUser(), 'step' => 'DRAFT'],
['id' => 'DESC'],
$pagination->getItemsPerPage(),
$pagination->getCurrentPageFirstItemNumber()
);
return $this->render('@ChillPerson/AccompanyingPeriod/user_draft_periods_list.html.twig', [
'accompanyingPeriods' => $accompanyingPeriods,
'pagination' => $pagination,
]);
}
}

View File

@@ -44,6 +44,13 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
'order' => 20,
'icon' => 'tasks',
]);
$menu->addChild('My accompanying periods in draft', [
'route' => 'chill_person_accompanying_period_draft_user',
])
->setExtras([
'order' => 30,
'icon' => 'tasks',
]);
}
}

View File

@@ -71,7 +71,7 @@ final class AccompanyingPeriodRepository implements ObjectRepository
$qb = $this->buildQueryByRecentUserHistory($user, $since);
return $qb->select('a')
->distinct(true)
->addOrderBy('userHistory.startDate', 'DESC')
->getQuery()
->setMaxResults($limit)
->setFirstResult($offset)
@@ -95,6 +95,7 @@ final class AccompanyingPeriodRepository implements ObjectRepository
$qb
->join('a.userHistories', 'userHistory')
->where($qb->expr()->eq('a.user', ':user'))
->andWhere($qb->expr()->neq('a.step', "'" . AccompanyingPeriod::STEP_DRAFT . "'"))
->andWhere($qb->expr()->gte('userHistory.startDate', ':since'))
->andWhere($qb->expr()->isNull('userHistory.endDate'))
->setParameter('user', $user)

View File

@@ -56,14 +56,18 @@
</div>
<div>
<add-persons
buttonTitle="persons_associated.add_persons"
modalTitle="add_persons.title"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
<ul class="record_actions">
<li class="add-persons">
<add-persons
buttonTitle="persons_associated.add_persons"
modalTitle="add_persons.title"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
<div v-if="!isParticipationValid" class="alert alert-warning to-confirm">

View File

@@ -144,14 +144,18 @@
</div>
<div>
<add-persons v-if="accompanyingCourse.requestor === null"
buttonTitle="requestor.add_requestor"
modalTitle="requestor.add_requestor"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
<ul class="record_actions">
<li class="add-persons">
<add-persons v-if="accompanyingCourse.requestor === null"
buttonTitle="requestor.add_requestor"
modalTitle="requestor.add_requestor"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
</div>

View File

@@ -29,14 +29,18 @@
</div>
<div>
<add-persons
buttonTitle="resources.add_resources"
modalTitle="resources.add_resources"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
<ul class="record_actions">
<li class="add-persons">
<add-persons
buttonTitle="resources.add_resources"
modalTitle="resources.add_resources"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
</div>

View File

@@ -160,7 +160,7 @@
</p>
<ul class="record_actions">
<li>
<li class="add-persons">
<add-persons
ref="handlingThirdPartyPicker"
v-bind:key="handlingThirdPartyPicker.key"
@@ -222,7 +222,7 @@
</div>
<ul class="record_actions">
<li>
<li class="add-persons">
<add-persons
ref="thirdPartyPicker"
v-bind:key="thirdPartyPicker.key"

View File

@@ -29,7 +29,7 @@
</div>
<ul class="record_actions">
<li>
<li class="add-persons">
<add-persons
buttonTitle="household_members_editor.concerned.add_persons"
modalTitle="household_members_editor.concerned.search"

View File

@@ -61,7 +61,7 @@
<li v-if="hasHousehold">
<button @click="resetMode" class="btn btn-sm btn-misc">{{ $t('household_members_editor.household.reset_mode')}}</button>
</li>
<li v-if="!hasHousehold">
<li v-if="!hasHousehold" class="add-persons">
<add-persons
modalTitle="Chercher un ménage existant"
buttonTitle="Chercher un ménage existant"

View File

@@ -1,10 +1,7 @@
<template>
<ul class="record_actions">
<li class="add-persons">
<a class="btn" :class="getClassButton" :title="$t(buttonTitle)"
@click="openModal"><span v-if="displayTextButton">{{ $t(buttonTitle) }}</span></a>
</li>
</ul>
<a class="btn" :class="getClassButton" :title="$t(buttonTitle)" @click="openModal">
<span v-if="displayTextButton">{{ $t(buttonTitle) }}</span>
</a>
<teleport to="body">
<modal v-if="modal.showModal"

View File

@@ -26,9 +26,9 @@
</div>
<div class="wh-row">
<div class="wh-col">
{% if period.closingDate == null %}
{% if period.closingDate == null and period.step != 'DRAFT' %}
{{ 'accompanying_period.dates_from_%opening_date%'|trans({ '%opening_date%': period.openingDate|format_date('long') } ) }}
{% else %}
{% elseif period.closingDate != null %}
{{ 'accompanying_period.dates_from_%opening_date%_to_%closing_date%'|trans({
'%opening_date%': period.openingDate|format_date('long'),
'%closing_date%': period.closingDate|format_date('long')}
@@ -55,65 +55,67 @@
</div>
</div>
</div>
<div class="item-row separator">
<div class="wrap-list">
{% if period.requestorPerson is not null or period.requestorThirdParty is not null %}
<div class="wl-row">
<div class="wl-col title"><h3>{{ 'Requestor'|trans({'gender': null }) }}</h3></div>
<div class="wl-col list">
{% if period.requestorPerson is not null %}
<span class="wl-item">
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
action: 'show', displayBadge: true,
targetEntity: { name: 'person', id: period.requestorPerson.id },
buttonText: period.requestorPerson|chill_entity_render_string,
isDead: period.requestorPerson.deathdate is not null
} %}
</span>
{% endif %}
{% if period.requestorThirdParty is not null %}
<span class="wl-item">
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
action: 'show', displayBadge: true,
targetEntity: { name: 'thirdparty', id: period.requestorThirdParty.id },
buttonText: period.requestorThirdParty|chill_entity_render_string
} %}
</span>
{% endif %}
{% if period.requestor is not null or period.participations.count > 0 or period.socialIssues.count > 0%}
<div class="item-row separator">
<div class="wrap-list">
{% if period.requestorPerson is not null or period.requestorThirdParty is not null %}
<div class="wl-row">
<div class="wl-col title"><h3>{{ 'Requestor'|trans({'gender': null }) }}</h3></div>
<div class="wl-col list">
{% if period.requestorPerson is not null %}
<span class="wl-item">
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
action: 'show', displayBadge: true,
targetEntity: { name: 'person', id: period.requestorPerson.id },
buttonText: period.requestorPerson|chill_entity_render_string,
isDead: period.requestorPerson.deathdate is not null
} %}
</span>
{% endif %}
{% if period.requestorThirdParty is not null %}
<span class="wl-item">
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
action: 'show', displayBadge: true,
targetEntity: { name: 'thirdparty', id: period.requestorThirdParty.id },
buttonText: period.requestorThirdParty|chill_entity_render_string
} %}
</span>
{% endif %}
</div>
</div>
</div>
{% endif %}
{% if period.participations.count > 0 %}
<div class="wl-row">
<div class="wl-col title"><h3>{{ 'Participants'|trans }}</h3></div>
<div class="wl-col list">
{% for p in period.getCurrentParticipations %}
<span class="wl-item">
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
action: 'show', displayBadge: true,
targetEntity: { name: 'person', id: p.person.id },
buttonText: p.person|chill_entity_render_string,
isDead: p.person.deathdate is not null
} %}
</span>
{% endfor %}
{% endif %}
{% if period.participations.count > 0 %}
<div class="wl-row">
<div class="wl-col title"><h3>{{ 'Participants'|trans }}</h3></div>
<div class="wl-col list">
{% for p in period.getCurrentParticipations %}
<span class="wl-item">
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
action: 'show', displayBadge: true,
targetEntity: { name: 'person', id: p.person.id },
buttonText: p.person|chill_entity_render_string,
isDead: p.person.deathdate is not null
} %}
</span>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% if period.socialIssues.count > 0 %}
<div class="wl-row">
<div class="wl-col title"><h3>{{ 'Social issues'|trans }}</h3></div>
<div class="wl-col list">
{% for si in period.socialIssues %}
<p class="wl-item">
{{ si|chill_entity_render_box }}
</p>
{% endfor %}
{% endif %}
{% if period.socialIssues.count > 0 %}
<div class="wl-row">
<div class="wl-col title"><h3>{{ 'Social issues'|trans }}</h3></div>
<div class="wl-col list">
{% for si in period.socialIssues %}
<p class="wl-item">
{{ si|chill_entity_render_box }}
</p>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="item-row separator">
<div class="item-col item-meta">
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', period.id) %}

View File

@@ -0,0 +1,32 @@
{% extends "@ChillMain/layout.html.twig" %}
{% set activeRouteKey = 'chill_person_accompanying_period_user_list' %}
{% block title %}{{ 'My accompanying periods in draft'|trans }}{% endblock title %}
{% macro recordAction(period) %}
<li>
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': period.id }) }}"
class="btn btn-show" title="{{ 'See accompanying period'|trans }}"></a>
</li>
{% endmacro %}
{% block content %}
<div class="col-md-10">
<h1>{{ 'My accompanying periods in draft'|trans }}</h1>
<div class="flex-table accompanyingcourse-list">
{% for period in accompanyingPeriods %}
{% include '@ChillPerson/AccompanyingPeriod/_list_item.html.twig' with {'period': period, 'recordAction': _self.recordAction(period)} %}
{% else %}
<p class="chill-no-data-statement">{{ 'Any accompanying period'|trans }}</p>
{% endfor %}
</div>
{{ chill_pagination(pagination) }}
</div>
{% endblock %}

View File

@@ -20,6 +20,8 @@
<div class="flex-table accompanyingcourse-list">
{% for period in accompanyingPeriods %}
{% include '@ChillPerson/AccompanyingPeriod/_list_item.html.twig' with {'period': period, 'recordAction': _self.recordAction(period)} %}
{% else %}
<p class="chill-no-data-statement">{{ 'Any accompanying period'|trans }}</p>
{% endfor %}
</div>

View File

@@ -32,14 +32,28 @@
</div>
<div class="item-row separator">
<div class="wrap-list">
{% if p.household is same as p.person.getCurrentHousehold %}
<div class="wl-row">
<div class="wl-col title">
<h3>{{ 'Address'|trans }}</h3>
</div>
<div class="wl-col list">
<p class="item">{{ p.household.getCurrentAddress|chill_entity_render_box }}</p>
</div>
</div>
{% endif %}
<div class="wl-row">
<div class="wl-col title">
<h3>En tant que</h3>
<h3>{{ 'household.As member'|trans }}</h3>
</div>
<div class="wl-col list">
<p class="item">{{ p.position.label|localize_translatable_string }}
<p class="item">
{{ p.position.label|localize_translatable_string }}
{% if p.holder %}
<span class="holder">{{ 'household.holder'|trans }}</span>
<span class="fa-stack fa-holder" title="{{ 'houshold.holder'|trans|e('html_attr') }}">
<i class="fa fa-circle fa-stack-1x text-success"></i>
<i class="fa fa-stack-1x">T</i>
</span>
{% endif %}
</p>
</div>

View File

@@ -58,6 +58,10 @@ class AccompanyingPeriodWorkVoter extends Voter
case self::SEE:
return $this->security->isGranted(AccompanyingPeriodVoter::SEE_DETAILS, $subject->getAccompanyingPeriod());
case self::CREATE:
case self::UPDATE:
return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $subject->getAccompanyingPeriod());
default:
throw new UnexpectedValueException("attribute {$attribute} is not supported");
}
@@ -66,6 +70,9 @@ class AccompanyingPeriodWorkVoter extends Voter
case self::SEE:
return $this->security->isGranted(AccompanyingPeriodVoter::SEE_DETAILS, $subject);
case self::CREATE:
return $this->security->isGranted(AccompanyingPeriodVoter::CREATE, $subject);
default:
throw new UnexpectedValueException(sprintf(
"attribute {$attribute} is not supported on instance %s",
@@ -79,6 +86,6 @@ class AccompanyingPeriodWorkVoter extends Voter
private function getRoles(): array
{
return [self::SEE];
return [self::SEE, self::CREATE, self::UPDATE];
}
}

View File

@@ -161,11 +161,13 @@ class AccompanyingPeriodContext implements
'class' => Person::class,
'choices' => $persons,
'choice_label' => function (Person $p) {
return $this->personRender->renderString($p, []);
return $this->personRender->renderString($p, ['addAge' => true]);
},
'multiple' => false,
'expanded' => true,
'required' => false,
'label' => $options[$key . 'Label'],
'placeholder' => $this->translator->trans('Any person selected'),
]);
}
}
@@ -241,7 +243,8 @@ class AccompanyingPeriodContext implements
public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void
{
$doc = new AccompanyingCourseDocument();
$doc->setTitle($this->translatableStringHelper->localize($template->getName()))
$doc->setTemplate($template)
->setTitle($this->translatableStringHelper->localize($template->getName()))
->setDate(new DateTime())
->setDescription($this->translatableStringHelper->localize($template->getName()))
->setCourse($entity)

View File

@@ -83,6 +83,12 @@ class PersonRender extends AbstractChillEntityRender
. $this->addAltNames($person, false) . ' (' . $this->translator->trans('years_old', ['age' => $person->getAge()]) . ')';
}
if (null !== $person->getDeathDate() && $options['addAge']) {
return $person->getFirstName() . ' ' . $person->getLastName()
. ' (‡)'
. $this->addAltNames($person, false);
}
return $person->getFirstName() . ' ' . $person->getLastName()
. $this->addAltNames($person, false);
}

View File

@@ -98,6 +98,7 @@ household:
from: Depuis
to: Jusqu'au
person history: Ménages
As member: En tant que
household_composition:
Since: >-

View File

@@ -85,6 +85,7 @@ Course number: Parcours n°
Civility: Civilité
choose civility: --
All genders: tous les genres
Any person selected: Aucune personne sélectionnée
# dédoublonnage
Old person: Doublon
@@ -179,6 +180,7 @@ An accompanying period is open: Une période d'accompagnement est ouverte
Accompanying period list: Périodes d'accompagnement
Accompanying period list for person: Périodes d'accompagnement de la personne
Accompanying period: Parcours d'accompagnement
Any accompanying period: Aucun parcours d'accompagnement
period: Parcours
New accompanying course: Nouveau parcours d'accompagnement
Choose a motive: Motif de fermeture
@@ -567,3 +569,4 @@ Linked evaluations: Évaluations associées
# Accompanying period per user
My accompanying periods: Mes parcours
My accompanying periods in draft: Mes parcours brouillons