mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 14:43:49 +00:00
Merge branch 'master' into 'issue378_normalize_requestor'
# Conflicts: # CHANGELOG.md
This commit is contained in:
@@ -15,6 +15,7 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
@@ -23,7 +24,7 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class AccompanyingCourseWorkController extends AbstractController
|
||||
{
|
||||
@@ -60,7 +61,7 @@ class AccompanyingCourseWorkController extends AbstractController
|
||||
*/
|
||||
public function createWork(AccompanyingPeriod $period): Response
|
||||
{
|
||||
// TODO ACL
|
||||
$this->denyAccessUnlessGranted(AccompanyingPeriodWorkVoter::CREATE, $period);
|
||||
|
||||
if ($period->getSocialIssues()->count() === 0) {
|
||||
$this->addFlash(
|
||||
@@ -93,7 +94,8 @@ class AccompanyingCourseWorkController extends AbstractController
|
||||
*/
|
||||
public function deleteWork(AccompanyingPeriodWork $work, Request $request): Response
|
||||
{
|
||||
// TODO ACL
|
||||
$this->denyAccessUnlessGranted(AccompanyingPeriodWorkVoter::UPDATE, $work);
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$form = $this->createDeleteForm($work->getId());
|
||||
@@ -138,7 +140,8 @@ class AccompanyingCourseWorkController extends AbstractController
|
||||
*/
|
||||
public function editWork(AccompanyingPeriodWork $work): Response
|
||||
{
|
||||
// TODO ACL
|
||||
$this->denyAccessUnlessGranted(AccompanyingPeriodWorkVoter::UPDATE, $work);
|
||||
|
||||
$json = $this->serializer->normalize($work, 'json', ['groups' => ['read']]);
|
||||
|
||||
return $this->render('@ChillPerson/AccompanyingCourseWork/edit.html.twig', [
|
||||
@@ -157,13 +160,13 @@ class AccompanyingCourseWorkController extends AbstractController
|
||||
*/
|
||||
public function listWorkByAccompanyingPeriod(AccompanyingPeriod $period): Response
|
||||
{
|
||||
// TODO ACL
|
||||
$this->denyAccessUnlessGranted(AccompanyingPeriodWorkVoter::SEE, $period);
|
||||
|
||||
$totalItems = $this->workRepository->countByAccompanyingPeriod($period);
|
||||
$paginator = $this->paginator->create($totalItems);
|
||||
|
||||
$works = $this->workRepository->findByAccompanyingPeriod(
|
||||
$works = $this->workRepository->findByAccompanyingPeriodOpenFirst(
|
||||
$period,
|
||||
['startDate' => 'DESC', 'endDate' => 'DESC'],
|
||||
$paginator->getItemsPerPage(),
|
||||
$paginator->getCurrentPageFirstItemNumber()
|
||||
);
|
||||
|
@@ -50,7 +50,6 @@ class HouseholdApiController extends ApiController
|
||||
*/
|
||||
public function getHouseholdByAddressReference(AddressReference $addressReference): Response
|
||||
{
|
||||
// TODO ACL
|
||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||
|
||||
$total = $this->householdACLAwareRepository->countByAddressReference($addressReference);
|
||||
|
@@ -224,6 +224,8 @@ final class PersonController extends AbstractController
|
||||
'label' => 'Add the person',
|
||||
])->add('createPeriod', SubmitType::class, [
|
||||
'label' => 'Add the person and create an accompanying period',
|
||||
])->add('createHousehold', SubmitType::class, [
|
||||
'label' => 'Add the person and create a household',
|
||||
]);
|
||||
|
||||
$form->handleRequest($request);
|
||||
@@ -252,6 +254,12 @@ final class PersonController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
if ($form->get('createHousehold')->isClicked()) {
|
||||
return $this->redirectToRoute('chill_person_household_members_editor', [
|
||||
'persons' => [$person->getId()],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute(
|
||||
'chill_person_general_edit',
|
||||
['person_id' => $person->getId()]
|
||||
|
@@ -1153,11 +1153,8 @@ class AccompanyingPeriod implements
|
||||
$this->removeComment($this->pinnedComment);
|
||||
}
|
||||
|
||||
if ($comment instanceof Comment) {
|
||||
if (null !== $this->pinnedComment) {
|
||||
$this->addComment($this->pinnedComment);
|
||||
}
|
||||
$this->addComment($comment);
|
||||
if (null !== $this->pinnedComment) {
|
||||
$this->addComment($this->pinnedComment);
|
||||
}
|
||||
|
||||
$this->pinnedComment = $comment;
|
||||
|
@@ -44,8 +44,8 @@ class AccompanyingPeriodWork implements AccompanyingPeriodLinkedWithSocialIssues
|
||||
{
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
|
||||
* @Serializer\Groups({"read","read:accompanyingPeriodWork:light"})
|
||||
* @Serializer\Context(normalizationContext={"groups"={"read"}}, groups={"read:accompanyingPeriodWork:light"})
|
||||
* @Serializer\Groups({"read", "read:accompanyingPeriodWork:light"})
|
||||
* @Serializer\Context(normalizationContext={"groups": {"read"}}, groups={"read:accompanyingPeriodWork:light"})
|
||||
*/
|
||||
private ?AccompanyingPeriod $accompanyingPeriod = null;
|
||||
|
||||
|
@@ -13,7 +13,10 @@ namespace Chill\PersonBundle\Menu;
|
||||
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Workflow\Registry;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
@@ -24,15 +27,18 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
protected Registry $registry;
|
||||
|
||||
protected Security $security;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, Registry $registry)
|
||||
public function __construct(TranslatorInterface $translator, Registry $registry, Security $security)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->registry = $registry;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters): void
|
||||
@@ -47,38 +53,44 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
||||
], ])
|
||||
->setExtras(['order' => 10]);
|
||||
|
||||
$menu->addChild($this->translator->trans('Edit Accompanying Course'), [
|
||||
'route' => 'chill_person_accompanying_course_edit',
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 20]);
|
||||
if ($this->security->isGranted(AccompanyingPeriodVoter::EDIT, $period)) {
|
||||
$menu->addChild($this->translator->trans('Edit Accompanying Course'), [
|
||||
'route' => 'chill_person_accompanying_course_edit',
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 20]);
|
||||
}
|
||||
|
||||
if (AccompanyingPeriod::STEP_DRAFT === $period->getStep()) {
|
||||
// no more menu items if the period is draft
|
||||
return;
|
||||
}
|
||||
|
||||
$menu->addChild($this->translator->trans('Accompanying Course History'), [
|
||||
'route' => 'chill_person_accompanying_course_history',
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 30]);
|
||||
if ($this->security->isGranted(AccompanyingPeriodVoter::SEE_DETAILS, $period)) {
|
||||
$menu->addChild($this->translator->trans('Accompanying Course History'), [
|
||||
'route' => 'chill_person_accompanying_course_history',
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 30]);
|
||||
|
||||
$menu->addChild($this->translator->trans('Accompanying Course Action'), [
|
||||
'route' => 'chill_person_accompanying_period_work_list',
|
||||
'routeParameters' => [
|
||||
'id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 40]);
|
||||
$menu->addChild($this->translator->trans('Accompanying Course Comment'), [
|
||||
'route' => 'chill_person_accompanying_period_comment_list',
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 50]);
|
||||
}
|
||||
|
||||
$menu->addChild($this->translator->trans('Accompanying Course Comment'), [
|
||||
'route' => 'chill_person_accompanying_period_comment_list',
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 50]);
|
||||
if ($this->security->isGranted(AccompanyingPeriodWorkVoter::SEE, $period)) {
|
||||
$menu->addChild($this->translator->trans('Accompanying Course Action'), [
|
||||
'route' => 'chill_person_accompanying_period_work_list',
|
||||
'routeParameters' => [
|
||||
'id' => $period->getId(),
|
||||
], ])
|
||||
->setExtras(['order' => 40]);
|
||||
}
|
||||
|
||||
$workflow = $this->registry->get($period, 'accompanying_period_lifecycle');
|
||||
|
||||
|
@@ -16,17 +16,22 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->repository = $entityManager->getRepository(AccompanyingPeriodWork::class);
|
||||
}
|
||||
|
||||
@@ -78,6 +83,36 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
||||
return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of accompanying period with a defined order:.
|
||||
*
|
||||
* * first, opened works
|
||||
* * then, closed works
|
||||
*
|
||||
* @return AccompanyingPeriodWork[]
|
||||
*/
|
||||
public function findByAccompanyingPeriodOpenFirst(AccompanyingPeriod $period, int $limit = 10, int $offset = 0): array
|
||||
{
|
||||
$rsm = new ResultSetMappingBuilder($this->em);
|
||||
$rsm->addRootEntityFromClassMetadata(AccompanyingPeriodWork::class, 'w');
|
||||
|
||||
$sql = "SELECT {$rsm} FROM chill_person_accompanying_period_work w
|
||||
WHERE accompanyingPeriod_id = :periodId
|
||||
ORDER BY
|
||||
CASE WHEN enddate IS NULL THEN '-infinity'::timestamp ELSE 'infinity'::timestamp END ASC,
|
||||
startdate DESC,
|
||||
enddate DESC,
|
||||
id DESC
|
||||
LIMIT :limit OFFSET :offset";
|
||||
|
||||
$nq = $this->em->createNativeQuery($sql, $rsm)
|
||||
->setParameter('periodId', $period->getId(), Types::INTEGER)
|
||||
->setParameter('limit', $limit, Types::INTEGER)
|
||||
->setParameter('offset', $offset, Types::INTEGER);
|
||||
|
||||
return $nq->getResult();
|
||||
}
|
||||
|
||||
public function findNearEndDateByUser(User $user, DateTimeImmutable $since, DateTimeImmutable $until, int $limit = 20, int $offset = 0): array
|
||||
{
|
||||
return $this->buildQueryNearEndDateByUser($user, $since, $until)
|
||||
|
@@ -14,7 +14,7 @@ namespace Chill\PersonBundle\Repository\Household;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Security\Authorization\HouseholdVoter;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
@@ -39,7 +39,7 @@ final class HouseholdACLAwareRepository implements HouseholdACLAwareRepositoryIn
|
||||
{
|
||||
$centers = $this->authorizationHelper->getReachableCenters(
|
||||
$this->security->getUser(),
|
||||
HouseholdVoter::SEE
|
||||
PersonVoter::SEE // the authorization to see a household is the same as seeing a person
|
||||
);
|
||||
|
||||
if ([] === $centers) {
|
||||
|
@@ -60,14 +60,14 @@
|
||||
<template v-slot:body>
|
||||
<p>{{ $t('confirm.sure_description') }}</p>
|
||||
<div v-if="accompanyingCourse.user === null">
|
||||
<div v-if="filteredReferrersSuggested.length === 0">
|
||||
<div v-if="usersSuggestedFilteredByJob.length === 0">
|
||||
<p class="alert alert-warning">{{ $t('confirm.no_suggested_referrer') }}</p>
|
||||
</div>
|
||||
<div v-if="filteredReferrersSuggested.length === 1" class="alert alert-info">
|
||||
<div v-if="usersSuggestedFilteredByJob.length === 1" class="alert alert-info">
|
||||
<p>{{ $t('confirm.one_suggested_referrer') }}:</p>
|
||||
<ul class="list-suggest add-items inline">
|
||||
<li>
|
||||
<user-render-box-badge :user="filteredReferrersSuggested[0]"></user-render-box-badge>
|
||||
<user-render-box-badge :user="usersSuggestedFilteredByJob[0]"></user-render-box-badge>
|
||||
</li>
|
||||
</ul>
|
||||
<p>{{ $t('confirm.choose_suggested_referrer') }}</p>
|
||||
@@ -150,7 +150,6 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
accompanyingCourse: state => state.accompanyingCourse,
|
||||
filteredReferrersSuggested: state => state.filteredReferrersSuggested
|
||||
}),
|
||||
...mapGetters([
|
||||
'isParticipationValid',
|
||||
@@ -160,15 +159,16 @@ export default {
|
||||
'isLocationValid',
|
||||
'isJobValid',
|
||||
'validationKeys',
|
||||
'isValidToBeConfirmed'
|
||||
'isValidToBeConfirmed',
|
||||
'usersSuggestedFilteredByJob',
|
||||
]),
|
||||
deleteLink() {
|
||||
return `/fr/parcours/${this.accompanyingCourse.id}/delete`; //TODO locale
|
||||
},
|
||||
disableConfirm() {
|
||||
return this.clickedDoNotChooseReferrer
|
||||
? (this.accompanyingCourse.user === null && this.filteredReferrersSuggested.length === 0)
|
||||
: (this.accompanyingCourse.user === null && this.filteredReferrersSuggested.length === 0) || (this.filteredReferrersSuggested.length === 1);
|
||||
return (this.accompanyingCourse.user === null
|
||||
&& this.usersSuggestedFilteredByJob.length === 1
|
||||
&& this.clickedDoNotChooseReferrer === false);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -183,7 +183,7 @@ export default {
|
||||
});
|
||||
},
|
||||
chooseSuggestedReferrer() {
|
||||
this.$store.dispatch('updateReferrer', this.filteredReferrersSuggested[0])
|
||||
this.$store.dispatch('updateReferrer', this.usersSuggestedFilteredByJob[0])
|
||||
.catch(({name, violations}) => {
|
||||
if (name === 'ValidationException' || name === 'AccessException') {
|
||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||
|
@@ -10,6 +10,7 @@
|
||||
addAge : true,
|
||||
hLevel : 3,
|
||||
isConfidential : false,
|
||||
isMultiline: true,
|
||||
}"
|
||||
:person="participation.person"
|
||||
:returnPath="getAccompanyingCourseReturnPath">
|
||||
@@ -28,7 +29,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" :canCloseModal="canCloseOnTheFlyModal"></on-the-fly></li>
|
||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
|
||||
<li>
|
||||
<button v-if="!participation.endDate"
|
||||
class="btn btn-sm btn-remove"
|
||||
@@ -90,7 +91,6 @@ export default {
|
||||
hLevel: 1
|
||||
}
|
||||
},
|
||||
canCloseOnTheFlyModal: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -120,12 +120,14 @@ export default {
|
||||
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||
body.phonenumber = payload.data.phonenumber;
|
||||
body.mobilenumber = payload.data.mobilenumber;
|
||||
body.email = payload.data.email;
|
||||
body.altNames = payload.data.altNames;
|
||||
body.gender = payload.data.gender;
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/person/person/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('addPerson', { target: payload.target, body: response })
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$store.dispatch('addPerson', { target: payload.target, body: response });
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
@@ -143,10 +145,10 @@ export default {
|
||||
body.telephone = payload.data.phonenumber;
|
||||
body.address = { id: payload.data.address.address_id };
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/third-party/third-party/${payload.data.id}.json`, body)
|
||||
makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('addThirdparty', { target: payload.target, body: response })
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
|
@@ -1,164 +1,178 @@
|
||||
<template>
|
||||
<div class="vue-component">
|
||||
<h2><a id="section-80"></a>{{ $t('referrer.title') }}</h2>
|
||||
<div class="vue-component">
|
||||
<h2><a id="section-80"></a>{{ $t('referrer.title') }}</h2>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
|
||||
<label class="col-form-label" for="selectJob">
|
||||
{{ $t('job.label') }}
|
||||
{{ $t('job.label') }}
|
||||
</label>
|
||||
|
||||
<VueMultiselect
|
||||
name="selectJob"
|
||||
label="text"
|
||||
:custom-label="customJobLabel"
|
||||
track-by="id"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('job.placeholder')"
|
||||
v-model="valueJob"
|
||||
:options="jobs"
|
||||
:select-label="$t('multiselect.select_label')"
|
||||
:deselect-label="$t('multiselect.deselect_label')"
|
||||
:selected-label="$t('multiselect.selected_label')"
|
||||
@select="updateJob">
|
||||
</VueMultiselect>
|
||||
name="selectJob"
|
||||
label="text"
|
||||
:custom-label="customJobLabel"
|
||||
track-by="id"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('job.placeholder')"
|
||||
v-model="valueJob"
|
||||
:options="jobs"
|
||||
:select-label="$t('multiselect.select_label')"
|
||||
:deselect-label="$t('multiselect.deselect_label')"
|
||||
:selected-label="$t('multiselect.selected_label')"
|
||||
></VueMultiselect>
|
||||
|
||||
<label class="col-form-label" for="selectReferrer">
|
||||
{{ $t('referrer.label') }}
|
||||
{{ $t('referrer.label') }}
|
||||
</label>
|
||||
|
||||
<VueMultiselect
|
||||
name="selectReferrer"
|
||||
label="text"
|
||||
track-by="id"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('referrer.placeholder')"
|
||||
v-model="value"
|
||||
:options="users"
|
||||
:select-label="$t('multiselect.select_label')"
|
||||
:deselect-label="$t('multiselect.deselect_label')"
|
||||
:selected-label="$t('multiselect.selected_label')"
|
||||
@select="updateReferrer">
|
||||
</VueMultiselect>
|
||||
name="selectReferrer"
|
||||
label="text"
|
||||
track-by="id"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('referrer.placeholder')"
|
||||
v-model="value"
|
||||
:options="users"
|
||||
:select-label="$t('multiselect.select_label')"
|
||||
:deselect-label="$t('multiselect.deselect_label')"
|
||||
:selected-label="$t('multiselect.selected_label')"
|
||||
></VueMultiselect>
|
||||
|
||||
<template v-if="filteredReferrersSuggested.length > 0">
|
||||
<ul class="list-suggest add-items inline">
|
||||
<li v-for="(u, i) in filteredReferrersSuggested" @click="updateReferrer(u)" :key="`referrer-${i}`">
|
||||
<template v-if="usersSuggestedFilteredByJob.length > 0">
|
||||
<ul class="list-suggest add-items inline">
|
||||
<li v-for="(u, i) in usersSuggestedFilteredByJob" @click="updateReferrer(u)" :key="`referrer-${i}`">
|
||||
<span>
|
||||
<user-render-box-badge :user="u"></user-render-box-badge>
|
||||
</span>
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button
|
||||
class="btn btn-create"
|
||||
type="button"
|
||||
name="button"
|
||||
@click="assignMe">
|
||||
{{ $t('referrer.assign_me') }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="btn btn-create"
|
||||
type="button"
|
||||
name="button"
|
||||
@click="assignMe">
|
||||
{{ $t('referrer.assign_me') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!isJobValid" class="alert alert-warning to-confirm">
|
||||
<div v-if="!isJobValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('job.not_valid') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods';
|
||||
import {mapState, mapGetters} from 'vuex';
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
|
||||
|
||||
export default {
|
||||
name: "Referrer",
|
||||
components: {
|
||||
UserRenderBoxBadge,
|
||||
VueMultiselect,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
jobs: []
|
||||
name: "Referrer",
|
||||
components: {
|
||||
UserRenderBoxBadge,
|
||||
VueMultiselect,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
jobs: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
valueJob: state => state.accompanyingCourse.job,
|
||||
}),
|
||||
...mapGetters(['isJobValid', 'usersSuggestedFilteredByJob']),
|
||||
users: function () {
|
||||
let users = this.$store.getters.usersFilteredByJob;
|
||||
|
||||
console.log('users filtered by job', users);
|
||||
|
||||
// ensure that the selected user is in the list. add it if necessary
|
||||
if (this.$store.state.accompanyingCourse.user !== null && users.find(u => this.$store.state.accompanyingCourse.user.id === u.id) === undefined) {
|
||||
console.log('add user to users');
|
||||
users.push(this.$store.state.accompanyingCourse.user);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
value: state => state.accompanyingCourse.user,
|
||||
valueJob: state => state.accompanyingCourse.job,
|
||||
users: state => state.users.filter(u => {
|
||||
if (u.user_job && state.accompanyingCourse.job) {
|
||||
return u.user_job.id === state.accompanyingCourse.job.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
filteredReferrersSuggested: state => state.filteredReferrersSuggested,
|
||||
}),
|
||||
...mapGetters([
|
||||
'isJobValid'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
this.getJobs();
|
||||
},
|
||||
methods: {
|
||||
updateReferrer(value) {
|
||||
this.$store.dispatch('updateReferrer', value)
|
||||
|
||||
console.log('users to return', users);
|
||||
return users;
|
||||
},
|
||||
valueJob: {
|
||||
get() {
|
||||
return this.$store.state.accompanyingCourse.job;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.dispatch('updateJob', value)
|
||||
.catch(({name, violations}) => {
|
||||
if (name === 'ValidationException' || name === 'AccessException') {
|
||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||
} else {
|
||||
this.$toast.open({message: 'An error occurred'})
|
||||
}
|
||||
if (name === 'ValidationException' || name === 'AccessException') {
|
||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||
} else {
|
||||
this.$toast.open({message: 'An error occurred'})
|
||||
}
|
||||
});
|
||||
},
|
||||
getJobs() {
|
||||
const url = '/api/1.0/main/user-job.json';
|
||||
makeFetch('GET', url)
|
||||
.then(response => {
|
||||
this.jobs = response.results;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.open({message: error.txt})
|
||||
})
|
||||
},
|
||||
updateJob(value) {
|
||||
this.$store.dispatch('updateJob', value)
|
||||
.catch(({name, violations}) => {
|
||||
if (name === 'ValidationException' || name === 'AccessException') {
|
||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||
} else {
|
||||
this.$toast.open({message: 'An error occurred'})
|
||||
}
|
||||
});
|
||||
},
|
||||
customJobLabel(value) {
|
||||
return value.label.fr;
|
||||
},
|
||||
assignMe() {
|
||||
const url = `/api/1.0/main/whoami.json`;
|
||||
makeFetch('GET', url)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateReferrer', response);
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
commit('catchError', error);
|
||||
this.$toast.open({message: error.body})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
value: {
|
||||
get() {
|
||||
return this.$store.state.accompanyingCourse.user;
|
||||
},
|
||||
set(value) {
|
||||
console.log('set referrer', value);
|
||||
this.$store.dispatch('updateReferrer', value)
|
||||
.catch(({name, violations}) => {
|
||||
if (name === 'ValidationException' || name === 'AccessException') {
|
||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||
} else {
|
||||
this.$toast.open({message: 'An error occurred'})
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getJobs();
|
||||
},
|
||||
methods: {
|
||||
updateReferrer(value) {
|
||||
this.value = value;
|
||||
},
|
||||
getJobs() {
|
||||
const url = '/api/1.0/main/user-job.json';
|
||||
makeFetch('GET', url)
|
||||
.then(response => {
|
||||
this.jobs = response.results;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.open({message: error.txt})
|
||||
})
|
||||
},
|
||||
customJobLabel(value) {
|
||||
return value.label.fr;
|
||||
},
|
||||
assignMe() {
|
||||
const url = `/api/1.0/main/whoami.json`;
|
||||
makeFetch('GET', url)
|
||||
.then(user => {
|
||||
this.value = user
|
||||
})
|
||||
/*.catch((error) => {
|
||||
commit('catchError', error);
|
||||
this.$toast.open({message: error.body})
|
||||
})*/
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</third-party-render-box>
|
||||
@@ -52,7 +52,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</person-render-box>
|
||||
@@ -92,7 +92,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</third-party-render-box>
|
||||
@@ -114,7 +114,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" :canCloseModal="canCloseOnTheFlyModal"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</person-render-box>
|
||||
@@ -189,7 +189,6 @@ export default {
|
||||
uniq: true,
|
||||
}
|
||||
},
|
||||
canCloseOnTheFlyModal: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -261,12 +260,14 @@ export default {
|
||||
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||
body.phonenumber = payload.data.phonenumber;
|
||||
body.mobilenumber = payload.data.mobilenumber;
|
||||
body.email = payload.data.email;
|
||||
body.altNames = payload.data.altNames;
|
||||
body.gender = payload.data.gender;
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/person/person/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('addPerson', { target: payload.target, body: response })
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
@@ -284,10 +285,10 @@ export default {
|
||||
body.telephone = payload.data.phonenumber;
|
||||
body.address = { id: payload.data.address.address_id };
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/third-party/third-party/${payload.data.id}.json`, body)
|
||||
makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('addThirdparty', { target: payload.target, body: response })
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
|
@@ -35,7 +35,7 @@
|
||||
:id="resource.resource.id"
|
||||
action="edit"
|
||||
@saveFormOnTheFly="saveFormOnTheFly"
|
||||
:canCloseModal="canCloseOnTheFlyModal">
|
||||
ref="onTheFly">
|
||||
</on-the-fly>
|
||||
</li>
|
||||
<li>
|
||||
@@ -82,7 +82,7 @@
|
||||
:id="resource.resource.id"
|
||||
action="edit"
|
||||
@saveFormOnTheFly="saveFormOnTheFly"
|
||||
:canCloseModal="canCloseOnTheFlyModal">
|
||||
ref="onTheFly">
|
||||
</on-the-fly>
|
||||
</li>
|
||||
<li>
|
||||
@@ -116,11 +116,6 @@ export default {
|
||||
},
|
||||
props: ['resource'],
|
||||
emits: ['remove'],
|
||||
data() {
|
||||
return {
|
||||
canCloseOnTheFlyModal: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
parent() {
|
||||
return {
|
||||
@@ -152,12 +147,14 @@ export default {
|
||||
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||
body.phonenumber = payload.data.phonenumber;
|
||||
body.mobilenumber = payload.data.mobilenumber;
|
||||
body.email = payload.data.email;
|
||||
body.altNames = payload.data.altNames;
|
||||
body.gender = payload.data.gender;
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/person/person/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('addPerson', { target: payload.target, body: response })
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
@@ -175,10 +172,10 @@ export default {
|
||||
body.telephone = payload.data.phonenumber;
|
||||
body.address = { id: payload.data.address.address_id };
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/third-party/third-party/${payload.data.id}.json`, body)
|
||||
makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('addThirdparty', { target: payload.target, body: response })
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
|
@@ -140,7 +140,7 @@ const appMessages = {
|
||||
sure_description: "Une fois le changement confirmé, il ne sera plus possible de le remettre à l'état de brouillon !",
|
||||
ok: "Confirmer le parcours",
|
||||
delete: "Supprimer le parcours",
|
||||
no_suggested_referrer: "Il n'y a aucun référent qui puisse être désigné pour ce parcours. Vérifiez la localisation du parcours, les métiers et service indiqués. Si le problème persiste, contactez l'administrateur du logiciel.",
|
||||
no_suggested_referrer: "Il n'y a aucun référent qui puisse être suggéré pour ce parcours. Vérifiez la localisation du parcours, les métiers et service indiqués. Si les données sont correctes, vous pouvez confirmer ce parcours.",
|
||||
one_suggested_referrer: "Un unique référent peut être suggéré pour ce parcours",
|
||||
choose_suggested_referrer: "Voulez-vous le désigner directement ?",
|
||||
choose_button: "Désigner",
|
||||
|
@@ -40,7 +40,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
|
||||
scopesAtBackend: accompanyingCourse.scopes.map(scope => scope),
|
||||
// the users which are available for referrer
|
||||
referrersSuggested: [],
|
||||
filteredReferrersSuggested: [],
|
||||
// all the users available
|
||||
users: [],
|
||||
permissions: {}
|
||||
@@ -93,6 +92,30 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
|
||||
|
||||
return false;
|
||||
},
|
||||
usersFilteredByJob(state) {
|
||||
return state.users.filter(u => {
|
||||
if (null !== state.accompanyingCourse.job) {
|
||||
return (u.user_job === null ? null : u.user_job.id) === state.accompanyingCourse.job.id;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
},
|
||||
usersSuggestedFilteredByJob(state) {
|
||||
return state.referrersSuggested.filter(u => {
|
||||
if (null !== state.accompanyingCourse.job) {
|
||||
return (u.user_job === null ? null : u.user_job.id) === state.accompanyingCourse.job.id;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}).filter(u => {
|
||||
if (null !== state.accompanyingCourse.user) {
|
||||
return u.id !== state.accompanyingCourse.user.id;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
catchError(state, error) {
|
||||
@@ -216,22 +239,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
|
||||
return u;
|
||||
});
|
||||
},
|
||||
setFilteredReferrersSuggested(state) {
|
||||
state.filteredReferrersSuggested = state.referrersSuggested.filter(u => {
|
||||
if (u.user_job && state.accompanyingCourse.job && state.accompanyingCourse.user) {
|
||||
return u.user_job.id === state.accompanyingCourse.job.id && state.accompanyingCourse.user.id !== u.id
|
||||
} else {
|
||||
if (null === state.accompanyingCourse.user) {
|
||||
if (u.user_job && state.accompanyingCourse.job) {
|
||||
return u.user_job.id === state.accompanyingCourse.job.id
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return state.accompanyingCourse.user.id !== u.id;
|
||||
}
|
||||
})
|
||||
},
|
||||
confirmAccompanyingCourse(state, response) {
|
||||
//console.log('### mutation: confirmAccompanyingCourse: response', response);
|
||||
state.accompanyingCourse.step = response.step;
|
||||
@@ -689,8 +696,14 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
|
||||
})
|
||||
},
|
||||
updateReferrer({ commit }, payload) {
|
||||
console.log('update referrer', payload);
|
||||
console.log('payload !== null', payload !== null);
|
||||
const url = `/api/1.0/person/accompanying-course/${id}.json`;
|
||||
const body = { type: "accompanying_period", user: { id: payload.id, type: payload.type }};
|
||||
let body = { type: "accompanying_period", user: null };
|
||||
|
||||
if (payload !== null) {
|
||||
body = { type: "accompanying_period", user: { id: payload.id, type: payload.type } };
|
||||
}
|
||||
|
||||
return makeFetch('PATCH', url, body)
|
||||
.then((response) => {
|
||||
@@ -704,12 +717,15 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
|
||||
},
|
||||
updateJob({ commit }, payload) {
|
||||
const url = `/api/1.0/person/accompanying-course/${id}.json`;
|
||||
const body = { type: "accompanying_period", job: { id: payload.id, type: payload.type }};
|
||||
let body = { type: "accompanying_period", job: null };
|
||||
|
||||
if (payload !== null) {
|
||||
body = { type: "accompanying_period", job: { id: payload.id, type: payload.type } };
|
||||
}
|
||||
|
||||
return makeFetch('PATCH', url, body)
|
||||
.then((response) => {
|
||||
commit('updateJob', response.job);
|
||||
commit('setFilteredReferrersSuggested');
|
||||
})
|
||||
.catch((error) => {
|
||||
commit('catchError', error);
|
||||
@@ -734,7 +750,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
|
||||
async fetchReferrersSuggested({ state, commit}) {
|
||||
let users = await getReferrersSuggested(state.accompanyingCourse);
|
||||
commit('setReferrersSuggested', users);
|
||||
commit('setFilteredReferrersSuggested');
|
||||
if (
|
||||
null === state.accompanyingCourse.user
|
||||
&& !state.accompanyingCourse.confidential
|
||||
|
@@ -211,7 +211,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="thirdparty.type" :id="thirdparty.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="thirdparty.type" :id="thirdparty.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><on-the-fly :type="thirdparty.type" :id="thirdparty.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
|
||||
<li>
|
||||
<button :title="$t('remove_thirdparty')" class="btn btn-sm btn-remove" @click="removeThirdParty(thirdparty)" />
|
||||
</li>
|
||||
@@ -286,6 +286,8 @@ import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/
|
||||
import PickWorkflow from 'ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue';
|
||||
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api.js';
|
||||
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||
|
||||
|
||||
const i18n = {
|
||||
messages: {
|
||||
@@ -476,15 +478,27 @@ export default {
|
||||
},
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'resource';
|
||||
this.$store.dispatch('patchOnTheFly', payload)
|
||||
.catch(({name, violations}) => {
|
||||
if (name === 'ValidationException' || name === 'AccessException') {
|
||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||
|
||||
let body = { type: payload.type };
|
||||
body.name = payload.data.text;
|
||||
body.email = payload.data.email;
|
||||
body.telephone = payload.data.phonenumber;
|
||||
body.address = { id: payload.data.address.address_id };
|
||||
|
||||
makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateThirdParty', response)
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({message: 'An error occurred'})
|
||||
this.$toast.open({message: 'An error occurred'});
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import { createApp } from 'vue';
|
||||
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
|
||||
import { store } from './store';
|
||||
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
|
||||
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n';
|
||||
import VueToast from 'vue-toast-notification';
|
||||
import 'vue-toast-notification/dist/theme-sugar.css';
|
||||
import App from './App.vue';
|
||||
|
||||
const i18n = _createI18n(personMessages);
|
||||
@@ -10,6 +12,12 @@ const app = createApp({
|
||||
template: `<app></app>`,
|
||||
})
|
||||
.use(store)
|
||||
.use(VueToast, {
|
||||
position: "bottom-right",
|
||||
type: "error",
|
||||
duration: 5000,
|
||||
dismissible: true
|
||||
})
|
||||
.use(i18n)
|
||||
.component('app', App)
|
||||
.mount('#accompanying_course_work_edit');
|
||||
|
@@ -266,6 +266,14 @@ const store = createStore({
|
||||
state.thirdParties.push(unexistings[i]);
|
||||
}
|
||||
},
|
||||
updateThirdParty(state, thirdParty) {
|
||||
for (let t of state.thirdParties) {
|
||||
if (t.id === thirdParty.id){
|
||||
state.thirdParties = state.thirdParties.filter(t => t.id !== thirdParty.id);
|
||||
state.thirdParties.push(thirdParty);
|
||||
}
|
||||
}
|
||||
},
|
||||
removeThirdParty(state, thirdParty) {
|
||||
state.thirdParties = state.thirdParties
|
||||
.filter(t => t.id !== thirdParty.id);
|
||||
@@ -278,6 +286,10 @@ const store = createStore({
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
updateThirdParty({ commit }, payload) {
|
||||
console.log(payload);
|
||||
commit('updateThirdParty', payload);
|
||||
},
|
||||
getReachablesGoalsForAction({ getters, commit, dispatch }) {
|
||||
let
|
||||
socialActionId = getters.socialAction.id,
|
||||
|
@@ -69,7 +69,7 @@
|
||||
:buttonText="$t('onthefly.create.button', {q: query})"
|
||||
action="create"
|
||||
@saveFormOnTheFly="saveFormOnTheFly"
|
||||
:canCloseModal="canCloseOnTheFlyModal">
|
||||
ref="onTheFly">
|
||||
</on-the-fly>
|
||||
</div>
|
||||
|
||||
@@ -121,7 +121,6 @@ export default {
|
||||
selected: [],
|
||||
priorSuggestion: {}
|
||||
},
|
||||
canCloseOnTheFlyModal: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -271,7 +270,7 @@ export default {
|
||||
makeFetch('POST', '/api/1.0/person/person.json', data)
|
||||
.then(response => {
|
||||
this.newPriorSuggestion(response);
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
@@ -287,7 +286,7 @@ export default {
|
||||
makeFetch('POST', '/api/1.0/thirdparty/thirdparty.json', data)
|
||||
.then(response => {
|
||||
this.newPriorSuggestion(response);
|
||||
this.canCloseOnTheFlyModal = true;
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === 'ValidationException') {
|
||||
@@ -299,7 +298,6 @@ export default {
|
||||
}
|
||||
})
|
||||
}
|
||||
this.canCloseOnTheFlyModal = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@@ -43,10 +43,11 @@
|
||||
<label for="firstname">{{ $t('person.firstname') }}</label>
|
||||
</div>
|
||||
|
||||
<div v-for="(a) in config.altNames" :key="a.key" class="form-floating mb-3">
|
||||
<div v-for="(a, i) in config.altNames" :key="a.key" class="form-floating mb-3">
|
||||
<input
|
||||
class="form-control form-control-lg"
|
||||
:id="a.key"
|
||||
:value="personAltNamesLabels[i]"
|
||||
@input="onAltNameInput"
|
||||
/>
|
||||
<label :for="a.key">{{ a.labels.fr }}</label>
|
||||
@@ -199,6 +200,9 @@ export default {
|
||||
},
|
||||
feminized() {
|
||||
return (this.person.gender === 'woman')? 'e' : '';
|
||||
},
|
||||
personAltNamesLabels() {
|
||||
return this.person.altNames.map(a => a ? a.label : '');
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@@ -23,6 +23,8 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_new', { 'id': accompanyingCourse.id }) }}"
|
||||
|
@@ -41,7 +41,7 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="wh-col">
|
||||
<div class="wh-col" style="align-items: center;">
|
||||
{% if chill_accompanying_periods.fields.user == 'visible' %}
|
||||
{# the tags `data-referrer-text` is used by module `@ChillPerson/mod/AccompanyingPeriod/setReferrer.js` #}
|
||||
{% if period.user %}
|
||||
|
@@ -115,6 +115,9 @@
|
||||
<li>
|
||||
{{ form_widget(form.editPerson, { 'attr': { 'class': 'dropdown-item' }}) }}
|
||||
</li>
|
||||
<li>
|
||||
{{ form_widget(form.createHousehold, { 'attr': { 'class': 'dropdown-item' }}) }}
|
||||
</li>
|
||||
<li>
|
||||
{{ form_widget(form.createPeriod, { 'attr': { 'class': 'dropdown-item' }}) }}
|
||||
</li>
|
||||
|
@@ -32,14 +32,28 @@
|
||||
</div>
|
||||
<div class="item-row separator">
|
||||
<div class="wrap-list">
|
||||
{% if p.household is same as p.person.getCurrentHousehold %}
|
||||
<div class="wl-row">
|
||||
<div class="wl-col title">
|
||||
<h3>{{ 'Address'|trans }}</h3>
|
||||
</div>
|
||||
<div class="wl-col list">
|
||||
<p class="item">{{ p.household.getCurrentAddress|chill_entity_render_box }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="wl-row">
|
||||
<div class="wl-col title">
|
||||
<h3>En tant que</h3>
|
||||
<h3>{{ 'household.As member'|trans }}</h3>
|
||||
</div>
|
||||
<div class="wl-col list">
|
||||
<p class="item">{{ p.position.label|localize_translatable_string }}
|
||||
<p class="item">
|
||||
{{ p.position.label|localize_translatable_string }}
|
||||
{% if p.holder %}
|
||||
<span class="holder">{{ 'household.holder'|trans }}</span>
|
||||
<span class="fa-stack fa-holder" title="{{ 'houshold.holder'|trans|e('html_attr') }}">
|
||||
<i class="fa fa-circle fa-stack-1x text-success"></i>
|
||||
<i class="fa fa-stack-1x">T</i>
|
||||
</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
@@ -29,10 +29,10 @@
|
||||
|
||||
<div class="item-col" style="width: 33%;">
|
||||
<ul class="list-unstyled h3">
|
||||
{% if a.endDate is not null %}
|
||||
<li><span class="item-key">{{'Since'|trans}} : </span>{{ a.startDate|format_date('long') }}</li>
|
||||
{% if a.endDate is not null %}
|
||||
<li><span class="item-key">{{'Until'|trans}} : </span><b>{{ a.endDate|format_date('long') }}</b></li>
|
||||
{% endif %}
|
||||
<li><span class="item-key">{{'Until'|trans}} : </span><b>{{ a.endDate|format_date('long') }}</b></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="item-col flex-column justify-content-start">
|
||||
|
@@ -11,17 +11,23 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\PersonBundle\Security\Authorization;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use UnexpectedValueException;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
|
||||
class AccompanyingPeriodWorkVoter extends Voter
|
||||
{
|
||||
public const CREATE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_CREATE';
|
||||
|
||||
public const SEE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE';
|
||||
|
||||
public const UPDATE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE';
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(Security $security)
|
||||
@@ -31,8 +37,14 @@ class AccompanyingPeriodWorkVoter extends Voter
|
||||
|
||||
protected function supports($attribute, $subject): bool
|
||||
{
|
||||
return $subject instanceof AccompanyingPeriodWork
|
||||
&& in_array($attribute, $this->getRoles(), true);
|
||||
return
|
||||
(
|
||||
$subject instanceof AccompanyingPeriodWork
|
||||
&& in_array($attribute, $this->getRoles(), true)
|
||||
) || (
|
||||
$subject instanceof AccompanyingPeriod
|
||||
&& in_array($attribute, [self::SEE, self::CREATE], true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,13 +53,28 @@ class AccompanyingPeriodWorkVoter extends Voter
|
||||
*/
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
|
||||
{
|
||||
switch ($attribute) {
|
||||
case self::SEE:
|
||||
return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getAccompanyingPeriod());
|
||||
if ($subject instanceof AccompanyingPeriodWork) {
|
||||
switch ($attribute) {
|
||||
case self::SEE:
|
||||
return $this->security->isGranted(AccompanyingPeriodVoter::SEE_DETAILS, $subject->getAccompanyingPeriod());
|
||||
|
||||
default:
|
||||
throw new UnexpectedValueException("attribute {$attribute} is not supported");
|
||||
default:
|
||||
throw new UnexpectedValueException("attribute {$attribute} is not supported");
|
||||
}
|
||||
} elseif ($subject instanceof AccompanyingPeriod) {
|
||||
switch ($attribute) {
|
||||
case self::SEE:
|
||||
return $this->security->isGranted(AccompanyingPeriodVoter::SEE_DETAILS, $subject);
|
||||
|
||||
default:
|
||||
throw new UnexpectedValueException(sprintf(
|
||||
"attribute {$attribute} is not supported on instance %s",
|
||||
AccompanyingPeriod::class
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnexpectedValueException(sprintf("attribute {$attribute} on instance %s is not supported", get_class($subject)));
|
||||
}
|
||||
|
||||
private function getRoles(): array
|
||||
|
@@ -91,6 +91,7 @@ class PersonJsonNormalizer implements
|
||||
'deathdate',
|
||||
'center',
|
||||
'altNames',
|
||||
'email',
|
||||
];
|
||||
|
||||
$fields = array_filter(
|
||||
@@ -161,6 +162,11 @@ class PersonJsonNormalizer implements
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
$person->setEmail($data[$item]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -189,6 +195,7 @@ class PersonJsonNormalizer implements
|
||||
'centers' => $this->normalizer->normalize($this->centerResolverManager->resolveCenters($person), $format, $context),
|
||||
'phonenumber' => $person->getPhonenumber(),
|
||||
'mobilenumber' => $person->getMobilenumber(),
|
||||
'email' => $person->getEmail(),
|
||||
'altNames' => $this->normalizeAltNames($person->getAltNames()),
|
||||
'gender' => $person->getGender(),
|
||||
'current_household_address' => $this->normalizer->normalize($person->getCurrentHouseholdAddress(), $format, $context),
|
||||
|
@@ -21,6 +21,7 @@ use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use function array_map;
|
||||
@@ -58,10 +59,16 @@ final class HouseholdApiControllerTest extends WebTestCase
|
||||
$centerA = $em->getRepository(Center::class)->findOneBy(['name' => 'Center A']);
|
||||
$nbReference = $em->createQueryBuilder()->select('count(ar)')->from(AddressReference::class, 'ar')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
|
||||
if (0 === $nbReference) {
|
||||
throw new RuntimeException('any reference found. Add a reference in database to perform this test');
|
||||
}
|
||||
|
||||
$reference = $em->createQueryBuilder()->select('ar')->from(AddressReference::class, 'ar')
|
||||
->setFirstResult(random_int(0, $nbReference))
|
||||
->setMaxResults(1)
|
||||
->getQuery()->getSingleResult();
|
||||
|
||||
$p = new Person();
|
||||
$p->setFirstname('test')->setLastName('test lastname')
|
||||
->setGender(Person::BOTH_GENDER)
|
||||
@@ -79,6 +86,7 @@ final class HouseholdApiControllerTest extends WebTestCase
|
||||
[HouseholdMember::class, $m->getId()],
|
||||
[User::class, $p->getId()],
|
||||
[Household::class, $h->getId()],
|
||||
[Person::class, $p->getId()],
|
||||
];
|
||||
|
||||
yield [$reference->getId(), $h->getId()];
|
||||
|
@@ -129,20 +129,27 @@ final class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertNull($period->getPinnedComment());
|
||||
|
||||
$period->setPinnedComment($comment);
|
||||
|
||||
$this->assertSame($period->getPinnedComment(), $comment);
|
||||
$this->assertSame($period, $comment->getAccompanyingPeriod());
|
||||
$this->assertEquals(0, count($period->getComments()), 'The initial comment should not appears in the list of comments');
|
||||
$this->assertNull($comment->getAccompanyingPeriod());
|
||||
$this->assertEquals(0, count($period->getComments()));
|
||||
|
||||
$period->setPinnedComment($replacingComment);
|
||||
|
||||
$this->assertSame($period->getPinnedComment(), $replacingComment);
|
||||
$this->assertSame($period, $replacingComment->getAccompanyingPeriod());
|
||||
$this->assertEquals(0, count($period->getComments()), 'The initial comment should not appears in the list of comments');
|
||||
$this->assertNull($comment->getAccompanyingPeriod());
|
||||
$this->assertNull($replacingComment->getAccompanyingPeriod());
|
||||
$this->assertSame($period, $comment->getAccompanyingPeriod());
|
||||
$this->assertEquals(1, count($period->getComments()));
|
||||
$this->assertContains($comment, $period->getComments());
|
||||
|
||||
$period->setPinnedComment(null);
|
||||
|
||||
$this->assertNull($period->getPinnedComment());
|
||||
$this->assertNull($replacingComment->getAccompanyingPeriod());
|
||||
$this->assertEquals(0, count($period->getComments()), 'The initial comment should not appears in the list of comments');
|
||||
$this->assertSame($period, $comment->getAccompanyingPeriod());
|
||||
$this->assertSame($period, $replacingComment->getAccompanyingPeriod());
|
||||
$this->assertEquals(2, count($period->getComments()));
|
||||
$this->assertContains($comment, $period->getComments());
|
||||
$this->assertContains($replacingComment, $period->getComments());
|
||||
}
|
||||
|
||||
public function testRequestor()
|
||||
|
@@ -36,7 +36,7 @@ class HouseholdMembershipSequentialValidator extends ConstraintValidator
|
||||
public function validate($person, Constraint $constraint)
|
||||
{
|
||||
if (!$person instanceof Person) {
|
||||
throw new UnexpectedTypeException($constraint, Person::class);
|
||||
throw new UnexpectedTypeException($person, Person::class);
|
||||
}
|
||||
|
||||
$participations = $person->getHouseholdParticipationsShareHousehold();
|
||||
|
@@ -98,6 +98,7 @@ household:
|
||||
from: Depuis
|
||||
to: Jusqu'au
|
||||
person history: Ménages
|
||||
As member: En tant que
|
||||
|
||||
household_composition:
|
||||
Since: >-
|
||||
|
@@ -124,7 +124,7 @@ address_country_code: Code pays
|
||||
'Alreay existing person': 'Dossiers déjà encodés'
|
||||
'Add the person': 'Ajouter la personne'
|
||||
'Add the person and create an accompanying period': "Créer la personne & créer une période d'accompagnement"
|
||||
'Add the person and create an household': "Créer la personne & créer un ménage"
|
||||
'Add the person and create a household': "Créer la personne & créer un ménage"
|
||||
Show person: Voir le dossier de la personne
|
||||
'Confirm the creation': 'Confirmer la création'
|
||||
'You will create this person': 'Vous allez créer le dossier suivant'
|
||||
@@ -211,7 +211,7 @@ No requestor: Pas de demandeur
|
||||
No resources: "Pas d'interlocuteurs privilégiés"
|
||||
Persons associated: Usagers concernés
|
||||
Referrer: Référent
|
||||
Some peoples does not belong to any household currently. Add them to an household soon: Certaines personnes n'appartiennent à aucun ménage actuellement. Renseignez leur appartenance à un ménage dès que possible.
|
||||
Some peoples does not belong to any household currently. Add them to an household soon: Certaines personnes n'appartiennent à aucun ménage actuellement. Renseignez leur ménage dès que possible.
|
||||
Add to household now: Ajouter à un ménage
|
||||
Any resource for this accompanying course: Aucun interlocuteur privilégié pour ce parcours
|
||||
course.draft: Brouillon
|
||||
@@ -557,7 +557,7 @@ household_composition:
|
||||
numberOfChildren: Nombre d'enfants mineurs au sein du ménage
|
||||
Household composition: Composition du ménage
|
||||
Composition added: Information sur la composition familiale ajoutée
|
||||
Currently no composition: Aucune composition famiale renseignée.
|
||||
Currently no composition: Aucune composition familiale renseignée.
|
||||
Add a composition: Ajouter une composition familiale
|
||||
Update composition: Modifier la composition familiale
|
||||
|
||||
|
Reference in New Issue
Block a user