mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
Merge remote-tracking branch 'origin/master' into calendar/finalization
This commit is contained in:
commit
59e24ff39d
17
CHANGELOG.md
17
CHANGELOG.md
@ -11,6 +11,21 @@ and this project adheres to
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
<!-- write down unreleased development here -->
|
<!-- write down unreleased development here -->
|
||||||
|
* [workflow]: added pagination to workflow list page
|
||||||
|
* [homepage_widget]: null error on tasks widget fixed
|
||||||
|
* [person-thirdparty]: fix quick-add of names that consist of multiple parts (eg. De Vlieger) within onthefly modal person/thirdparty
|
||||||
|
* [search]: Order of birthdate fields changed in advanced search to avoid confusion.
|
||||||
|
* [workflow]: Constraint added to workflow (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/675)
|
||||||
|
* [action]: Agents traitants should be prefilled with referrer of the parcours or left empty if there is no referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/696)
|
||||||
|
|
||||||
|
## Test releases
|
||||||
|
|
||||||
|
### 2022-05-30
|
||||||
|
|
||||||
|
* fix creating a new AccompanyingPeriodWorkEvaluationDocument when replacing the document (the workflow was lost)
|
||||||
|
|
||||||
|
### 2022-05-27
|
||||||
|
|
||||||
* [storedobject] add title field on StoredObject entity + use it in activity documents (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/604)
|
* [storedobject] add title field on StoredObject entity + use it in activity documents (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/604)
|
||||||
* [main] add a "read more..." on comment embeddable when overflown (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/604)
|
* [main] add a "read more..." on comment embeddable when overflown (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/604)
|
||||||
* [person] add closing motive to closed acc course (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/603)
|
* [person] add closing motive to closed acc course (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/603)
|
||||||
@ -28,8 +43,6 @@ and this project adheres to
|
|||||||
* [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)
|
||||||
|
|
||||||
|
|
||||||
## Test releases
|
|
||||||
|
|
||||||
### 2022-05-06
|
### 2022-05-06
|
||||||
|
|
||||||
* [person] add civility when creating a person (with the on-the-fly component or in the php form) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/557)
|
* [person] add civility when creating a person (with the on-the-fly component or in the php form) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/557)
|
||||||
|
@ -2,12 +2,30 @@
|
|||||||
{% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) %}
|
{% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) %}
|
||||||
{% if no_action is not defined or no_action == false %}
|
{% if no_action is not defined or no_action == false %}
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-misc" href="{{ chill_path_add_return_path('chill_main_notification_create', {
|
{% set showGroup = activity.accompanyingPeriod is not null and activity.accompanyingPeriod.hasUser and activity.accompanyingPeriod.user is not same as(app.user) %}
|
||||||
'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity',
|
<div class="{% if showGroup %}btn-group{% endif %}" {% if showGroup %}role="group"{% endif %}>
|
||||||
'entityId': activity.id
|
{% if showGroup %}
|
||||||
}) }}">
|
<button id="btnGroupNotifyButtons" type="button" class="btn btn-notify dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="fa fa-paper-plane fa-fw"></i>
|
{{ 'notification.Notify'|trans }}
|
||||||
{{ 'notification.Notify'|trans }}</a>
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnGroupNotifyButtons">
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': activity.id, 'tos': [activity.accompanyingPeriod.user.id]}) }}">
|
||||||
|
{{ 'notification.Notify referrer'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': activity.id}) }}">
|
||||||
|
{{ 'notification.Notify any'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<a class="btn btn-notify" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': activity.id}) }}">
|
||||||
|
{{ 'notification.Notify'|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if context == 'person' and activity.accompanyingPeriod is not empty %}
|
{% if context == 'person' and activity.accompanyingPeriod is not empty %}
|
||||||
|
@ -217,9 +217,30 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-notify" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': entity.id}) }}">
|
{% set showGroup = entity.accompanyingPeriod is not null and entity.accompanyingPeriod.hasUser and entity.accompanyingPeriod.user is not same as(app.user) %}
|
||||||
{{ 'notification.Notify'|trans }}
|
<div class="{% if showGroup %}btn-group{% endif %}" {% if showGroup %}role="group"{% endif %}>
|
||||||
</a>
|
{% if showGroup %}
|
||||||
|
<button id="btnGroupNotifyButtons" type="button" class="btn btn-notify dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{{ 'notification.Notify'|trans }}
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnGroupNotifyButtons">
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': entity.id, 'tos': [entity.accompanyingPeriod.user.id]}) }}">
|
||||||
|
{{ 'notification.Notify referrer'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': entity.id}) }}">
|
||||||
|
{{ 'notification.Notify any'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<a class="btn btn-notify" href="{{ chill_path_add_return_path('chill_main_notification_create', {'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity', 'entityId': entity.id}) }}">
|
||||||
|
{{ 'notification.Notify'|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% if is_granted('CHILL_ACTIVITY_UPDATE', entity) %}
|
{% if is_granted('CHILL_ACTIVITY_UPDATE', entity) %}
|
||||||
<li>
|
<li>
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
<?php
|
<?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);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Chill\Migrations\Calendar;
|
namespace Chill\Migrations\Calendar;
|
||||||
@ -9,6 +16,12 @@ use Doctrine\Migrations\AbstractMigration;
|
|||||||
|
|
||||||
final class Version20220527234046 extends AbstractMigration
|
final class Version20220527234046 extends AbstractMigration
|
||||||
{
|
{
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
public function getDescription(): string
|
public function getDescription(): string
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
@ -19,12 +32,5 @@ final class Version20220527234046 extends AbstractMigration
|
|||||||
$this->addSql('UPDATE chill_calendar.calendar SET privateComment_comments=\'{}\' WHERE privateComment_comments IS NULL');
|
$this->addSql('UPDATE chill_calendar.calendar SET privateComment_comments=\'{}\' WHERE privateComment_comments IS NULL');
|
||||||
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET NOT NULL');
|
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET NOT NULL');
|
||||||
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET DEFAULT \'{}\'');
|
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET DEFAULT \'{}\'');
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments DROP NOT NULL');
|
|
||||||
$this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET DEFAULT NULL');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,9 @@ class PrivateCommentEmbeddable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCommentForUser(User $user, string $content): self
|
public function setCommentForUser(User $user, ?string $content): self
|
||||||
{
|
{
|
||||||
$this->comments[$user->getId()] = trim($content);
|
$this->comments[$user->getId()] = trim((string) $content);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ class UserCurrentLocationType extends AbstractType
|
|||||||
},
|
},
|
||||||
'placeholder' => 'Pick a location',
|
'placeholder' => 'Pick a location',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
'attr' => ['class' => 'select2'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@ class WorkflowStepType extends AbstractType
|
|||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
'choices' => $choices,
|
'choices' => $choices,
|
||||||
|
'constraints' => [new NotNull()],
|
||||||
'choice_label' => function (Transition $transition) use ($workflow) {
|
'choice_label' => function (Transition $transition) use ($workflow) {
|
||||||
$meta = $workflow->getMetadataStore()->getTransitionMetadata($transition);
|
$meta = $workflow->getMetadataStore()->getTransitionMetadata($transition);
|
||||||
|
|
||||||
@ -208,24 +209,28 @@ class WorkflowStepType extends AbstractType
|
|||||||
$transition = $form['transition']->getData();
|
$transition = $form['transition']->getData();
|
||||||
$toFinal = true;
|
$toFinal = true;
|
||||||
|
|
||||||
foreach ($transition->getTos() as $to) {
|
if (null === $transition) {
|
||||||
$meta = $workflow->getMetadataStore()->getPlaceMetadata($to);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!array_key_exists('isFinal', $meta) || false === $meta['isFinal']
|
|
||||||
) {
|
|
||||||
$toFinal = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$destUsers = $form['future_dest_users']->getData();
|
|
||||||
$destEmails = $form['future_dest_emails']->getData();
|
|
||||||
|
|
||||||
if (!$toFinal && [] === $destUsers && [] === $destEmails) {
|
|
||||||
$context
|
$context
|
||||||
->buildViolation('workflow.You must add at least one dest user or email')
|
->buildViolation('workflow.You must select a next step, pick another decision if no next steps are available');
|
||||||
->atPath('future_dest_users')
|
} else {
|
||||||
->addViolation();
|
foreach ($transition->getTos() as $to) {
|
||||||
|
$meta = $workflow->getMetadataStore()->getPlaceMetadata($to);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!array_key_exists('isFinal', $meta) || false === $meta['isFinal']
|
||||||
|
) {
|
||||||
|
$toFinal = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$destUsers = $form['future_dest_users']->getData();
|
||||||
|
$destEmails = $form['future_dest_emails']->getData();
|
||||||
|
|
||||||
|
if (!$toFinal && [] === $destUsers && [] === $destEmails) {
|
||||||
|
$context
|
||||||
|
->buildViolation('workflow.You must add at least one dest user or email')
|
||||||
|
->atPath('future_dest_users')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
@ -15,26 +15,69 @@
|
|||||||
<span v-if="forceRedirect">{{ $t('wait_redirection') }}</span>
|
<span v-if="forceRedirect">{{ $t('wait_redirection') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showMessageWhenNoAddress" class="mt-5">
|
<div v-if="(!this.context.edit && !this.flag.success && this.context.target.name !== 'household')" class="mt-5">
|
||||||
<p class="chill-no-data-statement">
|
<div class="no-address-yet">
|
||||||
{{ $t('not_yet_address') }}
|
<i class="fa fa-map-marker" aria-hidden="true"></i>
|
||||||
</p>
|
<p class="chill-no-data-statement">
|
||||||
|
{{ $t('not_yet_address') }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<action-buttons
|
||||||
|
:options="this.options"
|
||||||
|
:defaultz="this.defaultz"
|
||||||
|
class="add-address-btn">
|
||||||
|
<template v-slot:action>
|
||||||
|
<button @click.prevent="$emit('openEditPane')"
|
||||||
|
class="btn" :class="getClassButton"
|
||||||
|
type="button" name="button" :title="$t(getTextButton)">
|
||||||
|
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</action-buttons>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="this.context.edit" class="mb-3 row">
|
||||||
|
<div class="col-sm-4"></div>
|
||||||
|
<div class="address-container col-sm-8">
|
||||||
|
<address-render-box :address="address" :isMultiline="false" :useDatePane="useDatePane"></address-render-box>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="this.context.target.name === 'household' || this.context.edit">
|
||||||
|
<action-buttons
|
||||||
|
:options="this.options"
|
||||||
|
:defaultz="this.defaultz">
|
||||||
|
<template v-slot:action>
|
||||||
|
<button @click.prevent="$emit('openEditPane')"
|
||||||
|
class="btn btn-sm" :class="getClassButton"
|
||||||
|
type="button" name="button" :title="$t(getTextButton)">
|
||||||
|
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</action-buttons>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!this.context.edit">
|
||||||
|
<address-render-box :address="address" :isMultiline="false" :useDatePane="useDatePane"></address-render-box>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<address-render-box :address="address" :useDatePane="useDatePane"></address-render-box>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<action-buttons
|
<div v-if="onlyButton">
|
||||||
:options="this.options"
|
<action-buttons
|
||||||
:defaultz="this.defaultz">
|
:options="this.options"
|
||||||
<template v-slot:action>
|
:defaultz="this.defaultz"
|
||||||
<button @click.prevent="$emit('openEditPane')"
|
class="add-address-btn">
|
||||||
class="btn" :class="getClassButton"
|
<template v-slot:action>
|
||||||
type="button" name="button" :title="$t(getTextButton)">
|
<button @click.prevent="$emit('openEditPane')"
|
||||||
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
class="btn" :class="getClassButton"
|
||||||
</button>
|
type="button" name="button" :title="$t(getTextButton)">
|
||||||
</template>
|
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
||||||
</action-buttons>
|
</button>
|
||||||
|
</template>
|
||||||
|
</action-buttons>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -58,6 +101,9 @@ export default {
|
|||||||
'useDatePane'
|
'useDatePane'
|
||||||
],
|
],
|
||||||
emits: ['openEditPane'],
|
emits: ['openEditPane'],
|
||||||
|
mounted() {
|
||||||
|
console.log('context', this.context)
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
address() {
|
address() {
|
||||||
return this.entity.address;
|
return this.entity.address;
|
||||||
@ -91,13 +137,35 @@ export default {
|
|||||||
forceRedirect() {
|
forceRedirect() {
|
||||||
return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
|
return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
|
||||||
},
|
},
|
||||||
showMessageWhenNoAddress() {
|
// showMessageWhenNoAddress() {
|
||||||
let showMessageWhenNoAddress = this.options.showMessageWhenNoAddress === undefined ? this.defaultz.showMessageWhenNoAddress : this.options.showMessageWhenNoAddress;
|
// let showMessageWhenNoAddress = this.options.showMessageWhenNoAddress === undefined ? this.defaultz.showMessageWhenNoAddress : this.options.showMessageWhenNoAddress;
|
||||||
if (showMessageWhenNoAddress === true || showMessageWhenNoAddress === false) {
|
// if (showMessageWhenNoAddress === true || showMessageWhenNoAddress === false) {
|
||||||
return !this.context.edit && !this.address.id && showMessageWhenNoAddress;
|
// return !this.context.edit && !this.address.id && showMessageWhenNoAddress;
|
||||||
}
|
// }
|
||||||
return !this.context.edit && !this.address.id && this.options.stickyActions;
|
// return !this.context.edit && !this.address.id && this.options.stickyActions;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.address-container {
|
||||||
|
display:flex;
|
||||||
|
justify-content:flex-end;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.no-address-yet {
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||||
|
padding:1.5rem;
|
||||||
|
margin-bottom:2rem;
|
||||||
|
i {
|
||||||
|
font-size:2rem;
|
||||||
|
margin-bottom:2rem;
|
||||||
|
}
|
||||||
|
.add-address-btn {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="alert alert-light">{{ $t('my_tasks.description_warning') }}</div>
|
<div class="alert alert-light">{{ $t('my_tasks.description_warning') }}</div>
|
||||||
<span v-if="noResultsAlert" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
<span v-if="noResultsAlert" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
@ -11,7 +11,8 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-slot:tbody>
|
<template v-slot:tbody>
|
||||||
<tr v-for="(t, i) in tasks.alert.results" :key="`task-alert-${i}`">
|
<tr v-for="(t, i) in tasks.alert.results" :key="`task-alert-${i}`">
|
||||||
<td>{{ $d(t.warningDate.datetime, 'short') }}</td>
|
<td v-if="null !== t.warningDate">{{ $d(t.warningDate.datetime, 'short') }}</td>
|
||||||
|
<td v-else></td>
|
||||||
<td>
|
<td>
|
||||||
<span class="outdated">{{ $d(t.endDate.datetime, 'short') }}</span>
|
<span class="outdated">{{ $d(t.endDate.datetime, 'short') }}</span>
|
||||||
</td>
|
</td>
|
||||||
@ -24,7 +25,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
</tab-table>
|
</tab-table>
|
||||||
|
|
||||||
<div class="alert alert-light">{{ $t('my_tasks.description_alert') }}</div>
|
<div class="alert alert-light">{{ $t('my_tasks.description_alert') }}</div>
|
||||||
<span v-if="noResultsWarning" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
<span v-if="noResultsWarning" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
@ -49,7 +50,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
</tab-table>
|
</tab-table>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -115,5 +115,6 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -16,6 +16,7 @@ use Chill\MainBundle\Notification\Counter\NotificationByUserCounter;
|
|||||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
use Chill\MainBundle\Workflow\Counter\WorkflowByUserCounter;
|
use Chill\MainBundle\Workflow\Counter\WorkflowByUserCounter;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
|
|
||||||
private NotificationByUserCounter $notificationByUserCounter;
|
private NotificationByUserCounter $notificationByUserCounter;
|
||||||
|
|
||||||
|
private RequestStack $requestStack;
|
||||||
|
|
||||||
private Security $security;
|
private Security $security;
|
||||||
|
|
||||||
private TranslatorInterface $translator;
|
private TranslatorInterface $translator;
|
||||||
@ -36,13 +39,15 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
WorkflowByUserCounter $workflowByUserCounter,
|
WorkflowByUserCounter $workflowByUserCounter,
|
||||||
Security $security,
|
Security $security,
|
||||||
TranslatorInterface $translator,
|
TranslatorInterface $translator,
|
||||||
ParameterBagInterface $parameterBag
|
ParameterBagInterface $parameterBag,
|
||||||
|
RequestStack $requestStack
|
||||||
) {
|
) {
|
||||||
$this->notificationByUserCounter = $notificationByUserCounter;
|
$this->notificationByUserCounter = $notificationByUserCounter;
|
||||||
$this->workflowByUserCounter = $workflowByUserCounter;
|
$this->workflowByUserCounter = $workflowByUserCounter;
|
||||||
$this->security = $security;
|
$this->security = $security;
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
$this->parameterBag = $parameterBag;
|
$this->parameterBag = $parameterBag;
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters)
|
public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters)
|
||||||
@ -59,7 +64,12 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
$menu
|
$menu
|
||||||
->addChild(
|
->addChild(
|
||||||
$locationTextMenu,
|
$locationTextMenu,
|
||||||
['route' => 'chill_main_user_currentlocation_edit']
|
[
|
||||||
|
'route' => 'chill_main_user_currentlocation_edit',
|
||||||
|
'routeParameters' => [
|
||||||
|
'returnPath' => $this->requestStack->getCurrentRequest()->getRequestUri(),
|
||||||
|
],
|
||||||
|
]
|
||||||
)
|
)
|
||||||
->setExtras([
|
->setExtras([
|
||||||
'order' => -9999999,
|
'order' => -9999999,
|
||||||
|
@ -463,6 +463,7 @@ workflow:
|
|||||||
Previous transitionned: Anciens workflows
|
Previous transitionned: Anciens workflows
|
||||||
Previous workflow transitionned help: Workflows où vous avez exécuté une action.
|
Previous workflow transitionned help: Workflows où vous avez exécuté une action.
|
||||||
For: Pour
|
For: Pour
|
||||||
|
You must select a next step, pick another decision if no next steps are available: Il faut une prochaine étape. Choissisez une autre décision si nécessaire.
|
||||||
|
|
||||||
|
|
||||||
Subscribe final: Recevoir une notification à l'étape finale
|
Subscribe final: Recevoir une notification à l'étape finale
|
||||||
|
@ -0,0 +1,167 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
||||||
|
}
|
@ -692,6 +692,10 @@ class AccompanyingPeriod implements
|
|||||||
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->getStep() === self::STEP_CLOSED) {
|
||||||
|
return [[self::STEP_DRAFT, self::STEP_CONFIRMED, self::STEP_CLOSED]];
|
||||||
|
}
|
||||||
|
|
||||||
throw new LogicException('no validation group permitted with this step: ' . $this->getStep());
|
throw new LogicException('no validation group permitted with this step: ' . $this->getStep());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity
|
* @ORM\Entity
|
||||||
@ -31,20 +30,20 @@ class Origin
|
|||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue
|
* @ORM\GeneratedValue
|
||||||
* @ORM\Column(type="integer")
|
* @ORM\Column(type="integer")
|
||||||
* @Groups({"read", "docgen:read"})
|
* @Serializer\Groups({"read", "docgen:read"})
|
||||||
*/
|
*/
|
||||||
private ?int $id = null;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="json")
|
* @ORM\Column(type="json")
|
||||||
* @Groups({"read", "docgen:read"})
|
* @Serializer\Groups({"read", "docgen:read"})
|
||||||
* @Serializer\Context({"is-translatable": true}, groups={"docgen:read"})
|
* @Serializer\Context({"is-translatable": true}, groups={"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private array $label = [];
|
private array $label = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="date_immutable", nullable=true)
|
* @ORM\Column(type="date_immutable", nullable=true)
|
||||||
* @Groups({"read"})
|
* @Serializer\Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private ?DateTimeImmutable $noActiveAfter = null;
|
private ?DateTimeImmutable $noActiveAfter = null;
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ 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,8 +25,10 @@ class AccompanyingPeriodWorkEventListener
|
|||||||
|
|
||||||
public function prePersistAccompanyingPeriodWork(AccompanyingPeriodWork $work): void
|
public function prePersistAccompanyingPeriodWork(AccompanyingPeriodWork $work): void
|
||||||
{
|
{
|
||||||
if ($this->security->getUser() instanceof User) {
|
$referrer = $work->getAccompanyingPeriod()->getUser();
|
||||||
$work->addReferrer($this->security->getUser());
|
|
||||||
|
if (null !== $referrer) {
|
||||||
|
$work->addReferrer($referrer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,13 @@ 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\Authorization\AuthorizationCheckerInterface;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,20 +25,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(AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator, ParameterBagInterface $parameterBag)
|
public function __construct(ParameterBagInterface $parameterBag, Security $security, TranslatorInterface $translator)
|
||||||
{
|
{
|
||||||
$this->authorizationChecker = $authorizationChecker;
|
|
||||||
$this->translator = $translator;
|
|
||||||
$this->parameterBag = $parameterBag;
|
$this->parameterBag = $parameterBag;
|
||||||
|
$this->security = $security;
|
||||||
|
$this->translator = $translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +46,7 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
*/
|
*/
|
||||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
{
|
{
|
||||||
if ($this->authorizationChecker->isGranted(PersonVoter::CREATE) && $this->parameterBag->get('chill_person.create_person_allowed')) {
|
if ($this->security->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',
|
||||||
])
|
])
|
||||||
@ -65,7 +66,7 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->authorizationChecker->isGranted(AccompanyingPeriodVoter::REASSIGN_BULK, null)) {
|
if ($this->security->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',
|
||||||
])
|
])
|
||||||
@ -74,6 +75,16 @@ 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
|
||||||
|
@ -11,13 +11,19 @@ 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;
|
||||||
|
|
||||||
@ -62,6 +68,15 @@ 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) {
|
||||||
@ -126,6 +141,23 @@ 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[]
|
||||||
*/
|
*/
|
||||||
@ -146,4 +178,88 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,20 @@ 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(
|
||||||
@ -26,5 +35,13 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -232,6 +232,14 @@ const store = createStore({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let doc = evaluation.documents.find(d => d.key === payload.oldDocument.key);
|
||||||
|
|
||||||
|
if (typeof doc === 'undefined') {
|
||||||
|
console.error('doc not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.storedObject = payload.document.storedObject;
|
||||||
|
return;
|
||||||
let newDocument = Object.assign(
|
let newDocument = Object.assign(
|
||||||
payload.document, {
|
payload.document, {
|
||||||
key: evaluation.documents.length + 1,
|
key: evaluation.documents.length + 1,
|
||||||
|
@ -333,10 +333,10 @@ export default {
|
|||||||
addQueryItem(field, queryItem) {
|
addQueryItem(field, queryItem) {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case 'lastName':
|
case 'lastName':
|
||||||
this.person.lastName = queryItem;
|
this.person.lastName = this.person.lastName ? this.person.lastName += ` ${queryItem}` : queryItem;
|
||||||
break;
|
break;
|
||||||
case 'firstName':
|
case 'firstName':
|
||||||
this.person.firstName = queryItem;
|
this.person.firstName = this.person.firstName ? this.person.firstName += ` ${queryItem}` : queryItem;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -45,7 +45,7 @@ const personMessages = {
|
|||||||
},
|
},
|
||||||
address: {
|
address: {
|
||||||
create_address: "Ajouter une adresse",
|
create_address: "Ajouter une adresse",
|
||||||
show_address_form: "Créer un ménage et ajouter une adresse",
|
show_address_form: "Ajouter une adresse pour un usager non suivi et seul dans un ménage",
|
||||||
warning: "Un nouveau ménage va être créé. L'usager sera membre de ce ménage."
|
warning: "Un nouveau ménage va être créé. L'usager sera membre de ce ménage."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
{% 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 defined %}
|
||||||
|
{% 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 %}
|
||||||
|
|
@ -82,14 +82,14 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
|
|||||||
'label' => 'Last name',
|
'label' => 'Last name',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
->add('birthdate-after', ChillDateType::class, [
|
|
||||||
'label' => 'Birthdate after',
|
|
||||||
'required' => false,
|
|
||||||
])
|
|
||||||
->add('birthdate', ChillDateType::class, [
|
->add('birthdate', ChillDateType::class, [
|
||||||
'label' => 'Birthdate',
|
'label' => 'Birthdate',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
|
->add('birthdate-after', ChillDateType::class, [
|
||||||
|
'label' => 'Birthdate after',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
->add('birthdate-before', ChillDateType::class, [
|
->add('birthdate-before', ChillDateType::class, [
|
||||||
'label' => 'Birthdate before',
|
'label' => 'Birthdate before',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
@ -44,6 +44,7 @@ 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,
|
||||||
@ -121,6 +122,7 @@ class AccompanyingPeriodDocGenNormalizer implements ContextAwareNormalizerInterf
|
|||||||
'type' => 'accompanying_period',
|
'type' => 'accompanying_period',
|
||||||
'isNull' => false,
|
'isNull' => false,
|
||||||
'closingDate' => $this->normalizer->normalize($period->getClosingDate(), $format, $dateContext),
|
'closingDate' => $this->normalizer->normalize($period->getClosingDate(), $format, $dateContext),
|
||||||
|
'closingMotive' => $this->normalizer->normalize($period->getClosingMotive(), $format, array_merge($context, ['docgen:expects' => AccompanyingPeriod\ClosingMotive::class])),
|
||||||
'confidential' => $period->isConfidential(),
|
'confidential' => $period->isConfidential(),
|
||||||
'createdAt' => $this->normalizer->normalize($period->getCreatedAt(), $format, $dateContext),
|
'createdAt' => $this->normalizer->normalize($period->getCreatedAt(), $format, $dateContext),
|
||||||
'createdBy' => $this->normalizer->normalize($period->getCreatedBy(), $format, $userContext),
|
'createdBy' => $this->normalizer->normalize($period->getCreatedBy(), $format, $userContext),
|
||||||
|
@ -35,6 +35,6 @@ final class AccompanyingPeriodOriginNormalizer implements NormalizerInterface
|
|||||||
|
|
||||||
public function supportsNormalization($data, $format = null): bool
|
public function supportsNormalization($data, $format = null): bool
|
||||||
{
|
{
|
||||||
return $data instanceof Origin;
|
return $data instanceof Origin && 'json' === $format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,6 @@ namespace Chill\PersonBundle\Serializer\Normalizer;
|
|||||||
|
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
|
||||||
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
||||||
@ -35,18 +33,6 @@ class AccompanyingPeriodWorkEvaluationDenormalizer implements ContextAwareDenorm
|
|||||||
|
|
||||||
use ObjectToPopulateTrait;
|
use ObjectToPopulateTrait;
|
||||||
|
|
||||||
private EntityManagerInterface $em;
|
|
||||||
|
|
||||||
private AccompanyingPeriodWorkRepository $workRepository;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
AccompanyingPeriodWorkRepository $workRepository,
|
|
||||||
EntityManagerInterface $em
|
|
||||||
) {
|
|
||||||
$this->workRepository = $workRepository;
|
|
||||||
$this->em = $em;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function denormalize($data, $type, $format = null, array $context = [])
|
public function denormalize($data, $type, $format = null, array $context = [])
|
||||||
{
|
{
|
||||||
$evaluation = $this->denormalizer->denormalize($data, $type, $format, array_merge(
|
$evaluation = $this->denormalizer->denormalize($data, $type, $format, array_merge(
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
||||||
|
}
|
@ -11,9 +11,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Tests\Controller;
|
namespace Chill\PersonBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,10 +57,10 @@ final class PersonControllerUpdateTest extends WebTestCase
|
|||||||
{
|
{
|
||||||
self::bootKernel();
|
self::bootKernel();
|
||||||
|
|
||||||
$this->em = self::$kernel->getContainer()
|
$this->em = self::$container
|
||||||
->get('doctrine.orm.entity_manager');
|
->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
$center = $this->em->getRepository(\Chill\MainBundle\Entity\Center::class)
|
$center = $this->em->getRepository(Center::class)
|
||||||
->findOneBy(['name' => 'Center A']);
|
->findOneBy(['name' => 'Center A']);
|
||||||
|
|
||||||
$this->person = (new Person())
|
$this->person = (new Person())
|
||||||
|
@ -65,6 +65,7 @@ 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',
|
||||||
@ -121,59 +122,7 @@ 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()
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
<?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 Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
|
||||||
|
use Chill\PersonBundle\Serializer\Normalizer\AccompanyingPeriodWorkEvaluationDenormalizer;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ReflectionProperty;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
final class AccompanyingPeriodWorkEvaluationDenormalizerTest extends TestCase
|
||||||
|
{
|
||||||
|
private const ENCODED_DATA = ' {
|
||||||
|
"type": "accompanying_period_work_evaluation",
|
||||||
|
"key": 0,
|
||||||
|
"evaluation": {
|
||||||
|
"id": 100,
|
||||||
|
"type": "social_work_evaluation"
|
||||||
|
},
|
||||||
|
"startDate": {
|
||||||
|
"datetime": "2022-04-29T00:00:00+02:00"
|
||||||
|
},
|
||||||
|
"endDate": null,
|
||||||
|
"maxDate": null,
|
||||||
|
"warningInterval": "P0D",
|
||||||
|
"comment": "",
|
||||||
|
"documents": [
|
||||||
|
{
|
||||||
|
"type": "accompanying_period_work_evaluation_document",
|
||||||
|
"id": 1,
|
||||||
|
"storedObject": {
|
||||||
|
"creationDate": {
|
||||||
|
"datetime": "2022-05-30T21:22:47+0200"
|
||||||
|
},
|
||||||
|
"datas": [],
|
||||||
|
"filename": "ZeoWSjqVc2qN1XUHptTV6S",
|
||||||
|
"id": 11,
|
||||||
|
"iv": [
|
||||||
|
89,
|
||||||
|
164,
|
||||||
|
162,
|
||||||
|
48,
|
||||||
|
155,
|
||||||
|
159,
|
||||||
|
69,
|
||||||
|
135,
|
||||||
|
191,
|
||||||
|
241,
|
||||||
|
241,
|
||||||
|
8,
|
||||||
|
17,
|
||||||
|
56,
|
||||||
|
183,
|
||||||
|
224
|
||||||
|
],
|
||||||
|
"keyInfos": {
|
||||||
|
"alg": "A256CBC",
|
||||||
|
"ext": true,
|
||||||
|
"k": "uW4d7si_hi--VQHxi76ZllKQiYzaEJYGN8KBrWXxi7s",
|
||||||
|
"key_ops": [
|
||||||
|
"encrypt",
|
||||||
|
"decrypt"
|
||||||
|
],
|
||||||
|
"kty": "oct"
|
||||||
|
},
|
||||||
|
"title": "",
|
||||||
|
"type": "application/vnd.oasis.opendocument.text",
|
||||||
|
"uuid": "b9dd9eff-a7cf-4a29-89e3-57efc9ed215b"
|
||||||
|
},
|
||||||
|
"title": "test",
|
||||||
|
"key": 2,
|
||||||
|
"workflows_availables": [
|
||||||
|
{
|
||||||
|
"name": "vendee_internal",
|
||||||
|
"text": "Suivi CD85"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"workflows": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 382
|
||||||
|
}';
|
||||||
|
|
||||||
|
public function testAssociatedDocumentIsTheSame()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('not yet finished');
|
||||||
|
$evaluation = new AccompanyingPeriodWorkEvaluation();
|
||||||
|
$doc = new AccompanyingPeriodWorkEvaluationDocument();
|
||||||
|
$doc->setStoredObject($storedObject = new StoredObject());
|
||||||
|
$reflectionProperty = new ReflectionProperty(AccompanyingPeriodWorkEvaluationDocument::class, 'id');
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
$reflectionProperty->setValue($doc, 1);
|
||||||
|
|
||||||
|
$evaluation->addDocument($doc);
|
||||||
|
|
||||||
|
$data = json_decode(self::ENCODED_DATA);
|
||||||
|
$context =
|
||||||
|
[AbstractNormalizer::OBJECT_TO_POPULATE => $evaluation, 'groups' => ['write']];
|
||||||
|
|
||||||
|
$denormalizer = new AccompanyingPeriodWorkEvaluationDenormalizer();
|
||||||
|
|
||||||
|
/*
|
||||||
|
$this->assertTrue(
|
||||||
|
$denormalizer->supportsDenormalization(
|
||||||
|
$data,
|
||||||
|
AccompanyingPeriodWorkEvaluation::class,
|
||||||
|
'json',
|
||||||
|
$context
|
||||||
|
)
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
$denormalizedEvaluation = $denormalizer->denormalize(
|
||||||
|
$data,
|
||||||
|
AccompanyingPeriodWorkEvaluation::class,
|
||||||
|
'json',
|
||||||
|
$context
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame($evaluation, $denormalizedEvaluation);
|
||||||
|
$this->assertCount(1, $evaluation->getDocuments());
|
||||||
|
$this->assertSame($doc, $evaluation->getDocuments()->first());
|
||||||
|
$this->assertNotSame($storedObject, $evaluation->getDocuments()->first()->getStoredObject());
|
||||||
|
}
|
||||||
|
}
|
@ -86,8 +86,9 @@ Civility: Civilité
|
|||||||
choose civility: --
|
choose civility: --
|
||||||
All genders: tous les genres
|
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: Créer un ménage et ajouter une adresse
|
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
|
||||||
|
@ -27,11 +27,7 @@
|
|||||||
} %}
|
} %}
|
||||||
</span>
|
</span>
|
||||||
{% elseif task.course is not null %}
|
{% elseif task.course is not null %}
|
||||||
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': task.course.id }) }}"
|
<div style="margin-bottom: 1rem;">
|
||||||
class="btn btn-sm btn-outline-primary" title="{{ 'See accompanying period'|trans }}">
|
|
||||||
<i class="fa fa-random fa-fw"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% for part in task.course.currentParticipations %}
|
{% for part in task.course.currentParticipations %}
|
||||||
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
|
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
|
||||||
targetEntity: { name: 'person', id: part.person.id },
|
targetEntity: { name: 'person', id: part.person.id },
|
||||||
@ -41,7 +37,11 @@
|
|||||||
isDead: part.person.deathdate is not null
|
isDead: part.person.deathdate is not null
|
||||||
} %}
|
} %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': task.course.id }) }}"
|
||||||
|
class="btn btn-sm btn-outline-primary" title="{{ 'See accompanying period'|trans }}">
|
||||||
|
<i class="fa fa-random fa-fw"></i>
|
||||||
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -80,6 +80,13 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{# {% if task.course is not null %}
|
||||||
|
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': task.course.id }) }}"
|
||||||
|
class="btn btn-sm btn-outline-primary" style="float:right;" title="{{ 'See accompanying period'|trans }}">
|
||||||
|
<i class="fa fa-random fa-fw"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %} #}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -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 = $firstname;
|
$this->firstname = trim((string) $firstname);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -781,9 +781,9 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName($name): self
|
public function setName(?string $name): self
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = (string) $name;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ export default {
|
|||||||
addQueryItem(field, queryItem) {
|
addQueryItem(field, queryItem) {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case 'name':
|
case 'name':
|
||||||
this.thirdparty.name = queryItem;
|
this.thirdparty.name ? this.thirdparty.name += ` ${queryItem}` : this.thirdparty.name = queryItem;
|
||||||
break;
|
break;
|
||||||
case 'firstName':
|
case 'firstName':
|
||||||
this.thirdparty.firstname = queryItem;
|
this.thirdparty.firstname = queryItem;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user