Compare commits

..

12 Commits

30 changed files with 410 additions and 687 deletions

View File

@@ -94,8 +94,7 @@ unit_tests:
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev - php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev
- php -d memory_limit=3G tests/app/bin/console doctrine:fixtures:load -n - php -d memory_limit=3G tests/app/bin/console doctrine:fixtures:load -n
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=test - php -d memory_limit=2G tests/app/bin/console cache:clear --env=test
- php -d memory_limit=2G tests/app/bin/console doctrine:query:dql "SELECT c.name FROM Chill\\MainBundle\\Entity\\Center c" - php -d memory_limit=4G bin/phpunit --colors=never
- php -d memory_limit=4G bin/phpunit --colors=never --testdox
artifacts: artifacts:
expire_in: 30 min expire_in: 30 min
paths: paths:

View File

@@ -41,6 +41,7 @@ and this project adheres to
* [activity] activity admin: translations + remove label field for comment on admin activity type (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/587) * [activity] activity admin: translations + remove label field for comment on admin activity type (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/587)
* [main] admin user_job: improvements (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/588) * [main] admin user_job: improvements (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/588)
* [address] can add extra address info even if noAddress (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/576) * [address] can add extra address info even if noAddress (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/576)
* [search] Change order of birthdate fields in advanced search
### 2022-05-06 ### 2022-05-06

View File

