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

This commit is contained in:
Julien Fastré 2022-02-17 23:16:41 +01:00
commit 05f83bf566
31 changed files with 188 additions and 185 deletions

View File

@ -12,6 +12,16 @@ and this project adheres to
<!-- write down unreleased development here --> <!-- write down unreleased development here -->
* [thirdparty] Extend the thirdparty search to thirdparty children (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/448) * [thirdparty] Extend the thirdparty search to thirdparty children (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/448)
* [person]: AddPersons: allow creation of person or thirdparty only (no users) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/422)
* [person]: AddPersons: allow creation of person or thirdparty depending on allowed types (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/422)
* [person]: AddPersons: add suggestion of name when creating new person or thirdparty (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/422)
* [main] Address: fix small bug: when modifying an address without street (isNoAddress), also check errors if street is an empty string as back-end change null value to empty string for street (and streetNumber)
* [main] Address: stronger client-side validation of addresses (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/449)
* [person] accompanying course: filter suggested entities by open participations (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/415)
[activity] can click through the cross icon for removing person in concerned group (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/476)
[activity] correct associated persons by considering only open participations (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/476)
* [person_resources]: Renderboxes used to display person/thirdparty info (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/465)
## Test releases ## Test releases
### test release 2022-02-14 ### test release 2022-02-14

View File