@@ -215,7 +215,7 @@ class WorkflowStepType extends AbstractType
} else { } else {
foreach ($transition->getTos() as $to) { foreach ($transition->getTos() as $to) {
$meta = $workflow->getMetadataStore()->getPlaceMetadata($to); $meta = $workflow->getMetadataStore()->getPlaceMetadata($to);
if ( if (
!array_key_exists('isFinal', $meta) || false === $meta['isFinal'] !array_key_exists('isFinal', $meta) || false === $meta['isFinal']
) { ) {
@@ -224,7 +224,7 @@ class WorkflowStepType extends AbstractType
} }
$destUsers = $form['future_dest_users']->getData(); $destUsers = $form['future_dest_users']->getData();
$destEmails = $form['future_dest_emails']->getData(); $destEmails = $form['future_dest_emails']->getData();
if (!$toFinal && [] === $destUsers && [] === $destEmails) { if (!$toFinal && [] === $destUsers && [] === $destEmails) {
$context $context
->buildViolation('workflow.You must add at least one dest user or email') ->buildViolation('workflow.You must add at least one dest user or email')

View File

@@ -42,6 +42,13 @@ body {
footer { footer {
margin-top: auto; margin-top: auto;
} }
.content-title {
background-color: $chill-l-gray;
border-radius:3px;
padding:.5rem;
margin-bottom: 1rem;
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px !important;
}
} }
header { header {
@@ -214,6 +221,19 @@ footer.footer {
} }
} }
/*
* PERSON INFO
*/
.chill_view_data, .pop-item {
.info-field {
border: 1px dashed;
padding:.5rem;
border-radius:3px;
margin-top:.5rem;
}
}
/* /*
* ADMIN STYLES * ADMIN STYLES
*/ */
@@ -260,6 +280,8 @@ table.table-bordered {
background-color: $gray-200; background-color: $gray-200;
color: $gray-800; color: $gray-800;
font-size: 90%; font-size: 90%;
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;
border-radius: 5px !important;
p { p {
margin-bottom: 0.75rem !important; margin-bottom: 0.75rem !important;
@@ -459,8 +481,19 @@ span.item-key {
/// Workflows /// Workflows
div.workflow { div.workflow {
section.step { section.step {
border: 1px solid $chill-l-gray; form {
padding: 1em 2em; display: flex;
flex-direction: column;
align-items: center;
}
i.fa-angle-double-down {
font-size: 3rem;
color: rgba(0, 0, 0, 0.568);
margin-bottom: 1rem;
margin-top: 1rem;
}
// border: 1px solid $chill-l-gray;
// padding: 1em 2em;
div.flex-table { div.flex-table {
margin: 1.5em -2em; margin: 1.5em -2em;
} }

View File

@@ -6,6 +6,26 @@
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION * FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
*/ */
.pop-item {
border-radius: 10px !important;
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px !important;
padding:1.7rem;
margin-top: .5rem;
margin-bottom: .5rem;
.subtitle {
background-color: $chill-ll-gray;
border-radius:3px;
padding:.5rem;
margin-top: 1rem;
}
&:last-child {
margin-bottom: 1rem;
}
&:first-child {
margin-top:1rem;
}
}
div.flex-bloc, div.flex-bloc,
div.flex-table { div.flex-table {
display: flex; display: flex;
@@ -14,11 +34,39 @@ div.flex-table {
box-sizing: border-box; box-sizing: border-box;
margin: 1.5em 0; margin: 1.5em 0;
div.message-item {
border-radius: 10px !important;
box-shadow: rgba(9, 30, 66, 0.25) 0px 1px 1px, rgba(9, 30, 66, 0.13) 0px 0px 1px 1px !important;
width: 96%;
margin-bottom: .5rem;
margin-left: auto;
margin-right: auto;
}
div.card-item {
border-radius: 10px !important;
box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px, rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset !important;
width: 96%;
margin-left: auto;
margin-right: auto;
}
div.item-bloc { div.item-bloc {
display: flex; display: flex;
@include border-collapse; @include border-collapse;
padding: 1em; padding: 1em;
border-radius: 5px !important;
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px, rgba(0, 0, 0, 0.24) 0px 1px 2px !important;
margin-left: auto;
margin-right: auto;
margin-top: .5rem;
width: 97%;
&:last-child {
margin-bottom: 1rem;
}
&:first-child {
margin-top:1rem;
}
div.item-row { div.item-row {
display: flex; display: flex;

View File

@@ -48,19 +48,40 @@ div.notification-show {
} }
} }
ul.small_in_title { ul.small_in_title {
list-style-type: circle; // list-style-type: circle;
li { li {
list-style: none;
margin-bottom: 1rem;
span.item-key { span.item-key {
display: inline-block; display: inline-block;
background-color: white;
width: 3em; width: 3em;
font-size: 1.2rem;
} }
} }
} }
} }
div.notification-content { div.notification-content {
margin: 1.5rem; width: 93%;
p { margin: 1.5rem auto 1.5rem auto;
margin-bottom: 0.75rem; .message {
background-color: #f3f3f3;
line-height: 1.75;
box-shadow: rgba(0, 0, 0, 0.25) 0px 0.0625em 0.0625em, rgba(0, 0, 0, 0.25) 0px 0.125em 0.5em, rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset;
padding: 1.5rem;
border-radius: 5px;
border-left: $chill-yellow 10px solid;
p:first-child {
margin-bottom: 1rem;
&::before {
content: "";
font-family: Georgia;
font-size: 40px;
line-height: 0;
display: inline-block;
display: -webkit-inline-box;
}
}
} }
} }
} }

View File

@@ -67,14 +67,16 @@
<div class="notification-content"> <div class="notification-content">
{% if c.full_content is defined and c.full_content == true %} {% if c.full_content is defined and c.full_content == true %}
{% if c.notification.message is not empty %} {% if c.notification.message is not empty %}
{{ c.notification.message|chill_markdown_to_html }} <div class="message">{{ c.notification.message|chill_markdown_to_html }}</div>
{% else %} {% else %}
<p class="chill-no-data-statement">{{ 'Any comment'|trans }}</p> <p class="chill-no-data-statement">{{ 'Any comment'|trans }}</p>
{% endif %} {% endif %}
{% else %} {% else %}
{% if c.notification.message is not empty %} {% if c.notification.message is not empty %}
{{ c.notification.message|u.truncate(250, '…', false)|chill_markdown_to_html }} <div class="message">
<p class="read-more"><a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}">{{ 'Read more'|trans }}</a></p> {{ c.notification.message|u.truncate(250, '…', false)|chill_markdown_to_html }}
<p class="read-more"><a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}">{{ 'Read more'|trans }}</a></p>
</div>
{% else %} {% else %}
<p class="chill-no-data-statement">{{ 'Any comment'|trans }}</p> <p class="chill-no-data-statement">{{ 'Any comment'|trans }}</p>
{% endif %} {% endif %}

View File

@@ -9,7 +9,7 @@
{% set labels = workflow_metadata(entity_workflow, 'label', step.currentStep) %} {% set labels = workflow_metadata(entity_workflow, 'label', step.currentStep) %}
{% set label = labels is null ? step.currentStep : labels|localize_translatable_string %} {% set label = labels is null ? step.currentStep : labels|localize_translatable_string %}
<div class="card"> <div class="pop-item">
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
@@ -47,38 +47,40 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<i class="fa fa-angle-double-down" aria-hidden="true"></i>
<div class="pop-item">
<div id="transitionFilter">
{% if transition_form.transitionFilter is defined %}
{{ form_row(transition_form.transitionFilter) }}
{% endif %}
</div>
<div id="transitionFilter"> <div id="transitions">
{% if transition_form.transitionFilter is defined %} {{ form_row(transition_form.transition) }}
{{ form_row(transition_form.transitionFilter) }} </div>
{% if transition_form.freezeAfter is defined %}
{{ form_row(transition_form.freezeAfter) }}
{% endif %} {% endif %}
<div id="futureDests">
{{ form_row(transition_form.future_dest_users) }}
{{ form_row(transition_form.future_dest_emails) }}
</div>
<p>{{ form_label(transition_form.comment) }}</p>
{{ form_widget(transition_form.comment) }}
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(transition_form) }}
</div> </div>
<div id="transitions">
{{ form_row(transition_form.transition) }}
</div>
{% if transition_form.freezeAfter is defined %}
{{ form_row(transition_form.freezeAfter) }}
{% endif %}
<div id="futureDests">
{{ form_row(transition_form.future_dest_users) }}
{{ form_row(transition_form.future_dest_emails) }}
</div>
<p>{{ form_label(transition_form.comment) }}</p>
{{ form_widget(transition_form.comment) }}
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(transition_form) }}
{% else %} {% else %}
<div class="alert alert-chill-yellow"> <div class="alert alert-chill-yellow">

View File

@@ -5,7 +5,7 @@
{% set place_labels = workflow_metadata(entity_workflow, 'label', step.currentStep) %} {% set place_labels = workflow_metadata(entity_workflow, 'label', step.currentStep) %}
{% set place_label = place_labels is null ? step.currentStep : place_labels|localize_translatable_string %} {% set place_label = place_labels is null ? step.currentStep : place_labels|localize_translatable_string %}
<div class="item-bloc {{ 'bloc' ~ step.id }} {% if loop.first %}initial{% endif %}"> <div class="item-bloc message-item {{ 'bloc' ~ step.id }} {% if loop.first %}initial{% endif %}">
<div class="item-row"> <div class="item-row">
{% if loop.first and step.next is null %} {% if loop.first and step.next is null %}

View File

@@ -32,33 +32,31 @@
- src/Bundle/ChillPersonBundle/Resources/views/Workflow/_accompanying_period_work.html.twig - src/Bundle/ChillPersonBundle/Resources/views/Workflow/_accompanying_period_work.html.twig
- src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/_workflow.html.twig - src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/_workflow.html.twig
#} #}
<section class="step my-4"> <section class="step my-4 pop-item">
<div class="mb-5"> <div class="mb-3">
<h2>{{ handler.entityTitle(entity_workflow) }}</h2> <h2>{{ handler.entityTitle(entity_workflow) }}</h2>
{{ macro.breadcrumb({'entity_workflow': entity_workflow}) }} {{ macro.breadcrumb({'entity_workflow': entity_workflow}) }}
</div> </div>
{% include handler_template with handler_template_data|merge({'display_action': true }) %} {% include handler_template with handler_template_data|merge({'display_action': true }) %}
{% if is_granted('CHILL_MAIN_WORKFLOW_DELETE', entity_workflow) %}
<ul class="record_actions">
<li>
<a class="btn btn-delete"
href="{{ chill_path_add_return_path('chill_main_workflow_delete', {'id': entity_workflow.id}) }}"
>
{{ 'workflow.Delete workflow'|trans }}
</a>
</li>
</ul>
{% endif %}
</section> </section>
<section class="step my-4">{% include '@ChillMain/Workflow/_follow.html.twig' %}</section> <section class="step my-4">{% include '@ChillMain/Workflow/_decision.html.twig' %}</section>
<section class="step my-4">{% include '@ChillMain/Workflow/_decision.html.twig' %}</section>{# <section class="step my-4 pop-item">{% include '@ChillMain/Workflow/_follow.html.twig' %}</section>
<section class="step my-4">{% include '@ChillMain/Workflow/_comment.html.twig' %}</section> #} {#<section class="step my-4">{% include '@ChillMain/Workflow/_comment.html.twig' %}</section> #}
<section class="step my-4">{% include '@ChillMain/Workflow/_history.html.twig' %}</section> <section class="step my-4 pop-item">{% include '@ChillMain/Workflow/_history.html.twig' %}</section>
{% if is_granted('CHILL_MAIN_WORKFLOW_DELETE', entity_workflow) %}
<ul class="record_actions">
<li>
<a class="btn btn-delete"
href="{{ chill_path_add_return_path('chill_main_workflow_delete', {'id': entity_workflow.id}) }}"
>
{{ 'workflow.Delete workflow'|trans }}
</a>
</li>
</ul>
{% endif %}
{# useful ? {# useful ?
<ul class="record_actions sticky-form-buttons"> <ul class="record_actions sticky-form-buttons">
<li class="cancel"> <li class="cancel">

View File

@@ -1,167 +0,0 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Templating\EngineInterface;
class AccompanyingPeriodRegulationListController
{
private AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository;
private EngineInterface $engine;
private FormFactoryInterface $formFactory;
private PaginatorFactory $paginatorFactory;
private Security $security;
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository, EngineInterface $engine, FormFactoryInterface $formFactory, PaginatorFactory $paginatorFactory, Security $security, TranslatableStringHelperInterface $translatableStringHelper)
{
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
$this->engine = $engine;
$this->formFactory = $formFactory;
$this->paginatorFactory = $paginatorFactory;
$this->security = $security;
$this->translatableStringHelper = $translatableStringHelper;
}
/**
* @Route("/{_locale}/person/periods/undispatched", name="chill_person_course_list_regulation")
*/
public function listRegul(Request $request): Response
{
if (!$this->security->isGranted('ROLE_USER') || !$this->security->getUser() instanceof User) {
throw new AccessDeniedHttpException();
}
$form = $this->buildFilterForm();
$form->handleRequest($request);
$total = $this->accompanyingPeriodACLAwareRepository->countByUnDispatched(
$form['jobs']->getData(),
$form['services']->getData(),
$form['locations']->getData(),
);
$paginator = $this->paginatorFactory->create($total);
$periods = $this->accompanyingPeriodACLAwareRepository
->findByUnDispatched(
$form['jobs']->getData(),
$form['services']->getData(),
$form['locations']->getData(),
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
return new Response(
$this->engine->render('@ChillPerson/AccompanyingCourse/dispatch_list.html.twig', [
'paginator' => $paginator,
'periods' => $periods,
'form' => $form->createView(),
])
);
}
private function buildFilterForm(): FormInterface
{
$data = [
'services' => [],
'jobs' => [],
'locations' => [],
];
$builder = $this->formFactory->createBuilder(FormType::class, $data, [
'method' => 'get', 'csrf_protection' => false, ]);
$builder
->add('services', EntityType::class, [
'class' => Scope::class,
'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('s');
},
'choice_label' => function (Scope $s) {
return $this->translatableStringHelper->localize($s->getName());
},
'multiple' => true,
'label' => 'Service',
'required' => false,
])
->add('jobs', EntityType::class, [
'class' => UserJob::class,
'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->translatableStringHelper->localize($j->getLabel());
},
'multiple' => true,
'label' => 'Métier',
'required' => false,
])
->add('locations', EntityType::class, [
'class' => Location::class,
'query_builder' => static function (EntityRepository $er) {
$qb = $er->createQueryBuilder('l');
$qb
->join('l.locationType', 't')
->where(
$qb->expr()->andX(
$qb->expr()->eq('t.availableForUsers', "'TRUE'"),
$qb->expr()->eq('t.active', "'TRUE'"),
$qb->expr()->eq('l.active', "'TRUE'"),
$qb->expr()->eq('l.availableForUsers', "'TRUE'")
)
);
return $qb;
},
'choice_label' => static function (Location $l) {
return $l->getName();
},
'multiple' => true,
'group_by' => function (Location $l) {
if (null === $type = $l->getLocationType()) {
return null;
}
return $this->translatableStringHelper->localize($type->getTitle());
},
'label' => 'Localisation administrative',
'required' => false,
]);
return $builder->getForm();
}
}

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\EventListener; namespace Chill\PersonBundle\EventListener;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
@@ -26,7 +27,6 @@ class AccompanyingPeriodWorkEventListener
public function prePersistAccompanyingPeriodWork(AccompanyingPeriodWork $work): void public function prePersistAccompanyingPeriodWork(AccompanyingPeriodWork $work): void
{ {
$referrer = $work->getAccompanyingPeriod()->getUser(); $referrer = $work->getAccompanyingPeriod()->getUser();
if (null !== $referrer) { if (null !== $referrer) {
$work->addReferrer($referrer); $work->addReferrer($referrer);
} }

View File

@@ -11,13 +11,12 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Menu; namespace Chill\PersonBundle\Menu;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Knp\Menu\MenuItem; use Knp\Menu\MenuItem;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
/** /**
@@ -25,20 +24,20 @@ use Symfony\Contracts\Translation\TranslatorInterface;
*/ */
class SectionMenuBuilder implements LocalMenuBuilderInterface class SectionMenuBuilder implements LocalMenuBuilderInterface
{ {
protected AuthorizationCheckerInterface $authorizationChecker;
protected ParameterBagInterface $parameterBag; protected ParameterBagInterface $parameterBag;
protected TranslatorInterface $translator; protected TranslatorInterface $translator;
private Security $security;
/** /**
* SectionMenuBuilder constructor. * SectionMenuBuilder constructor.
*/ */
public function __construct(ParameterBagInterface $parameterBag, Security $security, TranslatorInterface $translator) public function __construct(AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator, ParameterBagInterface $parameterBag)
{ {
$this->parameterBag = $parameterBag; $this->authorizationChecker = $authorizationChecker;
$this->security = $security;
$this->translator = $translator; $this->translator = $translator;
$this->parameterBag = $parameterBag;
} }
/** /**
@@ -46,7 +45,7 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
*/ */
public function buildMenu($menuId, MenuItem $menu, array $parameters) public function buildMenu($menuId, MenuItem $menu, array $parameters)
{ {
if ($this->security->isGranted(PersonVoter::CREATE) && $this->parameterBag->get('chill_person.create_person_allowed')) { if ($this->authorizationChecker->isGranted(PersonVoter::CREATE) && $this->parameterBag->get('chill_person.create_person_allowed')) {
$menu->addChild($this->translator->trans('Add a person'), [ $menu->addChild($this->translator->trans('Add a person'), [
'route' => 'chill_person_new', 'route' => 'chill_person_new',
]) ])
@@ -66,7 +65,7 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
]); ]);
} }
if ($this->security->isGranted(AccompanyingPeriodVoter::REASSIGN_BULK, null)) { if ($this->authorizationChecker->isGranted(AccompanyingPeriodVoter::REASSIGN_BULK, null)) {
$menu->addChild($this->translator->trans('reassign.Bulk reassign'), [ $menu->addChild($this->translator->trans('reassign.Bulk reassign'), [
'route' => 'chill_course_list_reassign', 'route' => 'chill_course_list_reassign',
]) ])
@@ -75,16 +74,6 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
'icons' => [], 'icons' => [],
]); ]);
} }
if ($this->security->getUser() instanceof User && $this->security->isGranted('ROLE_USER')) {
$menu
->addChild('Régulation', [
'route' => 'chill_person_course_list_regulation',
])
->setExtras([
'order' => 150,
]);
}
} }
public static function getMenuIds(): array public static function getMenuIds(): array

View File

@@ -11,19 +11,13 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Repository; namespace Chill\PersonBundle\Repository;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface; use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use DateTime; use DateTime;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
use function count; use function count;
@@ -68,15 +62,6 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC
return $qb; return $qb;
} }
public function countByUnDispatched(array $jobs, array $services, array $administrativeLocations): int
{
$qb = $this->addACLByUnDispatched($this->buildQueryUnDispatched($jobs, $services, $administrativeLocations));
$qb->select('COUNT(ap)');
return $qb->getQuery()->getSingleScalarResult();
}
public function countByUserOpenedAccompanyingPeriod(?User $user): int public function countByUserOpenedAccompanyingPeriod(?User $user): int
{ {
if (null === $user) { if (null === $user) {
@@ -141,23 +126,6 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC
return $qb->getQuery()->getResult(); return $qb->getQuery()->getResult();
} }
public function findByUnDispatched(array $jobs, array $services, array $administrativeLocations, ?int $limit = null, ?int $offset = null): array
{
$qb = $this->addACLByUnDispatched($this->buildQueryUnDispatched($jobs, $services, $administrativeLocations));
$qb->select('ap');
if (null !== $limit) {
$qb->setMaxResults($limit);
}
if (null !== $offset) {
$qb->setFirstResult($offset);
}
return $qb->getQuery()->getResult();
}
/** /**
* @return array|AccompanyingPeriod[] * @return array|AccompanyingPeriod[]
*/ */
@@ -178,88 +146,4 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC
return $qb->getQuery()->getResult(); return $qb->getQuery()->getResult();
} }
private function addACLByUnDispatched(QueryBuilder $qb): QueryBuilder
{
$centers = $this->authorizationHelper->getReachableCenters(
$this->security->getUser(),
AccompanyingPeriodVoter::SEE
);
$orX = $qb->expr()->orX();
if (0 === count($centers)) {
return $qb->andWhere("'FALSE' = 'TRUE'");
}
foreach ($centers as $key => $center) {
$scopes = $this->authorizationHelper
->getReachableCircles(
$this->security->getUser(),
AccompanyingPeriodVoter::SEE,
$center
);
$and = $qb->expr()->andX(
$qb->expr()->exists('SELECT part FROM ' . AccompanyingPeriodParticipation::class . ' part ' .
"JOIN part.person p WHERE part.accompanyingPeriod = ap.id AND p.center = :center_{$key}")
);
$qb->setParameter('center_' . $key, $center);
$orScope = $qb->expr()->orX();
foreach ($scopes as $skey => $scope) {
$orScope->add(
$qb->expr()->isMemberOf(':scope_' . $key . '_' . $skey, 'ap.scopes')
);
$qb->setParameter('scope_' . $key . '_' . $skey, $scope);
}
$and->add($orScope);
$orX->add($and);
}
return $qb->andWhere($orX);
}
/**
* @param array|UserJob[] $jobs
* @param array|Scope[] $services
* @param array|Location[] $locations
*/
private function buildQueryUnDispatched(array $jobs, array $services, array $locations): QueryBuilder
{
$qb = $this->accompanyingPeriodRepository->createQueryBuilder('ap');
$qb->where(
$qb->expr()->andX(
$qb->expr()->isNull('ap.user'),
$qb->expr()->neq('ap.step', ':draft'),
$qb->expr()->neq('ap.step', ':closed')
)
)
->setParameter('draft', AccompanyingPeriod::STEP_DRAFT)
->setParameter('closed', AccompanyingPeriod::STEP_CLOSED);
if (0 < count($jobs)) {
$qb->andWhere($qb->expr()->in('ap.job', ':jobs'))
->setParameter('jobs', $jobs);
}
if (0 < count($locations)) {
$qb->andWhere($qb->expr()->in('ap.administrativeLocation', ':locations'))
->setParameter('locations', $locations);
}
if (0 < count($services)) {
$or = $qb->expr()->orX();
foreach ($services as $key => $service) {
$or->add($qb->expr()->isMemberOf('ap.scopes', ':scope_' . $key));
$qb->setParameter('scope_' . $key, $service);
}
$qb->andWhere($or);
}
return $qb;
}
} }

View File

@@ -11,20 +11,11 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Repository; namespace Chill\PersonBundle\Repository;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
interface AccompanyingPeriodACLAwareRepositoryInterface interface AccompanyingPeriodACLAwareRepositoryInterface
{ {
/**
* @param array|UserJob[] $jobs
* @param array|Scope[] $services
*/
public function countByUnDispatched(array $jobs, array $services, array $administrativeLocations): int;
public function countByUserOpenedAccompanyingPeriod(?User $user): int; public function countByUserOpenedAccompanyingPeriod(?User $user): int;
public function findByPerson( public function findByPerson(
@@ -35,13 +26,5 @@ interface AccompanyingPeriodACLAwareRepositoryInterface
?int $offset = null ?int $offset = null
): array; ): array;
/**
* @param array|UserJob[] $jobs if empty, does not take this argument into account
* @param array|Scope[] $services if empty, does not take this argument into account
*
* @return array|AccompanyingPeriod[]
*/
public function findByUnDispatched(array $jobs, array $services, array $administrativeLocations, ?int $limit = null, ?int $offset = null): array;
public function findByUserOpenedAccompanyingPeriod(?User $user, array $orderBy = [], int $limit = 0, int $offset = 50): array; public function findByUserOpenedAccompanyingPeriod(?User $user, array $orderBy = [], int $limit = 0, int $offset = 50): array;
} }