@ -357,7 +357,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
if (null !== $this->accompanyingPeriod) { if (null !== $this->accompanyingPeriod) {
$personsAssociated = []; $personsAssociated = [];
foreach ($this->accompanyingPeriod->getParticipations() as $participation) { foreach ($this->accompanyingPeriod->getOpenParticipations() as $participation) {
if ($this->persons->contains($participation->getPerson())) { if ($this->persons->contains($participation->getPerson())) {
$personsAssociated[] = $participation->getPerson(); $personsAssociated[] = $participation->getPerson();
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<li> <li>
<span :title="person.text"> <span :title="person.text" @click.prevent="$emit('remove', person)">
<span class="chill_denomination" @click.prevent="$emit('remove', person)"> <span class="chill_denomination">
<person-text :person="person" :isCut="true"></person-text> <person-text :person="person" :isCut="true"></person-text>
</span> </span>
</span> </span>

View File

@ -139,12 +139,10 @@ class Address
private $point; private $point;
/** /**
* @var PostalCode
*
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode") * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
* @Groups({"write"}) * @Groups({"write"})
*/ */
private $postcode; private ?PostalCode $postcode;
/** /**
* @var string|null * @var string|null

View File

@ -260,8 +260,7 @@ export default {
editPane: false, editPane: false,
datePane: false, datePane: false,
loading: false, loading: false,
success: false, success: false
dirty: false
}, },
errors: [], errors: [],
defaultz: { defaultz: {
@ -537,17 +536,19 @@ export default {
checkErrors() { checkErrors() {
this.errors = []; this.errors = [];
if (this.flag.dirty) {
if (this.entity.selected.country === null) { if (this.entity.selected.country === null) {
this.errors.push("Un pays doit être sélectionné."); this.errors.push("Un pays doit être sélectionné.");
} }
if (this.entity.selected.city === null) {
this.errors.push("Une ville doit être sélectionnée.");
} else {
if (Object.keys(this.entity.selected.city).length === 0) { if (Object.keys(this.entity.selected.city).length === 0) {
this.errors.push("Une ville doit être sélectionnée."); this.errors.push("Une ville doit être sélectionnée.");
} }
if (!this.entity.selected.isNoAddress) {
if (this.entity.selected.address.street === null || this.entity.selected.address.streetNumber === null) {
this.errors.push("Une adresse doit être sélectionnée.");
} }
if (!this.entity.selected.isNoAddress) {
if (this.entity.selected.address.street === null || this.entity.selected.address.street === '' || this.entity.selected.address.streetNumber === null || this.entity.selected.address.streetNumber === '') {
this.errors.push("Une adresse doit être sélectionnée.");
} }
} }
}, },
@ -567,7 +568,7 @@ export default {
this.entity.selected.country = this.context.edit ? this.entity.address.country : {}; this.entity.selected.country = this.context.edit ? this.entity.address.country : {};
this.entity.selected.postcode = this.context.edit ? this.entity.address.postcode : {}; this.entity.selected.postcode = this.context.edit ? this.entity.address.postcode : {};
this.entity.selected.city = {}; this.entity.selected.city = this.context.edit ? this.entity.address.postcode : {};
this.entity.selected.address = {}; this.entity.selected.address = {};
this.entity.selected.address.street = this.context.edit ? this.entity.address.street: null; this.entity.selected.address.street = this.context.edit ? this.entity.address.street: null;
@ -583,6 +584,8 @@ export default {
this.entity.selected.writeNew.address = this.context.edit && this.entity.address.addressReference === null && this.entity.address.street.length > 0 this.entity.selected.writeNew.address = this.context.edit && this.entity.address.addressReference === null && this.entity.address.street.length > 0
this.entity.selected.writeNew.postcode = false // NB: this used to be this.context.edit, but think it was erroneous; this.entity.selected.writeNew.postcode = false // NB: this used to be this.context.edit, but think it was erroneous;
console.log('!! just set writeNew.postcode to', this.entity.selected.writeNew.postcode); console.log('!! just set writeNew.postcode to', this.entity.selected.writeNew.postcode);
this.checkErrors();
}, },
/* /*

View File

@ -111,11 +111,9 @@ export default {
this.entity.selected.address.streetNumber = value.streetNumber; this.entity.selected.address.streetNumber = value.streetNumber;
this.entity.selected.writeNew.address = false; this.entity.selected.writeNew.address = false;
this.updateMapCenter(value.point); this.updateMapCenter(value.point);
this.flag.dirty = true;
this.checkErrors(); this.checkErrors();
}, },
remove() { remove() {
this.flag.dirty = true;
this.entity.selected.address = {}; this.entity.selected.address = {};
this.checkErrors(); this.checkErrors();
}, },
@ -158,7 +156,6 @@ export default {
this.entity.selected.address.street = addr.street; this.entity.selected.address.street = addr.street;
this.entity.selected.address.streetNumber = addr.number; this.entity.selected.address.streetNumber = addr.number;
this.entity.selected.writeNew.address = true; this.entity.selected.writeNew.address = true;
this.flag.dirty = true;
this.checkErrors(); this.checkErrors();
} }
}, },

View File

@ -125,11 +125,9 @@ export default {
if (value.center) { if (value.center) {
this.updateMapCenter(value.center); this.updateMapCenter(value.center);
} }
this.flag.dirty = true;
this.checkErrors(); this.checkErrors();
}, },
remove() { remove() {
this.flag.dirty = true;
this.entity.selected.city = {}; this.entity.selected.city = {};
this.checkErrors(); this.checkErrors();
}, },

View File

@ -51,7 +51,6 @@ export default {
init() { init() {
if (this.value !== undefined) { if (this.value !== undefined) {
this.selectCountry(this.value); this.selectCountry(this.value);
this.flag.dirty = false;
} }
}, },
selectCountryByCode(countryCode) { selectCountryByCode(countryCode) {
@ -67,7 +66,6 @@ export default {
this.checkErrors(); this.checkErrors();
}, },
remove() { remove() {
this.flag.dirty = true;
this.entity.selected.country = null; this.entity.selected.country = null;
this.checkErrors(); this.checkErrors();
}, },

View File

@ -157,6 +157,7 @@ export default {
set(value) { set(value) {
console.log('isNoAddress value', value); console.log('isNoAddress value', value);
this.entity.selected.isNoAddress = value; this.entity.selected.isNoAddress = value;
this.checkErrors();
}, },
get() { get() {
return this.entity.selected.isNoAddress; return this.entity.selected.isNoAddress;

View File

@ -1,6 +1,6 @@
<template> <template>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="nav-item"> <li v-if="allowedTypes.includes('person')" class="nav-item">
<a class="nav-link" :class="{ active: isActive('person') }"> <a class="nav-link" :class="{ active: isActive('person') }">
<label for="person"> <label for="person">
<input type="radio" name="person" id="person" v-model="radioType" value="person"> <input type="radio" name="person" id="person" v-model="radioType" value="person">
@ -8,7 +8,7 @@
</label> </label>
</a> </a>
</li> </li>
<li class="nav-item"> <li v-if="allowedTypes.includes('thirdparty')" class="nav-item">
<a class="nav-link" :class="{ active: isActive('thirdparty') }"> <a class="nav-link" :class="{ active: isActive('thirdparty') }">
<label for="thirdparty"> <label for="thirdparty">
<input type="radio" name="thirdparty" id="thirdparty" v-model="radioType" value="thirdparty"> <input type="radio" name="thirdparty" id="thirdparty" v-model="radioType" value="thirdparty">
@ -21,14 +21,16 @@
<div class="my-4"> <div class="my-4">
<on-the-fly-person <on-the-fly-person
v-if="type === 'person'" v-if="type === 'person'"
v-bind:action="action" :action="action"
:query="query"
ref="castPerson" ref="castPerson"
> >
</on-the-fly-person> </on-the-fly-person>
<on-the-fly-thirdparty <on-the-fly-thirdparty
v-if="type === 'thirdparty'" v-if="type === 'thirdparty'"
v-bind:action="action" :action="action"
:query="query"
ref="castThirdparty" ref="castThirdparty"
> >
</on-the-fly-thirdparty> </on-the-fly-thirdparty>
@ -38,18 +40,17 @@
<script> <script>
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue'; import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue'; import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue';
import { postPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
export default { export default {
name: "OnTheFlyCreate", name: "OnTheFlyCreate",
props: ['action'], props: ['action', 'allowedTypes', 'query'],
components: { components: {
OnTheFlyPerson, OnTheFlyPerson,
OnTheFlyThirdparty OnTheFlyThirdparty
}, },
data() { data() {
return { return {
type: 'person' //by default type: null
} }
}, },
computed: { computed: {
@ -61,7 +62,10 @@ export default {
get() { get() {
return this.type; return this.type;
} }
} },
},
mounted() {
this.type = (this.allowedTypes.length === 1 && this.allowedTypes.includes('thirdparty')) ? 'thirdparty' : 'person'
}, },
methods: { methods: {
isActive(tab) { isActive(tab) {
@ -74,7 +78,7 @@ export default {
case 'thirdparty': case 'thirdparty':
let data = this.$refs.castThirdparty.$data.thirdparty; let data = this.$refs.castThirdparty.$data.thirdparty;
data.name = data.text; data.name = data.text;
if (data.address !== undefined) { if (data.address !== null) {
data.address = { id: data.address.address_id } data.address = { id: data.address.address_id }
} else { } else {
data.address = null; data.address = null;

View File

@ -54,6 +54,8 @@
<template v-slot:body v-else> <template v-slot:body v-else>
<on-the-fly-create <on-the-fly-create
:action="action" :action="action"
:allowedTypes="allowedTypes"
:query="query"
ref="castNew"> ref="castNew">
</on-the-fly-create> </on-the-fly-create>
</template> </template>
@ -90,7 +92,7 @@ export default {
OnTheFlyThirdparty, OnTheFlyThirdparty,
OnTheFlyCreate OnTheFlyCreate
}, },
props: ['type', 'id', 'action', 'buttonText', 'displayBadge', 'isDead', 'parent'], props: ['type', 'id', 'action', 'buttonText', 'displayBadge', 'isDead', 'parent', 'allowedTypes', 'query'],
emits: ['saveFormOnTheFly'], emits: ['saveFormOnTheFly'],
data() { data() {
return { return {
@ -129,6 +131,13 @@ export default {
return 'action.create'; return 'action.create';
} }
}, },
titleCreate() {
return this.allowedTypes.every(t => t === 'person')
? 'onthefly.create.title.person'
: this.allowedTypes.every(t => t === 'thirdparty')
? 'onthefly.create.title.thirdparty'
: 'onthefly.create.title.default'
},
titleModal() { titleModal() {
switch (this.action) { switch (this.action) {
case 'show': case 'show':
@ -136,7 +145,7 @@ export default {
case 'edit': case 'edit':
return 'onthefly.edit.' + this.type; return 'onthefly.edit.' + this.type;
case 'create': case 'create':
return 'onthefly.create.title'; return this.titleCreate;
} }
}, },
titleMessage() { titleMessage() {

View File

@ -9,11 +9,15 @@ const ontheflyMessages = {
}, },
edit: { edit: {
person: "Modifier un usager", person: "Modifier un usager",
thirdparty: "Modifier un tiers" thirdparty: "Modifier un tiers",
}, },
create: { create: {
button: "Créer \"{q}\"", button: "Créer \"{q}\"",
title: "Création d'un nouvel usager ou d'un tiers professionnel", title: {
default: "Création d'un nouvel usager ou d'un tiers professionnel",
person: "Création d'un nouvel usager",
thirdparty: "Création d'un nouveau tiers professionnel",
},
person: "un nouvel usager", person: "un nouvel usager",
thirdparty: "un nouveau tiers professionnel" thirdparty: "un nouveau tiers professionnel"
}, },

View File

@ -165,13 +165,6 @@ paths:
200: 200:
description: "OK" description: "OK"
/1.0/main/address.json: /1.0/main/address.json:
get:
tags:
- address
summary: Return a list of all Chill addresses
responses:
200:
description: "ok"
post: post:
tags: tags:
- address - address
@ -222,10 +215,44 @@ paths:
description: "Unprocessable entity (validation errors)" description: "Unprocessable entity (validation errors)"
400: 400:
description: "transition cannot be applyed" description: "transition cannot be applyed"
/1.0/main/address/{id}.json:
get:
tags:
- address
summary: Return an address by id
parameters:
- name: id
in: path
required: true
description: The address id
schema:
type: integer
format: integer
minimum: 1
responses:
200:
description: "ok"
content:
application/json:
schema:
$ref: '#/components/schemas/Address'
404:
description: "not found"
401:
description: "Unauthorized"
patch: patch:
tags: tags:
- address - address
summary: patch an address summary: patch an address
parameters:
- name: id
in: path
required: true
description: The address id
schema:
type: integer
format: integer
minimum: 1
requestBody: requestBody:
required: true required: true
content: content:
@ -277,31 +304,6 @@ paths:
400: 400:
description: "transition cannot be applyed" description: "transition cannot be applyed"
/1.0/main/address/{id}.json:
get:
tags:
- address
summary: Return an address by id
parameters:
- name: id
in: path
required: true
description: The address id
schema:
type: integer
format: integer
minimum: 1
responses:
200:
description: "ok"
content:
application/json:
schema:
$ref: '#/components/schemas/Address'
404:
description: "not found"
401:
description: "Unauthorized"
/1.0/main/address/{id}/duplicate.json: /1.0/main/address/{id}/duplicate.json:
post: post:

View File

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

View File

@ -30,7 +30,7 @@ class UserAccompanyingPeriodController extends AbstractController
} }
/** /**
* @Route("/{_locale}/accompanying-periods", name="chill_person_accompanying_period_user") * @Route("/{_locale}/person/accompanying-periods/my", name="chill_person_accompanying_period_user")
*/ */
public function listAction(Request $request) public function listAction(Request $request)
{ {
@ -44,13 +44,13 @@ class UserAccompanyingPeriodController extends AbstractController
); );
return $this->render('@ChillPerson/AccompanyingPeriod/user_periods_list.html.twig', [ return $this->render('@ChillPerson/AccompanyingPeriod/user_periods_list.html.twig', [
'accompanyingds' => $accompanyingPeriods, 'accompanyingPeriods' => $accompanyingPeriods,
'pagination' => $pagination, 'pagination' => $pagination,
]); ]);
} }
/** /**
* @Route("/{_locale}/accompanying-periods/drafts", name="chill_person_accompanying_period_draft_user") * @Route("/{_locale}/person/accompanying-periods/my/drafts", name="chill_person_accompanying_period_draft_user")
*/ */
public function listDraftsAction(Request $request) public function listDraftsAction(Request $request)
{ {

View File

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

View File

@ -20,7 +20,6 @@
<div class="form-check" v-for="p in participationWithoutHousehold" :key="p.id"> <div class="form-check" v-for="p in participationWithoutHousehold" :key="p.id">
<input type="checkbox" <input type="checkbox"
class="form-check-input" class="form-check-input"
v-model="hasNoHousehold"
name="persons[]" name="persons[]"
checked="checked" checked="checked"
:id="p.person.id" :id="p.person.id"

View File

@ -97,16 +97,10 @@ export default {
...mapGetters(['isJobValid', 'usersSuggestedFilteredByJob']), ...mapGetters(['isJobValid', 'usersSuggestedFilteredByJob']),
users: function () { users: function () {
let users = this.$store.getters.usersFilteredByJob; 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 // 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) { 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); users.push(this.$store.state.accompanyingCourse.user);
} }
console.log('users to return', users);
return users; return users;
}, },
valueJob: { valueJob: {

View File

@ -6,7 +6,7 @@
<div v-if="accompanyingCourse.requestor && isAnonymous" class="flex-table"> <div v-if="accompanyingCourse.requestor && isAnonymous" class="flex-table">
<label> <label>
<input type="checkbox" v-model="isAnonymous" class="me-2" /> <input type="checkbox" v-model="requestorIsAnonymous" class="me-2" />
{{ $t('requestor.is_anonymous') }} {{ $t('requestor.is_anonymous') }}
</label> </label>
<confidential v-if="accompanyingCourse.requestor.type === 'thirdparty'"> <confidential v-if="accompanyingCourse.requestor.type === 'thirdparty'">
@ -72,7 +72,7 @@
<div v-else-if="accompanyingCourse.requestor && !isAnonymous" class="flex-table"> <div v-else-if="accompanyingCourse.requestor && !isAnonymous" class="flex-table">
<label> <label>
<input type="checkbox" v-model="isAnonymous" class="me-2" /> <input type="checkbox" v-model="requestorIsAnonymous" class="me-2" />
{{ $t('requestor.is_anonymous') }} {{ $t('requestor.is_anonymous') }}
</label> </label>
@ -199,7 +199,7 @@ export default {
...mapState({ ...mapState({
suggestedEntities: state => { suggestedEntities: state => {
return [ return [
...state.accompanyingCourse.participations.map(p => p.person), ...state.accompanyingCourse.participations.filter((p) => p.endDate === null).map((p) => p.person),
...state.accompanyingCourse.resources.map(r => r.resource) ...state.accompanyingCourse.resources.map(r => r.resource)
] ]
.filter((e) => e !== null) .filter((e) => e !== null)
@ -218,7 +218,7 @@ export default {
accompanyingCourse() { accompanyingCourse() {
return this.$store.state.accompanyingCourse return this.$store.state.accompanyingCourse
}, },
isAnonymous: { requestorIsAnonymous: {
set(value) { set(value) {
this.$store.dispatch('requestorIsAnonymous', value); this.$store.dispatch('requestorIsAnonymous', value);
}, },
@ -287,7 +287,9 @@ export default {
body.name = payload.data.text; body.name = payload.data.text;
body.email = payload.data.email; body.email = payload.data.email;
body.telephone = payload.data.phonenumber; body.telephone = payload.data.phonenumber;
if (payload.data.address) {
body.address = { id: payload.data.address.address_id }; body.address = { id: payload.data.address.address_id };
}
makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body) makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body)
.then(response => { .then(response => {

View File

@ -77,7 +77,7 @@ export default {
counter: state => state.accompanyingCourse.resources.length, counter: state => state.accompanyingCourse.resources.length,
suggestedEntities: state => [ suggestedEntities: state => [
state.accompanyingCourse.requestor, state.accompanyingCourse.requestor,
...state.accompanyingCourse.participations.map(p => p.person), ...state.accompanyingCourse.participations.filter((p) => p.endDate === null).map((p) => p.person),
] ]
.filter((e) => e !== null) .filter((e) => e !== null)
.filter( .filter(

View File

@ -428,42 +428,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
throw error; throw error;
}) })
}, },
/**
* On The Fly
*/
patchOnTheFly({ commit }, payload) {
// TODO should be into the dedicated component, no ? JF
console.log('## action: patch OnTheFly', payload);
let body = { type: payload.type };
if (payload.type === 'person') {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.gender = payload.data.gender;
console.log('id', payload.data.id, 'and body', body);
patchPerson(payload.data.id, body)
.then(person => new Promise((resolve, reject) => {
console.log('patch person', person);
commit('updatePerson', { target: payload.target, person: person });
resolve();
}));
}
else if (payload.type === 'thirdparty') {
body.name = payload.data.text;
body.email = payload.data.email;
body.telephone = payload.data.phonenumber;
body.address = { id: payload.data.address.address_id };
console.log('id', payload.data.id, 'and body', body);
patchThirdparty(payload.data.id, body)
.then(thirdparty => new Promise((resolve, reject) => {
console.log('patch thirdparty', thirdparty);
commit('updateThirdparty', { target: payload.target, thirdparty: thirdparty });
resolve();
}));
}
},
/** /**
* Update accompanying course intensity/emergency/confidentiality * Update accompanying course intensity/emergency/confidentiality
*/ */

View File

@ -397,36 +397,6 @@ const store = createStore({
commit('setErrors', error.violations); commit('setErrors', error.violations);
}); });
}, },
patchOnTheFly({ commit }, payload) {
let body = { type: payload.type };
const id = payload.data.id;
let url = `/api/1.0/person/person/${id}.json`;
let mutation = "updatePerson";
if (payload.type === 'person') {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.gender = payload.data.gender;
} else if (payload.type === 'thirdparty') {
body.name = payload.data.text;
body.email = payload.data.email;
body.telephone = payload.data.phonenumber;
body.address = { id: payload.data.address.address_id };
url = `/api/1.0/thirdparty/thirdparty/${id}.json`;
mutation = 'updateThirdparty'
}
makeFetch('PATCH', url, body)
.then((response) => {
commit(mutation, {target: payload.target, thirdparty: response});
})
.catch((error) => {
throw error;
})
},
} }
}); });

View File

@ -62,8 +62,10 @@
<div class="create-button"> <div class="create-button">
<on-the-fly <on-the-fly
v-if="query.length >= 3" v-if="queryLength >= 3 && (options.type.includes('person') || options.type.includes('thirdparty'))"
:buttonText="$t('onthefly.create.button', {q: query})" :buttonText="$t('onthefly.create.button', {q: query})"
:allowedTypes="options.type"
:query="query"
action="create" action="create"
@saveFormOnTheFly="saveFormOnTheFly" @saveFormOnTheFly="saveFormOnTheFly"
ref="onTheFly"> ref="onTheFly">

View File

@ -32,6 +32,14 @@
<label for="lastname">{{ $t('person.lastname') }}</label> <label for="lastname">{{ $t('person.lastname') }}</label>
</div> </div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li v-for="(qi, i) in queryItems" :key="i" @click="addQueryItem('lastName', qi)">
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
<div class="form-floating mb-3"> <div class="form-floating mb-3">
<input <input
class="form-control form-control-lg" class="form-control form-control-lg"
@ -43,6 +51,14 @@
<label for="firstname">{{ $t('person.firstname') }}</label> <label for="firstname">{{ $t('person.firstname') }}</label>
</div> </div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li v-for="(qi, i) in queryItems" :key="i" @click="addQueryItem('firstName', qi)">
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
<div v-for="(a, i) 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 <input
class="form-control form-control-lg" class="form-control form-control-lg"
@ -122,7 +138,7 @@ import PersonRenderBox from '../Entity/PersonRenderBox.vue';
export default { export default {
name: "OnTheFlyPerson", name: "OnTheFlyPerson",
props: ['id', 'type', 'action'], props: ['id', 'type', 'action', 'query'],
//emits: ['createAction'], //emits: ['createAction'],
components: { components: {
PersonRenderBox PersonRenderBox
@ -203,6 +219,9 @@ export default {
}, },
personAltNamesLabels() { personAltNamesLabels() {
return this.person.altNames.map(a => a ? a.label : ''); return this.person.altNames.map(a => a ? a.label : '');
},
queryItems() {
return this.query ? this.query.split(' ') : null;
} }
}, },
mounted() { mounted() {
@ -244,6 +263,16 @@ export default {
) )
this.person.altNames = updateAltNames; this.person.altNames = updateAltNames;
}, },
addQueryItem(field, queryItem) {
switch (field) {
case 'lastName':
this.person.lastName = queryItem;
break;
case 'firstName':
this.person.firstName = queryItem;
break;
}
}
} }
} }
</script> </script>

View File

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

View File

@ -172,7 +172,7 @@
{%- if options['customButtons']['replace'] is defined -%} {%- if options['customButtons']['replace'] is defined -%}
{{ options['customButtons']['replace'] }} {{ options['customButtons']['replace'] }}
{%- elseif is_granted('CHILL_PERSON_SEE', person) -%} {%- elseif is_granted('CHILL_PERSON_SEE', person) and options['addLink'] -%}
<li> <li>
<a class="btn btn-sm btn-show" title="{{ 'Show person'|trans }}" <a class="btn btn-sm btn-show" title="{{ 'Show person'|trans }}"
href="{{ path('chill_person_view', { person_id: person.id }) }}"></a> href="{{ path('chill_person_view', { person_id: person.id }) }}"></a>

View File

@ -56,6 +56,11 @@
{% if action is defined %} {% if action is defined %}
<ul class="record_actions sticky-form-buttons"> <ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('chill_person_resource_list', { 'person_id': resource.personOwner.id } ) }}" class="btn btn-cancel">
{{ 'Cancel'|trans }}
</a>
</li>
<li class="edit"> <li class="edit">
<button class="btn btn-edit" <button class="btn btn-edit"
type="submit" id="newPersonResource"> type="submit" id="newPersonResource">

View File

@ -22,42 +22,34 @@
<div class="flex-table"> <div class="flex-table">
{% for resource in personResources %} {% for resource in personResources %}
<div class="item-bloc"> <div class="item-bloc">
{% if resource.kind is not null %}
<div class="item-row"> <div class="item-row">
<div class="item-col" style="width: 50%"> <section>
<p>{{ resource.kind.title.fr|capitalize }}</p>
</section>
</div>
{% endif %}
<div class="{% if resource.kind is not null %} separator {% endif %}">
{% if resource.person is not null %} {% if resource.person is not null %}
<div class="denomination h3"> {{ resource.person|chill_entity_render_box({
<span> 'render': 'bloc',
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with { 'addLink': true,
action: 'show', displayBadge: true, 'addInfo': true,
targetEntity: { name: 'person', id: resource.person.id }, 'addAge': true
buttonText: resource.person|chill_entity_render_string, }) }}
isDead: resource.person.deathdate is not null
} %}
</span>
</div>
{% elseif resource.thirdparty is not null %} {% elseif resource.thirdparty is not null %}
<div class="denomination h3"> {{ resource.thirdparty|chill_entity_render_box({
<span> 'render': 'bloc',
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with { 'showContacts': false,
action: 'show', displayBadge: true, 'addLink': true,
targetEntity: { name: 'thirdparty', id: resource.thirdparty.id }, 'isConfidential': (resource.thirdparty.contactDataAnonymous ? true : false)
buttonText: resource.thirdParty|chill_entity_render_string, }) }}
parent: resource.thirdparty.parent
} %}
</span>
</div>
{% else %} {% else %}
<div class="denomination h3"> <div class="denomination h3">
<span>{{ resource.freetext }}</span> <span>{{ resource.freetext }}</span>
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="item-col" style="justify-content: flex-end; ">
{% if resource.kind %}
<span>{{ resource.kind.title.fr|capitalize }}</span>
{% endif %}
</div>
</div>
{% if resource.comment.comment is not empty %} {% if resource.comment.comment is not empty %}
<div class="item-row separator"> <div class="item-row separator">
<section class="chill-entity entity-comment-embeddable"> <section class="chill-entity entity-comment-embeddable">