View File

@@ -226,16 +226,35 @@ div.banner {
div.household-resume { div.household-resume {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: flex-start;
justify-content: space-between;
padding-left: 1rem;
padding-right:1rem;
div.col-address { div.col-address {
font-size: 120%; font-size: 120%;
padding-left: 1em; padding: 1rem;
border-radius: 5px;
border: 1px dotted tint-color($chill-accourse-context, 10%);
border-left: 1px dotted tint-color($chill-accourse-context, 10%);
border-right: 1px dotted tint-color($chill-accourse-context, 10%);
div.address-box {
width: 100%;
justify-content: flex-start;
align-items: flex-start;
display: flex;
i {
font-size: 200%;
margin-right: 2rem;
margin-top: 2rem;
margin-left: 1rem;
}
}
} }
div.col-comment { div.col-comment {
//padding: 0; //padding: 0;
margin-bottom: 1rem; margin-bottom: 1rem;
width: 50%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
> * > * { > * > * {

View File

@@ -1,88 +0,0 @@
{% extends 'ChillMainBundle::layout.html.twig' %}
{% block title "Liste de parcours à répartir" %}
{% block js %}
{{ encore_entry_script_tags('mod_set_referrer') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('mod_set_referrer') }}
{% endblock %}
{% macro period_meta(period) %}
{% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE', period) %}
<div class="item-col item-meta">
{% set job_id = null %}
{% if period.job is not null %}
{% set job_id = period.job.id %}
{% endif %}
<span
data-set-referrer-app="data-set-referrer-app"
data-set-referrer-accompanying-period-id="{{ period.id }}"
data-set-referrer-job-id="{{ job_id }}"
></span>
</div>
{% endif %}
{% endmacro %}
{% macro period_actions(period) %}
{% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', period) %}
<li>
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': period.id}) }}" class="btn btn-show"></a>
</li>
{% endif %}
{% endmacro %}
{% import _self as m %}
{% block content %}
<div class="col-10">
<h1>{{ block('title') }}</h1>
{{ form_start(form) }}
<div class="row">
<div class="col-md-4">
{{ form_label(form.locations ) }}
{{ form_widget(form.locations, {'attr': {'class': 'select2'}}) }}
</div>
<div class="col-md-4">
{{ form_label(form.jobs) }}
{{ form_widget(form.jobs, {'attr': {'class': 'select2'}}) }}
</div>
<div class="col-md-4">
{{ form_label(form.services) }}
{{ form_widget(form.services, {'attr': {'class': 'select2'}}) }}
</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) }}
{% if periods|length == 0 %}
<p class="chill-no-data-statement">Aucun parcours à désigner, ou droits insuffisants pour les afficher</p>
{% else %}
<p><span class="badge rounded-pill bg-primary">{{ paginator.totalItems }}</span> parcours à attribuer (calculé ce jour à {{ null|format_time('medium') }})</p>
<div class="flex-table">
{% for period in periods %}
{% include '@ChillPerson/AccompanyingPeriod/_list_item.html.twig' with {'period': period,
'recordAction': m.period_actions(period), 'itemMeta': m.period_meta(period) } %}
{% endfor %}
</div>
{% endif %}
{{ chill_pagination(paginator) }}
</div>
{% endblock %}

View File

@@ -1,5 +1,4 @@
<div class="item-bloc accompanying_course_work-item{% if itemBlocClass is defined %} {{ itemBlocClass }}{% endif %}"> <div class="item-bloc card-item accompanying_course_work-item{% if itemBlocClass is defined %} {{ itemBlocClass }}{% endif %}">
<div class="item-row"> <div class="item-row">
<h2 class="badge-title"> <h2 class="badge-title">
<span class="title_label"></span> <span class="title_label"></span>
@@ -145,5 +144,4 @@
</ul> </ul>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
<div class="item-bloc accompanying-period-item{% if itemBlocClass is defined %} {{ itemBlocClass|raw }}{% endif %}" data-accompanying-period-id="{{ period.id|e('html_attr') }}"> <div class="item-bloc card-item accompanying-period-item{% if itemBlocClass is defined %} {{ itemBlocClass|raw }}{% endif %}" data-accompanying-period-id="{{ period.id|e('html_attr') }}">
<div class="item-row"> <div class="item-row">
<div class="wrap-header"> <div class="wrap-header">
<div class="wh-row"> <div class="wh-row">

View File

@@ -19,12 +19,14 @@
<div class="row household-resume"> <div class="row household-resume">
<div class="item-bloc col-5 col-address"> <div class="item-bloc col-5 col-address">
<h2>{{ 'Address'|trans }}</h2> <h2>{{ 'Address'|trans }}</h2>
<div class="address-box">
{% if address is empty %} <i class="fa fa-map-marker" aria-hidden="true"></i>
<p class="chill-no-data-statement">{{ 'household.Household does not have any address currently'|trans }}</p> {% if address is empty %}
{% else %} <p class="chill-no-data-statement">{{ 'household.Household does not have any address currently'|trans }}</p>
{{ address|chill_entity_render_box({'multiline': true, 'extended_infos': true }) }} {% else %}
{% endif %} {{ address|chill_entity_render_box({'multiline': true, 'extended_infos': true }) }}
{% endif %}
</div>
<ul class="list-inline text-right mt-2"> <ul class="list-inline text-right mt-2">
<li class="list-inline-item"> <li class="list-inline-item">
@@ -49,95 +51,95 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="item-bloc col-7 col-comment"> <div class="item-bloc col-7 col-comment pop-item">
{% if form is null %} {% if form is null %}
{% set currentComposition = household.currentComposition %} {% set currentComposition = household.currentComposition %}
{% if currentComposition is not null %} {% if currentComposition is not null %}
<div> <div>
<h6> <h6>
{{ currentComposition.householdCompositionType.label|localize_translatable_string }} {{ currentComposition.householdCompositionType.label|localize_translatable_string }}
</h6> </h6>
<p> <p>
{{ 'household_composition.numberOfChildren children in household'|trans({'numberOfChildren': currentComposition.numberOfChildren}) }} {{ 'household_composition.numberOfChildren children in household'|trans({'numberOfChildren': currentComposition.numberOfChildren}) }}
</p> </p>
<p> <p>
{{ 'household_composition.Since'|trans({'startDate': currentComposition.startDate}) }} {{ 'household_composition.Since'|trans({'startDate': currentComposition.startDate}) }}
</p> </p>
<ul class="record_actions"> <ul class="record_actions">
<li>
<a class="btn btn-sm btn-update change-icon"
href="{{ path('chill_person_household_composition_index', {'id': household.id}) }}">
{{ 'household_composition.Update composition'|trans }}
</a>
</li>
</ul>
</div>
{% else %}
<div class="alert alert-danger">
<p>
{{ 'household_composition.Currently no composition'|trans }}
</p>
<ul class="record_actions" style="margin-bottom: 0">
<li> <li>
<a class="btn btn-sm btn-update change-icon" <a class="btn btn-sm btn-update change-icon"
href="{{ path('chill_person_household_composition_index', {'id': household.id}) }}"> href="{{ path('chill_person_household_composition_index', {'id': household.id}) }}">
{{ 'household_composition.Update composition'|trans }} {{ 'household_composition.Add a composition'|trans }}
</a> </a>
</li> </li>
</ul> </ul>
</div>
{% else %}
<div class="alert alert-danger">
<p>
{{ 'household_composition.Currently no composition'|trans }}
</p>
<ul class="record_actions" style="margin-bottom: 0">
<li>
<a class="btn btn-sm btn-update change-icon"
href="{{ path('chill_person_household_composition_index', {'id': household.id}) }}">
{{ 'household_composition.Add a composition'|trans }}
</a>
</li>
</ul>
</div>
{% endif %}
{% if household.waitingForBirth or not household.commentMembers.isEmpty() %}
<div class="p-4 bg-light">
{% if household.waitingForBirth %}
<i class="fa fa-check-square-o pe-2"></i>
{% if household.waitingForBirthDate is not null %}
{{ 'household.Expecting for birth on date'|trans({ 'date': household.waitingForBirthDate|format_date('long') }) }}
{% else %}
{{ 'household.Expecting for birth'|trans }}
{% endif %}
{% endif %}
{% if not household.commentMembers.isEmpty() %}
{{ household.commentMembers|chill_entity_render_box }}
{% endif %}
</div>
{% endif %}
{% if not household.commentMembers.isEmpty() %}
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-edit btn-block">
{{ 'household.Edit comment and expecting birth'|trans }}
</a>
{% else %}
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-create btn-block">
{{ 'household.New comment and expecting birth'|trans }}
</a>
{% endif %}
{% else %}
{{ form_start(form) }}
<div id="waitingForBirthContainer">
{{ form_widget(form.waitingForBirth) }}
</div> </div>
<div id="waitingForBirthDateContainer">
{{ form_widget(form.waitingForBirthDate) }}
</div>
<div class="mt-3">
{{ form_widget(form.commentMembers) }}
</div>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save" id="form_household_comment_confirm">
{{ 'Save'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}
{% endif %} {% endif %}
</div> {% if household.waitingForBirth or not household.commentMembers.isEmpty() %}
<div class="p-4 bg-light">
{% if household.waitingForBirth %}
<i class="fa fa-check-square-o pe-2"></i>
{% if household.waitingForBirthDate is not null %}
{{ 'household.Expecting for birth on date'|trans({ 'date': household.waitingForBirthDate|format_date('long') }) }}
{% else %}
{{ 'household.Expecting for birth'|trans }}
{% endif %}
{% endif %}
{% if not household.commentMembers.isEmpty() %}
{{ household.commentMembers|chill_entity_render_box }}
{% endif %}
</div>
{% endif %}
{% if not household.commentMembers.isEmpty() %}
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-edit btn-block">
{{ 'household.Edit comment and expecting birth'|trans }}
</a>
{% else %}
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-create btn-block">
{{ 'household.New comment and expecting birth'|trans }}
</a>
{% endif %}
{% else %}
{{ form_start(form) }}
<div id="waitingForBirthContainer">
{{ form_widget(form.waitingForBirth) }}
</div>
<div id="waitingForBirthDateContainer">
{{ form_widget(form.waitingForBirthDate) }}
</div>
<div class="mt-3">
{{ form_widget(form.commentMembers) }}
</div>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save" id="form_household_comment_confirm">
{{ 'Save'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}
{% endif %}
</div>
</div> </div>
<h2 class="my-5">{{ 'household.Household members'|trans }}</h2> <h2 class="my-5">{{ 'household.Household members'|trans }}</h2>
@@ -153,7 +155,7 @@
{% endif %} {% endif %}
{% if not (p == '_none' and members|length == 0 and old_members|length == 0) %} {% if not (p == '_none' and members|length == 0 and old_members|length == 0) %}
<div class="mb-5"> <div class="mb-5 pop-item">
{% if p != '_none' %} {% if p != '_none' %}
<h3>{{ p.label|localize_translatable_string }} <h3>{{ p.label|localize_translatable_string }}
{% if false == p.shareHousehold %} {% if false == p.shareHousehold %}

View File

@@ -94,6 +94,10 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
'label' => 'Birthdate before', 'label' => 'Birthdate before',
'required' => false, 'required' => false,
]) ])
->add('birthdate-after', ChillDateType::class, [
'label' => 'Birthdate after',
'required' => false,
])
->add('phonenumber', TelType::class, [ ->add('phonenumber', TelType::class, [
'required' => false, 'required' => false,
'label' => 'Part of the phonenumber', 'label' => 'Part of the phonenumber',

View File

@@ -44,7 +44,6 @@ class AccompanyingPeriodDocGenNormalizer implements ContextAwareNormalizerInterf
private const PERIOD_NULL = [ private const PERIOD_NULL = [
'id', 'id',
'closingDate' => DateTime::class, 'closingDate' => DateTime::class,
'closingMotive' => AccompanyingPeriod\ClosingMotive::class,
'confidential', 'confidential',
'confidentialText', 'confidentialText',
'createdAt' => DateTime::class, 'createdAt' => DateTime::class,

View File

@@ -1,39 +0,0 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Controller;
use Chill\MainBundle\Test\PrepareClientTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* @internal
* @coversNothing
*/
final class AccompanyingPeriodRegulationListControllerTest extends WebTestCase
{
use PrepareClientTrait;
protected function setUp(): void
{
parent::setUp();
self::bootKernel();
}
public function testRegulationList(): void
{
$client = $this->getClientAuthenticated();
$client->request('GET', '/fr/person/periods/undispatched');
$this->assertResponseIsSuccessful();
}
}

View File

@@ -13,7 +13,6 @@ namespace Chill\PersonBundle\Tests\Controller;
use Chill\MainBundle\Test\PrepareClientTrait; use Chill\MainBundle\Test\PrepareClientTrait;
use DateTime; use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DomCrawler\Form; use Symfony\Component\DomCrawler\Form;
@@ -49,21 +48,21 @@ final class PersonControllerCreateTest extends WebTestCase
public static function tearDownAfterClass(): void public static function tearDownAfterClass(): void
{ {
self::bootKernel(); self::bootKernel();
$em = self::$kernel->getContainer()->get(EntityManagerInterface::class); $em = self::$kernel->getContainer()->get('doctrine.orm.entity_manager');
//remove two people created during test //remove two people created during test
$jesus = $em->getRepository(\Chill\PersonBundle\Entity\Person::class) $jesus = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)
->findOneBy(['firstName' => 'God']); ->findOneBy(['firstName' => 'God']);
if (null !== $jesus) { if (null !== $jesus) {
//$em->remove($jesus); $em->remove($jesus);
} }
$jesus2 = $em->getRepository(\Chill\PersonBundle\Entity\Person::class) $jesus2 = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)
->findOneBy(['firstName' => 'roger']); ->findOneBy(['firstName' => 'roger']);
if (null !== $jesus2) { if (null !== $jesus2) {
//$em->remove($jesus2); $em->remove($jesus2);
} }
$em->flush(); $em->flush();
} }

View File

@@ -11,12 +11,9 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Controller; namespace Chill\PersonBundle\Tests\Controller;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Repository\CenterRepository;
use Chill\MainBundle\Test\PrepareClientTrait; use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Closure; use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/** /**
@@ -58,17 +55,12 @@ final class PersonControllerUpdateTest extends WebTestCase
{ {
self::bootKernel(); self::bootKernel();
$this->em = self::$container $this->em = self::$kernel->getContainer()
->get(EntityManagerInterface::class); ->get('doctrine.orm.entity_manager');
$center = self::$container->get(CenterRepository::class) $center = $this->em->getRepository(\Chill\MainBundle\Entity\Center::class)
->findOneBy(['name' => 'Center A']); ->findOneBy(['name' => 'Center A']);
var_dump(array_map(
function (Center $c) { return $c->getName(); },
self::$container->get(CenterRepository::class)->findAll()
));
$this->person = (new Person()) $this->person = (new Person())
->setLastName('My Beloved') ->setLastName('My Beloved')
->setFirstName('Jesus') ->setFirstName('Jesus')

View File

@@ -65,7 +65,6 @@ final class AccompanyingPeriodDocGenNormalizerTest extends KernelTestCase
'type' => 'accompanying_period', 'type' => 'accompanying_period',
'isNull' => false, 'isNull' => false,
'closingDate' => '@ignored', 'closingDate' => '@ignored',
'closingMotive' => '@ignored',
'confidential' => true, 'confidential' => true,
'confidentialText' => 'confidentiel', 'confidentialText' => 'confidentiel',
'createdAt' => '@ignored', 'createdAt' => '@ignored',
@@ -122,7 +121,59 @@ final class AccompanyingPeriodDocGenNormalizerTest extends KernelTestCase
{ {
$data = $this->normalizer->normalize(null, 'docgen', ['docgen:expects' => AccompanyingPeriod::class]); $data = $this->normalizer->normalize(null, 'docgen', ['docgen:expects' => AccompanyingPeriod::class]);
$expected = [
'id' => '',
'type' => 'accompanying_period',
'closingDate' => '@ignored',
'confidential' => false,
'confidentialText' => '',
'createdAt' => '@ignored',
'createdBy' => '@ignored',
'emergency' => false,
'emergencyText' => '',
'openingDate' => '@ignored',
'originText' => '',
'origin' => '@ignored',
'requestorAnonymous' => false,
'resources' => [],
'socialIssues' => '@ignored',
'intensity' => '',
'step' => '',
'closingMotiveText' => '',
'socialIssuesText' => '',
'scopes' => '@ignored',
'scopesText' => '',
'ref' => '@ignored',
'participations' => '@ignored',
'currentParticipations' => '@ignored',
'isClosed' => false,
'hasRef' => false,
'hasRequestor' => false,
'requestorKind' => 'none',
'hasRequestorPerson' => false,
'hasRequestorThirdParty' => false,
'requestorPerson' => '@ignored',
'requestorThirdParty' => '@ignored',
'isNull' => true,
'administrativeLocation' => '@ignored',
'hasAdministrativeLocation' => false,
'hasLocation' => false,
'hasLocationPerson' => false,
'location' => '@ignored',
'locationPerson' => '@ignored',
'works' => [],
];
$this->assertIsArray($data); $this->assertIsArray($data);
$this->assertEqualsCanonicalizing(array_keys($expected), array_keys($data));
foreach ($expected as $key => $item) {
if ('@ignored' === $item) {
continue;
}
$this->assertEquals($item, $data[$key], "test the key {$key}");
}
} }
public function testNormalizeParticipations() public function testNormalizeParticipations()

View File

@@ -88,7 +88,6 @@ All genders: tous les genres
Any person selected: Aucune personne sélectionnée Any person selected: Aucune personne sélectionnée
Create a household and add an address: Ajouter une adresse pour un usager non suivi et seul dans un ménage Create a household and add an address: Ajouter une adresse pour un usager non suivi et seul dans un ménage
A new household will be created. The person will be member of this household.: Un nouveau ménage va être créé. L'usager sera membre de ce ménage. A new household will be created. The person will be member of this household.: Un nouveau ménage va être créé. L'usager sera membre de ce ménage.
Comment on the gender: Commentaire sur le genre
# dédoublonnage # dédoublonnage
Old person: Doublon Old person: Doublon

View File

@@ -7,15 +7,12 @@
&.place-new { &.place-new {
background-color: $chill-yellow; background-color: $chill-yellow;
} }
&.place-in_progress { &.place-in_progress {
background-color: $chill-green; background-color: $chill-green;
} }
&.place-closed { &.place-closed {
background-color: $chill-blue; background-color: $chill-blue;
} }
&.place-canceled { &.place-canceled {
background-color: $chill-beige; background-color: $chill-beige;
} }

View File

@@ -1,71 +1,68 @@
<div class="task-show"> <div class="task-show">
<h1>{{ 'Task'|trans }}</h1> {# <h1 class="content-title">{{ 'Task'|trans }}</h1> #}
<h2>{{ task.title }} <h2 style="margin-bottom: 1rem;">{{ task.title }}
{% for place in workflow_marked_places(task) %} {% for place in workflow_marked_places(task) %}
<span class="task-status box type-{{ task.type }} place-{{ place }}">{{ place|trans }}</span> <span class="task-status badge rounded-pill box type-{{ task.type }} place-{{ place }}">{{ place|trans }}</span>
{% endfor %} {% endfor %}
</h2> </h2>
<dl class="chill_view_data"> <div class="pop-item">
<dl class="chill_view_data">
<dt class="inline">{{ 'Description'|trans }}</dt> <dt class="inline">{{ 'Description'|trans }}</dt>
<dd>
{% if task.description is empty %}
<span class="chill-no-data-statement">{{"No description"|trans}}</span>
{% else %}
<blockquote class="chill-user-quote">
{{ task.description|chill_markdown_to_html }}
</blockquote>
{% endif %}
</dd>
<dt class="inline">{{ 'Assignee'|trans }}</dt>
<dd>
{% if task.assignee is null %}
<span class="chill-no-data-statement">{{"No one assignee"|trans}}</span>
{% else %}
{{ task.assignee }}
{% endif %}
</dd>
{% if task.scope is not null %}
<dt class="inline">{{ 'Scope'|trans }}</dt>
<dd> <dd>
<span class="scope">{{ task.scope.name|localize_translatable_string }}</span> {% if task.description is empty %}
<span class="chill-no-data-statement">{{"No description"|trans}}</span>
{% else %}
<blockquote class="chill-user-quote">
{{ task.description|chill_markdown_to_html }}
</blockquote>
{% endif %}
</dd> </dd>
{% endif %} <dt class="inline">{{ 'Assignee'|trans }}</dt>
<dd class="info-field">
<h3>{{"Dates"|trans}}</h3> {% if task.assignee is null %}
{% if task.startDate is null and task.endDate is null and task.warningDate is null %} <span class="chill-no-data-statement">{{"No one assignee"|trans}}</span>
<dt></dt> {% else %}
<dd> {{ task.assignee }}
<span class="chill-no-data-statement">{{"No dates specified"|trans}}</span> {% endif %}
</dd> </dd>
</dt> {% if task.scope is not null %}
{% else %} <dt class="inline">{{ 'Scope'|trans }}</dt>
{% if task.startDate is not null %} <dd class="info-field">
<dt class="inline">{{ 'Start'|trans }}</dt> <span class="scope">{{ task.scope.name|localize_translatable_string }}</span>
<dd>{{ task.startDate|format_date('long') }}</dd> </dd>
{% endif %}
<h3 class="subtitle">{{"Dates"|trans}}</h3>
{% if task.startDate is null and task.endDate is null and task.warningDate is null %}
<dt></dt>
<dd class="info-field">
<span class="chill-no-data-statement">{{"No dates specified"|trans}}</span>
</dd>
</dt>
{% else %}
{% if task.startDate is not null %}
<dt class="inline">{{ 'Start'|trans }}</dt>
<dd class="info-field">{{ task.startDate|format_date('long') }}</dd>
{% endif %}
{% if task.endDate is not null %}
<dt class="inline">{{ 'End'|trans }}</dt>
<dd class="info-field">{{ task.endDate|format_date('long') }}</dd>
{% endif %}
{% if task.warningDate is not null %}
<dt class="inline">{{ 'Warning'|trans }}</dt>
<dd class="info-field">{{ task.warningDate|format_date('long') }}</dd>
{% endif %}
{% endif %} {% endif %}
</dl>
{% if task.endDate is not null %} </div>
<dt class="inline">{{ 'End'|trans }}</dt>
<dd>{{ task.endDate|format_date('long') }}</dd>
{% endif %}
{% if task.warningDate is not null %}
<dt class="inline">{{ 'Warning'|trans }}</dt>
<dd>{{ task.warningDate|format_date('long') }}</dd>
{% endif %}
{% endif %}
</dl>
{% if timeline is not null %} {% if timeline is not null %}
<h3>{{"Timeline"|trans}}</h3> <div class="pop-item">
{{ timeline|raw }} <h3 class="subtitle">{{"Timeline"|trans}}</h3>
{{ timeline|raw }}
</div>
{% endif %} {% endif %}
<ul class="record_actions sticky-form-buttons"> <ul class="record_actions sticky-form-buttons">

View File

@@ -767,9 +767,9 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
return $this; return $this;
} }
public function setFirstname(?string $firstname): self public function setFirstname(string $firstname): self
{ {
$this->firstname = trim((string) $firstname); $this->firstname = $firstname;
return $this; return $this;
} }
@@ -781,9 +781,9 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
return $this; return $this;
} }
public function setName(?string $name): self public function setName($name): self
{ {
$this->name = (string) $name; $this->name = $name;
return $this; return $this;
} }