View File

@ -240,6 +240,7 @@ Select a type: "Choisissez un type"
Select a person: "Choisissez un usager" Select a person: "Choisissez un usager"
Select a thirdparty: "Choisissez un tiers" Select a thirdparty: "Choisissez un tiers"
Contact person: "Personne de contact" Contact person: "Personne de contact"
Kind: "Type"
# pickAPersonType # pickAPersonType

View File

@ -179,6 +179,8 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
* @var string * @var string
* @ORM\Column(name="name", type="string", length=255) * @ORM\Column(name="name", type="string", length=255)
* @Assert\Length(min="2") * @Assert\Length(min="2")
* @Assert\NotNull
* @Assert\NotBlank
* @Groups({"read", "write", "docgen:read", "docgen:read:3party:parent"}) * @Groups({"read", "write", "docgen:read", "docgen:read:3party:parent"})
*/ */
private ?string $name = ''; private ?string $name = '';

View File

@ -61,6 +61,13 @@
<input class="form-control form-control-lg" id="name" v-model="thirdparty.text" v-bind:placeholder="$t('thirdparty.name')" /> <input class="form-control form-control-lg" id="name" v-model="thirdparty.text" v-bind:placeholder="$t('thirdparty.name')" />
<label for="name">{{ $t('thirdparty.name') }}</label> <label for="name">{{ $t('thirdparty.name') }}</label>
</div> </div>
<div v-if="query">
<ul class="list-suggest add-items inline">
<li @click="addQuery(query)">
<span class="person-text">{{ query }}</span>
</li>
</ul>
</div>
<template <template
v-if="thirdparty.kind !== 'child'"> v-if="thirdparty.kind !== 'child'">
@ -85,7 +92,7 @@
<div class="input-group mb-3"> <div class="input-group mb-3">
<span class="input-group-text" id="phonenumber"><i class="fa fa-fw fa-phone"></i></span> <span class="input-group-text" id="phonenumber"><i class="fa fa-fw fa-phone"></i></span>
<input class="form-control form-control-lg" <input class="form-control form-control-lg"
v-model="thirdparty.phonenumber" v-model="thirdparty.telephone"
v-bind:placeholder="$t('thirdparty.phonenumber')" v-bind:placeholder="$t('thirdparty.phonenumber')"
v-bind:aria-label="$t('thirdparty.phonenumber')" v-bind:aria-label="$t('thirdparty.phonenumber')"
aria-describedby="phonenumber" /> aria-describedby="phonenumber" />
@ -102,7 +109,7 @@ import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
export default { export default {
name: "OnTheFlyThirdParty", name: "OnTheFlyThirdParty",
props: ['id', 'type', 'action'], props: ['id', 'type', 'action', 'query'],
components: { components: {
ThirdPartyRenderBox, ThirdPartyRenderBox,
AddAddress, AddAddress,
@ -113,6 +120,11 @@ export default {
//context: {}, <-- //context: {}, <--
thirdparty: { thirdparty: {
type: 'thirdparty', type: 'thirdparty',
address: null,
kind: 'company',
name: '',
telephone: '',
}, },
addAddress: { addAddress: {
options: { options: {
@ -186,6 +198,9 @@ export default {
this.thirdparty.address = payload.address; // <-- this.thirdparty.address = payload.address; // <--
console.log('switch address to edit mode', this.context); console.log('switch address to edit mode', this.context);
} }
},
addQuery(query) {
this.thirdparty.text = query;
} }
}, },
mounted() { mounted() {