Merge remote-tracking branch 'origin/master'

This commit is contained in:
Julien Fastré 2021-12-12 21:05:35 +01:00
commit e21f12d96c
54 changed files with 1184 additions and 822 deletions

View File

@ -11,11 +11,23 @@ and this project adheres to
## Unreleased
<!-- write down unreleased development here -->
* [main] change address format in case the country is France, in Address render box and address normalizer
* [person] add validator for accompanying period with a test on social issues (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/76)
* [activity] fix visibility for location
* [origin] fix origin: use correctly the translatable strings
* /!\ everyone must update the origin table. As there is only one row, execute `update chill_person_accompanying_period_origin set label = jsonb_build_object('fr', 'appel téléphonique');`
* [person] redirect bug fixed.
* [action] add an unrelated issue within action creation.
* [origin] fix origin: use correctly the translatable strings
* /!\ everyone must update the origin table. As there is only one row, execute `update chill_person_accompanying_period_origin set label = jsonb_build_object('fr', 'appel téléphonique');`
* [main] change order of civilities in civility fixtures (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
* [person] set min attr in the minimum of children field (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
* [person] add marital status date in person view (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
* [person] show number of children + allow set number of children to null (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
* [person] show acceptSMS option (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
* [person] add death information in person render box in twig and vue render boxes (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
## Test releases
@ -33,6 +45,9 @@ and this project adheres to
* [activity] create work if a work with same social action is not associated to the activity
* [visgraph] improve and fix bugs on vis-network relationship graph
* [bugfix] posting of birth- and deathdate through api fixed.
* [suggestions] improve suggestions lists
* [badge-entity] design coherency between badge-person and 3 kinds of badge-thirdparty
* [AddPersons] suggestions row are clickable, not only checkbox
### Test release 2021-11-19 - bis

View File

@ -409,3 +409,4 @@ Créer un titre enlevable (avec une croix rouge cliquable, l'ancre a est vide)
<a></a>
</div>
```
Les classes `cols` ou `inline` peuvent être ajoutées à côté de `list-suggest` pour modifier la disposition de la liste.

View File

@ -11,7 +11,7 @@
</persons-bloc>
</div>
<div v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0">
<ul class="list-suggest add-items">
<ul class="list-suggest add-items inline">
<li v-for="p in suggestedEntities" @click="addSuggestedEntity(p)">
<span>{{ p.text }}</span>
</li>

View File

@ -6,17 +6,17 @@ const debug = process.env.NODE_ENV !== 'production';
//console.log('window.activity', window.activity);
const addIdToValue = (string, id) => {
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
};
const removeIdFromValue = (string, id) => {
let array = string.split(',');
array = array.filter(el => el !== id.toString());
let str = array.join();
return str;
let array = string.split(',');
array = array.filter(el => el !== id.toString());
let str = array.join();
return str;
};
const store = createStore({
@ -50,9 +50,9 @@ const store = createStore({
return state.activity.activityType.personsVisible === 0
? []
: state.activity.accompanyingPeriod.participations
.filter((p) => p.endDate === null)
.map((p) => p.person)
.filter((p) => !existingPersonIds.includes(p.id));
.filter((p) => p.endDate === null)
.map((p) => p.person)
.filter((p) => !existingPersonIds.includes(p.id));
},
suggestedRequestor(state) {
if (state.activity.accompanyingPeriod.requestor === null) {
@ -78,8 +78,8 @@ const store = createStore({
return state.activity.activityType.usersVisible === 0
? []
: [state.activity.accompanyingPeriod.user].filter(
(u) => u !== null && !existingUserIds.includes(u.id)
);
(u) => u !== null && !existingUserIds.includes(u.id)
);
},
suggestedResources(state) {
const resources = state.activity.accompanyingPeriod.resources;

View File

@ -26,8 +26,8 @@ class LoadCivility extends Fixture implements FixtureGroupInterface
public function load(ObjectManager $manager): void
{
$civilities = [
['name' => ['fr' => 'Monsieur'], 'abbrev' => ['fr' => 'M.']],
['name' => ['fr' => 'Madame'], 'abbrev' => ['fr' => 'Mme']],
['name' => ['fr' => 'Monsieur'], 'abbrev' => ['fr' => 'M.']],
['name' => ['fr' => 'Docteur'], 'abbrev' => ['fr' => 'Dr']],
['name' => ['fr' => 'Professeur'], 'abbrev' => ['fr' => 'Pr']],
['name' => ['fr' => 'Madame la Directrice'], 'abbrev' => ['fr' => 'Mme']],

View File

@ -186,7 +186,7 @@ class User implements AdvancedUserInterface
/**
* @return string
*/
public function getEmail()
public function getEmail(): ?string
{
return $this->email;
}

View File

@ -25,6 +25,15 @@ ul.list-suggest {
text-align: start;
margin-bottom: 3px;
}
&.cols {
columns: 3;
}
&.inline {
li {
display: inline-block;
margin-right: 0.2em;
}
}
&.add-items {
li {
cursor: pointer;
@ -34,6 +43,9 @@ ul.list-suggest {
content: "\f067"; // fa-plus
color: var(--bs-success);
}
& span:hover {
color: $chill-l-gray;
}
}
}
&.remove-items {

View File

@ -0,0 +1,42 @@
<template>
<span v-if="entity.type === 'person'" class="badge rounded-pill bg-person">
{{ $t('renderbox.person') }}
</span>
<span v-if="entity.type === 'thirdparty'" class="badge rounded-pill bg-thirdparty">
<template v-if="options.displayLong !== true">
{{ $t('renderbox.type.thirdparty')}}
</template>
<i class="fa fa-fw fa-user" v-if="entity.kind === 'child'"></i>
<i class="fa fa-fw fa-hospital-o" v-else-if="entity.kind === 'company'"></i>
<i class="fa fa-fw fa-user-md" v-else></i>
<template v-if="options.displayLong === true">
<span v-if="entity.kind === 'child'">{{ $t('tparty.child')}}</span>
<span v-else-if="entity.kind === 'company'">{{ $t('tparty.company')}}</span>
<span v-else>{{ $t('tparty.contact')}}</span>
</template>
</span>
</template>
<script>
export default {
name: "BadgeEntity",
props: ['options', 'entity'],
i18n: {
messages: {
fr: {
tparty: {
child: "Personne de contact",
company: "Personne morale",
contact: "Personne physique",
}
}
}
}
}
</script>

View File

@ -12,13 +12,11 @@
* extended_infos bool add extra informations (step, floor, etc.)
#}
{% macro raw(address, options) %}
{% macro raw(address, options, streetLine) %}
{% if address.street is not empty %}
<p class="street">{{ address.street }}
{% if address.streetNumber is not empty %}
<span class="streetnumber">{{ address.streetNumber }}</span>
{% endif %}
</p>
<p>{{ streetLine }}</p>
{% endif %}
{% if options['extended_infos'] %}
{{ _self.extended(address, options) }}
@ -56,7 +54,7 @@
{% endif %}
{% endmacro %}
{% macro inline(address, options) %}
{% macro inline(address, options, streetLine) %}
{% if options['has_no_address'] == true and address.isNoAddress == true %}
{% if address.postCode is not empty %}
<p class="postcode">
@ -70,7 +68,7 @@
</span>
{% else %}
<span class="address{% if options['multiline'] %} multiline{% endif %}{% if options['with_delimiter'] %} delimiter{% endif %}">
{{ _self.raw(address, options) }}
{{ _self.raw(address, options, streetLine) }}
</span>
{% endif %}
{{ _self.validity(address, options) }}
@ -99,7 +97,7 @@
{% if options['with_picto'] %}
<i class="fa fa-li fa-map-marker"></i>
{% endif %}
{{ _self.inline(address, options) }}
{{ _self.inline(address, options, streetLine) }}
</li>
{%- endif -%}
@ -108,7 +106,7 @@
{% if options['with_picto'] %}
<i class="fa fa-fw fa-map-marker"></i>
{% endif %}
{{ _self.inline(address, options) }}
{{ _self.inline(address, options, streetLine) }}
</span>
{%- endif -%}
@ -133,7 +131,7 @@
{% if options['with_picto'] %}
<i class="fa fa-fw fa-map-marker"></i>
{% endif %}
{{ _self.raw(address, options) }}
{{ _self.raw(address, options, streetLine) }}
</div>
{% endif %}
{{ _self.validity(address, options) }}

View File

@ -1,5 +1,5 @@
{{ form_start(form) }}
<div class="chill_filter_order container">
<div class="chill_filter_order container my-4">
<div class="row">
{% if form.vars.has_search_box %}
<div class="col-md-12">

View File

@ -52,9 +52,19 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw
public function normalize($address, ?string $format = null, array $context = [])
{
if ($address instanceof Address) {
$text = $address->isNoAddress() ? '' : $address->getStreet() . ', ' . $address->getStreetNumber();
if (null !== $address->getPostCode()->getCountry()->getCountryCode()) {
if ($address->getPostCode()->getCountry()->getCountryCode() === 'FR') {
$text = $address->isNoAddress() ? '' : $address->getStreetNumber() . ', ' . $address->getStreet();
} else {
$text = $address->isNoAddress() ? '' : $address->getStreetNumber() . ', ' . $address->getStreet();
}
}
$data = [
'address_id' => $address->getId(),
'text' => $address->isNoAddress() ? '' : $address->getStreetNumber() . ', ' . $address->getStreet(),
'text' => $text,
'street' => $address->getStreet(),
'streetNumber' => $address->getStreetNumber(),
'postcode' => [

View File

@ -46,6 +46,7 @@ class AddressRender implements ChillEntityRenderInterface
return $this->templating
->render('@ChillMain/Entity/address.html.twig', [
'address' => $addr,
'streetLine' => $this->renderStreetLine($addr),
'render' => $options['render'] ?? 'bloc',
'options' => $options,
]);
@ -59,13 +60,7 @@ class AddressRender implements ChillEntityRenderInterface
{
$lines = [];
if (!empty($addr->getStreet())) {
$lines[0] = $addr->getStreet();
}
if (!empty($addr->getStreetNumber())) {
$lines[0] .= ', ' . $addr->getStreetNumber();
}
$lines[0] = $this->renderStreetLine($addr);
if (!empty($addr->getPostcode())) {
$lines[1] = strtr('{postcode} {label}', [
@ -81,4 +76,33 @@ class AddressRender implements ChillEntityRenderInterface
{
return $entity instanceof Address;
}
private function renderStreetLine($addr): string
{
if (!empty($addr->getStreet())) {
$street = $addr->getStreet();
} else {
$street = '';
}
if (!empty($addr->getStreetNumber())) {
$streetNumber = $addr->getStreetNumber();
} else {
$streetNumber = '';
}
$res = trim($street . ', ' . $streetNumber, ', ');
if (null !== $addr->getPostCode()->getCountry()->getCountryCode()) {
if ($addr->getPostCode()->getCountry()->getCountryCode() === 'FR') {
$res = trim($streetNumber . ', ' . $street, ', ');
}
}
if (',' === $res) {
$res = '';
}
return $res;
}
}

View File

@ -34,6 +34,8 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Workflow\Registry;
use function array_values;
@ -294,4 +296,17 @@ final class AccompanyingCourseApiController extends ApiController
return null;
}
protected function validate(string $action, Request $request, string $_format, $entity, array $more = []): ConstraintViolationListInterface
{
if ('work' !== $action) {
return parent::validate($action, $request, $_format, $entity, $more);
}
if (Request::METHOD_POST === $request->getMethod()) {
return $this->getValidator()->validate($more[0], null);
}
return new ConstraintViolationList([]);
}
}

View File

@ -186,7 +186,7 @@ class HouseholdMemberController extends ApiController
$_format,
['groups' => ['read']]
);
} catch (Exception\InvalidArgumentException | Exception\UnexpectedValueException $e) {
} catch (Exception\InvalidArgumentException|Exception\UnexpectedValueException $e) {
throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e);
}

View File

@ -222,9 +222,7 @@ 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 an household',
]); // TODO createHousehold form action
]);
$form->handleRequest($request);

View File

@ -79,6 +79,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
$loader->load('services/serializer.yaml');
$loader->load('services/security.yaml');
$loader->load('services/doctrineEventListener.yaml');
$loader->load('services/accompanyingPeriodConsistency.yaml');
if ($container->getParameter('chill_person.accompanying_period') !== 'hidden') {
$loader->load('services/exports_accompanying_period.yaml');

View File

@ -80,6 +80,7 @@ class Configuration implements ConfigurationInterface
->append($this->addFieldNode('memo'))
->append($this->addFieldNode('number_of_children'))
->append($this->addFieldNode('acceptEmail'))
->append($this->addFieldNode('deathdate'))
->arrayNode('alt_names')
->defaultValue([])
->arrayPrototype()

View File

@ -14,10 +14,12 @@ namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodLinkedWithSocialIssuesEntityInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\SocialWork\Result;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use DateTimeImmutable;
use DateTimeInterface;
@ -28,458 +30,470 @@ use LogicException;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
* @ORM\Table(name="chill_person_accompanying_period_work")
* @Serializer\DiscriminatorMap(
* typeProperty="type",
* mapping={
* "accompanying_period_work": AccompanyingPeriodWork::class
* }
* )
*/
class AccompanyingPeriodWork implements TrackCreationInterface, TrackUpdateInterface
{
/**
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
* @Serializer\Groups({"read"})
*/
private ?AccompanyingPeriod $accompanyingPeriod = null;
/**
* @ORM\OneToMany(
* targetEntity=AccompanyingPeriodWorkEvaluation::class,
* mappedBy="accompanyingPeriodWork",
* cascade={"remove", "persist"},
* orphanRemoval=true
* )
* @Serializer\Groups({"read", "docgen:read"})
*
* @internal /!\ the serialization for write evaluations is handled in `AccompanyingPeriodWorkDenormalizer`
*/
private Collection $accompanyingPeriodWorkEvaluations;
/**
* @ORM\Column(type="datetime_immutable")
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?DateTimeImmutable $createdAt = null;
/**
* @ORM\Column(type="boolean")
* @Serializer\Groups({"read", "docgen:read"})
*/
private bool $createdAutomatically = false;
/**
* @ORM\Column(type="text")
* @Serializer\Groups({"read", "docgen:read"})
*/
private string $createdAutomaticallyReason = '';
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?User $createdBy = null;
/**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"accompanying_period_work:create"})
* @Serializer\Groups({"accompanying_period_work:edit"})
* @Serializer\Groups({"read", "docgen:read"})
* @Assert\GreaterThan(propertyPath="startDate",
* message="accompanying_course_work.The endDate should be greater than the start date"
* )
*/
private ?DateTimeImmutable $endDate = null;
/**
* @ORM\OneToMany(
* targetEntity=AccompanyingPeriodWorkGoal::class,
* mappedBy="accompanyingPeriodWork",
* cascade={"persist"},
* orphanRemoval=true
* )
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*/
private Collection $goals;
/**
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*
* In schema : traitant
*/
private ?ThirdParty $handlingThierParty = null;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?int $id = null;
/**
* @ORM\Column(type="text")
* @Serializer\Groups({"read", "accompanying_period_work:edit", "docgen:read"})
*/
private string $note = '';
/**
* @ORM\ManyToMany(targetEntity=Person::class)
* @ORM\JoinTable(name="chill_person_accompanying_period_work_person")
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
* @Serializer\Groups({"accompanying_period_work:create"})
*/
private Collection $persons;
/**
* @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorks")
* @ORM\JoinTable(name="chill_person_accompanying_period_work_result")
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*/
private Collection $results;
/**
* @ORM\ManyToOne(targetEntity=SocialAction::class)
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:create"})
*/
private ?SocialAction $socialAction = null;
/**
* @ORM\Column(type="date_immutable")
* @Serializer\Groups({"accompanying_period_work:create"})
* @Serializer\Groups({"accompanying_period_work:edit"})
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?DateTimeImmutable $startDate = null;
/**
* @ORM\ManyToMany(targetEntity=ThirdParty::class)
* @ORM\JoinTable(name="chill_person_accompanying_period_work_third_party")
*
* In schema : intervenants
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*/
private Collection $thirdParties;
/**
* @ORM\Column(type="datetime_immutable")
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?DateTimeImmutable $updatedAt = null;
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?User $updatedBy = null;
public function __construct()
{
$this->goals = new ArrayCollection();
$this->results = new ArrayCollection();
$this->thirdParties = new ArrayCollection();
$this->persons = new ArrayCollection();
$this->accompanyingPeriodWorkEvaluations = new ArrayCollection();
}
public function addAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self
{
if (!$this->accompanyingPeriodWorkEvaluations->contains($evaluation)) {
$this->accompanyingPeriodWorkEvaluations[] = $evaluation;
$evaluation->setAccompanyingPeriodWork($this);
}
return $this;
}
public function addGoal(AccompanyingPeriodWorkGoal $goal): self
{
if (!$this->goals->contains($goal)) {
$this->goals[] = $goal;
$goal->setAccompanyingPeriodWork($this);
}
return $this;
}
public function addPerson(Person $person): self
{
if (!$this->persons->contains($person)) {
$this->persons[] = $person;
}
return $this;
}
public function addResult(Result $result): self
{
if (!$this->results->contains($result)) {
$this->results[] = $result;
}
return $this;
}
public function addThirdParty(ThirdParty $thirdParty): self
{
if (!$this->thirdParties->contains($thirdParty)) {
$this->thirdParties[] = $thirdParty;
}
return $this;
}
public function getAccompanyingPeriod(): ?AccompanyingPeriod
{
return $this->accompanyingPeriod;
}
/**
* @return Collection
*/
public function getAccompanyingPeriodWorkEvaluations()
{
return $this->accompanyingPeriodWorkEvaluations;
}
public function getCreatedAt(): ?DateTimeImmutable
{
return $this->createdAt;
}
public function getCreatedAutomatically(): ?bool
{
return $this->createdAutomatically;
}
public function getCreatedAutomaticallyReason(): ?string
{
return $this->createdAutomaticallyReason;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function getEndDate(): ?DateTimeInterface
{
return $this->endDate;
}
/**
* @return AccompanyingPeriodWorkGoal[]|Collection
*/
public function getGoals(): Collection
{
return $this->goals;
}
public function getHandlingThierParty(): ?ThirdParty
{
return $this->handlingThierParty;
}
public function getId(): ?int
{
return $this->id;
}
public function getNote(): ?string
{
return $this->note;
}
public function getPersons(): Collection
{
return $this->persons;
}
/**
* @return Collection|Result[]
*/
public function getResults(): Collection
{
return $this->results;
}
public function getSocialAction(): ?SocialAction
{
return $this->socialAction;
}
public function getStartDate(): ?DateTimeInterface
{
return $this->startDate;
}
/**
* @return Collection|ThirdParty[]
*/
public function getThirdParties(): Collection
{
return $this->thirdParties;
}
public function getThirdPartys(): Collection
{
return $this->getThirdParties();
}
public function getUpdatedAt(): ?DateTimeImmutable
{
return $this->updatedAt;
}
public function getUpdatedBy(): ?User
{
return $this->updatedBy;
}
public function removeAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self
{
$this->accompanyingPeriodWorkEvaluations
->removeElement($evaluation);
$evaluation->setAccompanyingPeriodWork(null);
return $this;
}
public function removeGoal(AccompanyingPeriodWorkGoal $goal): self
{
if ($this->goals->removeElement($goal)) {
// set the owning side to null (unless already changed)
if ($goal->getAccompanyingPeriodWork() === $this) {
$goal->setAccompanyingPeriodWork(null);
}
}
return $this;
}
public function removePerson(Person $person): self
{
$this->persons->removeElement($person);
return $this;
}
public function removeResult(Result $result): self
{
$this->results->removeElement($result);
return $this;
}
public function removeThirdParty(ThirdParty $thirdParty): self
{
$this->thirdParties->removeElement($thirdParty);
return $this;
}
/**
* Internal: you should use `$accompanyingPeriod->removeWork($work);` or
* `$accompanyingPeriod->addWork($work);`.
*/
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{
if ($this->accompanyingPeriod instanceof AccompanyingPeriod
&& $accompanyingPeriod !== $this->accompanyingPeriod) {
throw new LogicException('A work cannot change accompanyingPeriod');
}
$this->accompanyingPeriod = $accompanyingPeriod;
return $this;
}
public function setCreatedAt(DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function setCreatedAutomatically(bool $createdAutomatically): self
{
$this->createdAutomatically = $createdAutomatically;
return $this;
}
public function setCreatedAutomaticallyReason(string $createdAutomaticallyReason): self
{
$this->createdAutomaticallyReason = $createdAutomaticallyReason;
return $this;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
/**
* @ORM\Entity
* @ORM\Table(name="chill_person_accompanying_period_work")
* @Serializer\DiscriminatorMap(
* typeProperty="type",
* mapping={
* "accompanying_period_work": AccompanyingPeriodWork::class
* }
* )
*/
class AccompanyingPeriodWork implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface, TrackCreationInterface, TrackUpdateInterface
{
/**
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
* @Serializer\Groups({"read"})
*/
private ?AccompanyingPeriod $accompanyingPeriod = null;
/**
* @ORM\OneToMany(
* targetEntity=AccompanyingPeriodWorkEvaluation::class,
* mappedBy="accompanyingPeriodWork",
* cascade={"remove", "persist"},
* orphanRemoval=true
* )
* @Serializer\Groups({"read", "docgen:read"})
*
* @internal /!\ the serialization for write evaluations is handled in `AccompanyingPeriodWorkDenormalizer`
*/
private Collection $accompanyingPeriodWorkEvaluations;
/**
* @ORM\Column(type="datetime_immutable")
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?DateTimeImmutable $createdAt = null;
/**
* @ORM\Column(type="boolean")
* @Serializer\Groups({"read", "docgen:read"})
*/
private bool $createdAutomatically = false;
/**
* @ORM\Column(type="text")
* @Serializer\Groups({"read", "docgen:read"})
*/
private string $createdAutomaticallyReason = '';
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?User $createdBy = null;
/**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"accompanying_period_work:create"})
* @Serializer\Groups({"accompanying_period_work:edit"})
* @Serializer\Groups({"read", "docgen:read"})
* @Assert\GreaterThan(propertyPath="startDate",
* message="accompanying_course_work.The endDate should be greater than the start date"
* )
*/
private ?DateTimeImmutable $endDate = null;
/**
* @ORM\OneToMany(
* targetEntity=AccompanyingPeriodWorkGoal::class,
* mappedBy="accompanyingPeriodWork",
* cascade={"persist"},
* orphanRemoval=true
* )
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*/
private Collection $goals;
/**
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*
* In schema : traitant
*/
private ?ThirdParty $handlingThierParty = null;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?int $id = null;
/**
* @ORM\Column(type="text")
* @Serializer\Groups({"read", "accompanying_period_work:edit", "docgen:read"})
*/
private string $note = '';
/**
* @ORM\ManyToMany(targetEntity=Person::class)
* @ORM\JoinTable(name="chill_person_accompanying_period_work_person")
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
* @Serializer\Groups({"accompanying_period_work:create"})
*/
private Collection $persons;
/**
* @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorks")
* @ORM\JoinTable(name="chill_person_accompanying_period_work_result")
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*/
private Collection $results;
/**
* @ORM\ManyToOne(targetEntity=SocialAction::class)
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:create"})
*/
private ?SocialAction $socialAction = null;
/**
* @ORM\Column(type="date_immutable")
* @Serializer\Groups({"accompanying_period_work:create"})
* @Serializer\Groups({"accompanying_period_work:edit"})
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?DateTimeImmutable $startDate = null;
/**
* @ORM\ManyToMany(targetEntity=ThirdParty::class)
* @ORM\JoinTable(name="chill_person_accompanying_period_work_third_party")
*
* In schema : intervenants
* @Serializer\Groups({"read", "docgen:read"})
* @Serializer\Groups({"accompanying_period_work:edit"})
*/
private Collection $thirdParties;
/**
* @ORM\Column(type="datetime_immutable")
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?DateTimeImmutable $updatedAt = null;
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
* @Serializer\Groups({"read", "docgen:read"})
*/
private ?User $updatedBy = null;
public function __construct()
{
$this->goals = new ArrayCollection();
$this->results = new ArrayCollection();
$this->thirdParties = new ArrayCollection();
$this->persons = new ArrayCollection();
$this->accompanyingPeriodWorkEvaluations = new ArrayCollection();
}
public function addAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self
{
if (!$this->accompanyingPeriodWorkEvaluations->contains($evaluation)) {
$this->accompanyingPeriodWorkEvaluations[] = $evaluation;
$evaluation->setAccompanyingPeriodWork($this);
}
return $this;
}
public function addGoal(AccompanyingPeriodWorkGoal $goal): self
{
if (!$this->goals->contains($goal)) {
$this->goals[] = $goal;
$goal->setAccompanyingPeriodWork($this);
}
return $this;
}
public function addPerson(Person $person): self
{
if (!$this->persons->contains($person)) {
$this->persons[] = $person;
}
return $this;
}
public function addResult(Result $result): self
{
if (!$this->results->contains($result)) {
$this->results[] = $result;
}
return $this;
}
public function addThirdParty(ThirdParty $thirdParty): self
{
if (!$this->thirdParties->contains($thirdParty)) {
$this->thirdParties[] = $thirdParty;
}
return $this;
}
public function getAccompanyingPeriod(): ?AccompanyingPeriod
{
return $this->accompanyingPeriod;
}
/**
* @return Collection
*/
public function getAccompanyingPeriodWorkEvaluations()
{
return $this->accompanyingPeriodWorkEvaluations;
}
public function getCreatedAt(): ?DateTimeImmutable
{
return $this->createdAt;
}
public function getCreatedAutomatically(): ?bool
{
return $this->createdAutomatically;
}
public function getCreatedAutomaticallyReason(): ?string
{
return $this->createdAutomaticallyReason;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function getEndDate(): ?DateTimeInterface
{
return $this->endDate;
}
/**
* @return AccompanyingPeriodWorkGoal[]|Collection
*/
public function getGoals(): Collection
{
return $this->goals;
}
public function getHandlingThierParty(): ?ThirdParty
{
return $this->handlingThierParty;
}
public function getId(): ?int
{
return $this->id;
}
public function getNote(): ?string
{
return $this->note;
}
public function getPersons(): Collection
{
return $this->persons;
}
/**
* @return Collection|Result[]
*/
public function getResults(): Collection
{
return $this->results;
}
public function getSocialAction(): ?SocialAction
{
return $this->socialAction;
}
public function getSocialIssues(): Collection
{
return new ArrayCollection([$this->getSocialAction()->getIssue()]);
}
public function getStartDate(): ?DateTimeInterface
{
return $this->startDate;
}
/**
* @return Collection|ThirdParty[]
*/
public function getThirdParties(): Collection
{
return $this->thirdParties;
}
public function getThirdPartys(): Collection
{
return $this->getThirdParties();
}
public function getUpdatedAt(): ?DateTimeImmutable
{
return $this->updatedAt;
}
public function getUpdatedBy(): ?User
{
return $this->updatedBy;
}
public function removeAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self
{
$this->accompanyingPeriodWorkEvaluations
->removeElement($evaluation);
$evaluation->setAccompanyingPeriodWork(null);
return $this;
}
public function removeGoal(AccompanyingPeriodWorkGoal $goal): self
{
if ($this->goals->removeElement($goal)) {
// set the owning side to null (unless already changed)
if ($goal->getAccompanyingPeriodWork() === $this) {
$goal->setAccompanyingPeriodWork(null);
}
}
return $this;
}
public function removePerson(Person $person): self
{
$this->persons->removeElement($person);
return $this;
}
public function removeResult(Result $result): self
{
$this->results->removeElement($result);
return $this;
}
public function removeSocialIssue(SocialIssue $issue): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface
{
$this->getSocialIssues()->removeElement($issue);
return $this;
}
public function removeThirdParty(ThirdParty $thirdParty): self
{
$this->thirdParties->removeElement($thirdParty);
return $this;
}
/**
* Internal: you should use `$accompanyingPeriod->removeWork($work);` or
* `$accompanyingPeriod->addWork($work);`.
*/
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{
if ($this->accompanyingPeriod instanceof AccompanyingPeriod
&& $accompanyingPeriod !== $this->accompanyingPeriod) {
throw new LogicException('A work cannot change accompanyingPeriod');
}
$this->accompanyingPeriod = $accompanyingPeriod;
return $this;
}
public function setCreatedAt(DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
return $this;
}
public function setCreatedAutomatically(bool $createdAutomatically): self
{
$this->createdAutomatically = $createdAutomatically;
public function setEndDate(?DateTimeInterface $endDate = null): self
{
$this->endDate = $endDate;
return $this;
}
public function setCreatedAutomaticallyReason(string $createdAutomaticallyReason): self
{
$this->createdAutomaticallyReason = $createdAutomaticallyReason;
return $this;
}
return $this;
}
public function setHandlingThierParty(?ThirdParty $handlingThierParty): self
{
$this->handlingThierParty = $handlingThierParty;
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
return $this;
}
public function setNote(string $note): self
{
$this->note = $note;
public function setEndDate(?DateTimeInterface $endDate = null): self
{
$this->endDate = $endDate;
return $this;
}
return $this;
}
public function setSocialAction(?SocialAction $socialAction): self
{
$this->socialAction = $socialAction;
public function setHandlingThierParty(?ThirdParty $handlingThierParty): self
{
$this->handlingThierParty = $handlingThierParty;
return $this;
}
return $this;
}
public function setStartDate(DateTimeInterface $startDate): self
{
$this->startDate = $startDate;
public function setNote(string $note): self
{
$this->note = $note;
return $this;
}
return $this;
}
public function setUpdatedAt(DateTimeInterface $datetime): TrackUpdateInterface
{
$this->updatedAt = $datetime;
public function setSocialAction(?SocialAction $socialAction): self
{
$this->socialAction = $socialAction;
return $this;
}
return $this;
}
public function setUpdatedBy(User $user): TrackUpdateInterface
{
$this->updatedBy = $user;
public function setStartDate(DateTimeInterface $startDate): self
{
$this->startDate = $startDate;
return $this;
}
}
return $this;
}
public function setUpdatedAt(DateTimeInterface $datetime): TrackUpdateInterface
{
$this->updatedAt = $datetime;
return $this;
}
public function setUpdatedBy(User $user): TrackUpdateInterface
{
$this->updatedBy = $user;
return $this;
}
}

View File

@ -244,6 +244,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* @Assert\Date(
* groups={"general", "creation"}
* )
* @Assert\GreaterThan(propertyPath="birthDate")
* @Assert\LessThanOrEqual("today")
*/
private ?DateTimeImmutable $deathdate = null;
@ -1774,7 +1776,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
public function setNumberOfChildren(int $numberOfChildren): self
public function setNumberOfChildren(?int $numberOfChildren): self
{
$this->numberOfChildren = $numberOfChildren;

View File

@ -93,6 +93,7 @@ class PersonType extends AbstractType
])
->add('numberOfChildren', IntegerType::class, [
'required' => false,
'attr' => ['min' => 0],
]);
if ($this->configAltNamesHelper->hasAltNames()) {

View File

@ -162,6 +162,13 @@ div.activity-list {
}
/*
* Specific badge rounded-pill
*/
.badge {
&.bg-person {
//@extend .$chill-ll-gray;
background-color: $chill-ll-gray;
color: $chill-green;
}
}

View File

@ -22,9 +22,9 @@ const getUsers = () => {
};
const getReferrersSuggested = (course) => {
const url = `/api/1.0/person/accompanying-course/${course.id}/referrers-suggested.json`;
const url = `/api/1.0/person/accompanying-course/${course.id}/referrers-suggested.json`;
return fetchResults(url);
return fetchResults(url);
}
/*

View File

@ -48,7 +48,7 @@
</div>
<div v-if="suggestedPersons.length > 0">
<ul class="list-suggest add-items">
<ul class="list-suggest add-items inline">
<li v-for="p in suggestedPersons" :key="p.id" @click="addSuggestedPerson(p)">
<span>{{ p.text }}</span>
</li>

View File

@ -20,7 +20,7 @@
</VueMultiselect>
<template v-if="referrersSuggested.length > 0">
<ul class="list-suggest add-items">
<ul class="list-suggest add-items inline">
<li v-for="u in referrersSuggested" @click="updateReferrer(u)">
<span>
<user-render-box-badge :user="u"></user-render-box-badge>

View File

@ -134,7 +134,7 @@
</div>
<div v-if="accompanyingCourse.requestor === null && suggestedEntities.length > 0">
<ul class="list-suggest add-items">
<ul class="list-suggest add-items inline">
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
<span>{{ p.text }}</span>
</li>

View File

@ -20,7 +20,7 @@
</div>
<div v-if="suggestedEntities.length > 0">
<ul class="list-suggest add-items">
<ul class="list-suggest add-items inline">
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
<span>{{ p.text }}</span>
</li>

View File

@ -2,33 +2,81 @@
<person-render-box render="bloc"
v-if="resource.resource.type === 'person'"
:person="resource.resource"
:options="{ addInfo : true, addId : false, addEntity: true, addLink: false, addAltNames: true, addAge : false, hLevel : 3, isConfidential : true }"
>
:options="{
addInfo : true,
addId : false,
addEntity: true,
addLink: false,
addAltNames: true,
addAge : false,
hLevel : 3,
isConfidential : true
}">
<template v-slot:record-actions>
<ul class="record_actions">
<!--
<button-location v-if="hasCurrentHouseholdAddress" :person="resource.resource"></button-location>
-->
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="show"></on-the-fly></li>
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
<li><button class="btn btn-sm btn-remove" :title="$t('action.remove')" @click.prevent="$emit('remove', resource)"></button></li>
<li>
<on-the-fly
:type="resource.resource.type"
:id="resource.resource.id"
action="show">
</on-the-fly>
</li>
<li>
<on-the-fly
:type="resource.resource.type"
:id="resource.resource.id"
action="edit"
@saveFormOnTheFly="saveFormOnTheFly">
</on-the-fly>
</li>
<li>
<button
class="btn btn-sm btn-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)">
</button>
</li>
</ul>
</template>
</person-render-box>
<third-party-render-box
v-if="resource.resource.type === 'thirdparty'"
:thirdparty="resource.resource"
:options="{ addLink : false, addId : false, addEntity: true, addInfo: false, hLevel: 3 }"
>
:options="{
addLink : false,
addId : false,
addEntity: true,
addInfo: false,
//addComment: true,
hLevel: 3
}">
<template v-slot:record-actions>
<ul class="record_actions">
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="show"></on-the-fly></li>
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
<li><button class="btn btn-sm btn-remove" :title="$t('action.remove')" @click.prevent="$emit('remove', resource)"></button></li>
<li>
<on-the-fly
:type="resource.resource.type"
:id="resource.resource.id"
action="show">
</on-the-fly>
</li>
<li>
<on-the-fly
:type="resource.resource.type"
:id="resource.resource.id"
action="edit"
@saveFormOnTheFly="saveFormOnTheFly">
</on-the-fly>
</li>
<li>
<button
class="btn btn-sm btn-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)">
</button>
</li>
</ul>
</template>
</third-party-render-box>
</template>

View File

@ -132,6 +132,10 @@ 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"
},
action: {
choose_other_social_issue: "Veuillez choisir un autre problématique",
cancel: "Annuler",
},
// catch errors
'Error while updating AccompanyingPeriod Course.': "Erreur du serveur lors de la mise à jour du parcours d'accompagnement.",
'Error while retriving AccompanyingPeriod Course.': "Erreur du serveur lors du chargement du parcours d'accompagnement.",

View File

@ -5,24 +5,47 @@
<div id="awc_create_form">
<div id="picking">
<p>{{ $t('pick_social_issue_linked_with_action') }}</p>
<div v-for="si in socialIssues">
<input type="radio" v-bind:value="si.id" name="socialIssue" v-model="socialIssuePicked"><span class="badge bg-chill-l-gray text-dark">{{ si.text }}</span>
<div id="picking">
<p>{{ $t('pick_social_issue_linked_with_action') }}</p>
<div v-for="si in socialIssues">
<input type="radio" checked v-bind:value="si.id" name="socialIssue" v-model="socialIssuePicked"><span class="badge bg-chill-l-gray text-dark">{{ si.text }}</span>
</div>
<div class="my-3">
<div class="col-8">
<vue-multiselect
name="otherIssues"
label="text"
track-by="id"
open-direction="bottom"
:close-on-select="true"
:preserve-search="false"
:reset-after="true"
:hide-selected="true"
:taggable="false"
:multiple="false"
:searchable="true"
:allow-empty="true"
:show-labels="false"
:loading="issueIsLoading"
:placeholder="$t('action.choose_other_social_issue')"
:options="socialIssuesOther"
@select="addIssueInList">
</vue-multiselect>
</div>
</div>
<div v-if="hasSocialIssuePicked">
<h2>{{ $t('pick_an_action') }}</h2>
<vue-multiselect
v-model="socialActionPicked"
label="text"
:options="socialActionsReachables"
:searchable="true"
:close-on-select="true"
:show-labels="true"
track-by="id"
></vue-multiselect>
<div class="col-8">
<vue-multiselect
v-model="socialActionPicked"
label="text"
:options="socialActionsReachables"
:searchable="true"
:close-on-select="true"
:show-labels="true"
track-by="id"
></vue-multiselect>
</div>
</div>
<div v-if="isLoadingSocialActions">
@ -63,9 +86,9 @@
<div>
<ul class="record_actions">
<li class="cancel">
<a href="#" class="btn btn-cancel">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t('action.cancel') }}
</a>
</button>
</li>
<li v-if="hasSocialActionPicked">
<button class="btn btn-save" v-show="!isPostingWork" @click="submit">
@ -82,43 +105,7 @@
</template>
<style lang="scss">
#awc_create_form {
display: grid;
grid-template-areas:
"picking picking"
"start_date end_date"
"confirm confirm"
;
grid-template-columns: 50% 50%;
column-gap: 1.5rem;
#picking {
grid-area: picking;
#persons {
ul {
padding: 0;
list-style-type: none;
}
}
}
#start_date {
grid-area: start_date;
}
#end_date {
grid-area: end_date;
}
#confirm {
grid-area: confirm;
}
}
</style>
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
@ -145,17 +132,38 @@ export default {
name: 'App',
components: {
VueMultiselect,
PersonRenderBox,
PersonRenderBox,
},
methods: {
submit() {
this.$store.dispatch('submit');
}
this.$store.dispatch('submit')
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
},
addIssueInList(value) {
this.$store.commit('addIssueInList', value);
this.$store.commit('removeIssueInOther', value);
this.$store.dispatch('pickSocialIssue', value.id);
},
goToPrevious() {
let params = new URLSearchParams(window.location.search);
if (params.has('returnPath')) {
window.location.replace(params.get('returnPath'));
} else {
return;
}
},
},
i18n,
computed: {
...mapState([
'socialIssues',
'socialIssuesOther',
'socialActionsReachables',
'errors',
'personsReachables',
@ -170,12 +178,12 @@ export default {
personsPicked: {
get() {
let s = this.$store.state.personsPicked.map(p => p.id);
console.log('persons picked', s);
// console.log('persons picked', s);
return s;
},
set(v) {
console.log('persons picked', v);
// console.log('persons picked', v);
this.$store.commit('setPersonsPickedIds', v);
}
},
@ -228,10 +236,48 @@ export default {
@import 'ChillPersonAssets/chill/scss/mixins';
@import 'ChillMainAssets/chill/scss/chill_variables';
span.badge {
@include badge_social($social-issue-color);
font-size: 95%;
margin-bottom: 5px;
margin-right: 1em;
margin-left: 1em;
@include badge_social($social-issue-color);
font-size: 95%;
margin-bottom: 5px;
margin-right: 1em;
margin-left: 1em;
}
</style>
<style lang="scss">
#awc_create_form {
display: grid;
grid-template-areas:
"picking picking"
"start_date end_date"
"confirm confirm"
;
grid-template-columns: 50% 50%;
column-gap: 1.5rem;
#picking {
grid-area: picking;
#persons {
ul {
padding: 0;
list-style-type: none;
}
}
}
#start_date {
grid-area: start_date;
}
#end_date {
grid-area: end_date;
}
#confirm {
grid-area: confirm;
}
}
</style>

View File

@ -2,7 +2,8 @@
import { createStore } from 'vuex';
import { datetimeToISO } from 'ChillMainAssets/chill/js/date.js';
import { findSocialActionsBySocialIssue } from 'ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js';
import { create } from 'ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js';
// import { create } from 'ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js';
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
const debug = process.env.NODE_ENV !== 'production';
@ -12,6 +13,7 @@ const store = createStore({
accompanyingCourse: window.accompanyingCourse,
socialIssues: window.accompanyingCourse.socialIssues,
socialIssuePicked: null,
socialIssuesOther: [],
socialActionsReachables: [],
socialActionPicked: null,
personsPicked: window.accompanyingCourse.participations.filter(p => p.endDate == null)
@ -26,7 +28,6 @@ const store = createStore({
},
getters: {
hasSocialActionPicked(state) {
console.log(state.socialActionPicked);
return null !== state.socialActionPicked;
},
hasSocialIssuePicked(state) {
@ -73,27 +74,43 @@ const store = createStore({
},
mutations: {
setSocialActionsReachables(state, actions) {
console.log('set social action reachables');
console.log(actions);
// console.log('set social action reachables');
// console.log(actions);
state.socialActionsReachables = actions;
},
setSocialAction(state, socialAction) {
console.log('socialAction', socialAction);
// console.log('socialAction', socialAction);
state.socialActionPicked = socialAction;
},
setSocialIssue(state, socialIssueId) {
console.log('set social issue', socialIssueId);
// console.log('set social issue', socialIssueId);
if (socialIssueId === null) {
state.socialIssuePicked = null;
} else {
let mapped = state.socialIssues
.find(e => e.id === socialIssueId);
console.log('mapped', mapped);
state.socialIssuePicked = mapped;
console.log('social issue setted', state.socialIssuePicked);
// console.log('social issue setted', state.socialIssuePicked);
}
},
addIssueInList(state, issue) {
//console.log('add issue list', issue.id);
state.socialIssues.push(issue);
},
updateIssuesOther(state, payload) {
//console.log('update issues other');
state.socialIssuesOther = payload;
},
removeIssueInOther(state, issue) {
//console.log('remove issue other', issue.id);
state.socialIssuesOther = state.socialIssuesOther.filter(
(i) => i.id !== issue.id
);
},
updateSelected(state, payload) {
state.socialIssueSelected = payload;
},
setIsLoadingSocialActions(state, s) {
state.isLoadingSocialActions = s;
},
@ -131,8 +148,6 @@ const store = createStore({
findSocialActionsBySocialIssue(socialIssueId).then(
(response) => {
console.log(response);
console.log(response.results);
commit('setSocialIssue', socialIssueId);
commit('setSocialActionsReachables', response.results);
commit('setIsLoadingSocialActions', false);
@ -142,34 +157,34 @@ const store = createStore({
});
},
submit({ commit, getters, state }) {
console.log('submit');
let
payload = getters.buildPayloadCreate,
errors = [];
let payload = getters.buildPayloadCreate;
const url = `/api/1.0/person/accompanying-course/${state.accompanyingCourse.id}/work.json`;
commit('setPostingWork');
create(state.accompanyingCourse.id, payload)
.then( ({status, data}) => {
console.log('created return', { status, data});
if (status === 200) {
console.log('created, nothing to do here any more. Bye-bye!');
window.location.assign(`/fr/person/accompanying-period/work/${data.id}/edit`);
} else if (status === 422) {
console.log(data);
for (let i in data.violations) {
console.log(i);
console.log(data.violations[i].title);
errors.push(data.violations[i].title);
}
console.log('errors after reseponse handling', errors);
console.log({errors, cancel_posting: true});
commit('addErrors', { errors, cancel_posting: true });
}
makeFetch('POST', url, payload)
.then((response) => {
window.location.assign(`/fr/person/accompanying-period/work/${response.id}/edit`)
})
.catch((error) => {
throw error;
});
},
fetchOtherSocialIssues({commit}) {
const url = `/api/1.0/person/social-work/social-issue.json`;
return makeFetch('GET', url)
.then((response) => {
commit('updateIssuesOther', response.results);
})
.catch((error) => {
throw error;
})
}
},
});
store.dispatch('fetchOtherSocialIssues');
export { store };

View File

@ -15,7 +15,12 @@
<confirmation v-if="step === 'confirm'"></confirmation>
<ul class="record_actions sticky-form-buttons">
<li class="cancel" v-if="step !== 'concerned' || hasReturnPath">
<li class="cancel" v-if="step !== 'concerned'">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t('household_members_editor.app.previous') }}
</button>
</li>
<li class="cancel" v-else-if="hasReturnPath">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t('household_members_editor.app.cancel') }}
</button>

View File

@ -1,5 +1,5 @@
<template>
<div class="flex-table" v-if="hasHousehold">
<div class="flex-table mb-5" v-if="hasHousehold">
<div class="item-bloc">
<household-render-box :household="fakeHouseholdWithConcerned"></household-render-box>
</div>

View File

@ -51,6 +51,7 @@ const appMessages = {
},
app: {
next: 'Suivant',
previous: 'Précédent',
cancel: 'Annuler',
save: 'Enregistrer',
steps: {

View File

@ -1,30 +1,30 @@
const create = (accompanying_period_id, payload) => {
const url = `/api/1.0/person/accompanying-course/${accompanying_period_id}/work.json`;
let status;
console.log('create', payload);
// const create = (accompanying_period_id, payload) => {
// const url = `/api/1.0/person/accompanying-course/${accompanying_period_id}/work.json`;
// let status;
// console.log('create', payload);
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.then(response => {
if (response.ok || response.status === 422) {
status = response.status;
// return fetch(url, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify(payload),
// })
// .then(response => {
// if (response.ok || response.status === 422) {
// status = response.status;
return response.json();
}
// return response.json();
// }
throw new Error("Error while retrieving social actions: " + response.status +
" " + response.statusText);
})
.then(data => {
return new Promise((resolve, reject) => {
resolve({ status, data });
});
});
};
// throw new Error("Error while retrieving social actions: " + response.status +
// " " + response.statusText);
// })
// .then(data => {
// return new Promise((resolve, reject) => {
// resolve({ status, data });
// });
// });
// };
export { create };
// export { create };

View File

@ -1,21 +1,22 @@
<template>
<div class="list-item" :class="{ checked: isChecked }">
<label>
<div>
<input
v-bind:type="type"
<input
v-bind:type="type"
v-model="selected"
name="item"
v-bind:id="item"
v-bind:value="setValueByType(item, type)" />
</div>
<suggestion-person
<suggestion-person
v-if="item.result.type === 'person'"
v-bind:item="item">
</suggestion-person>
<suggestion-third-party
<suggestion-third-party
v-if="item.result.type === 'thirdparty'"
v-bind:item="item">
</suggestion-third-party>
@ -24,6 +25,7 @@
v-if="item.result.type === 'user'"
v-bind:item="item">
</suggestion-user>
</label>
</div>
</template>
@ -41,7 +43,7 @@ export default {
SuggestionUser,
},
props: [
'item',
'item',
'search',
'type'
],
@ -69,7 +71,7 @@ export default {
</script>
<style lang="scss">
div.results {
div.results {
div.list-item {
padding: 0.4em 0.8em;
display: flex;
@ -78,32 +80,36 @@ export default {
background-color: #ececec;
border-bottom: 1px dotted #8b8b8b;
}
div.container {
& > input {
margin-right: 0.8em;
label {
display: inline-flex;
width: 100%;
div.container {
& > input {
margin-right: 0.8em;
}
span:not(.name) {
margin-left: 0.5em;
opacity: 0.5;
font-size: 90%;
font-style: italic;
}
}
span:not(.name) {
margin-left: 0.5em;
opacity: 0.5;
font-size: 90%;
font-style: italic;
div.right_actions {
margin: 0 0 0 auto;
display: flex;
align-items: flex-end;
& > * {
margin-left: 0.5em;
align-self: baseline;
}
a.btn {
border: 1px solid lightgrey;
font-size: 70%;
padding: 4px;
}
}
}
div.right_actions {
margin: 0 0 0 auto;
display: flex;
align-items: flex-end;
& > * {
margin-left: 0.5em;
align-self: baseline;
}
a.btn {
border: 1px solid lightgrey;
font-size: 70%;
padding: 4px;
}
}
}
}
</style>

View File

@ -1,6 +1,5 @@
<template>
<div class="container">
<span class="name">
{{ item.result.text }}
</span>
@ -8,32 +7,33 @@
{{ $d(item.result.birthdate.datetime, 'short') }}
</span>
<span class="location" v-if="hasAddress">
{{ item.result.current_household_address.text }} -
{{ item.result.current_household_address.text }} -
{{ item.result.current_household_address.postcode.name }}
</span>
</div>
<div class="right_actions">
<span class="badge rounded-pill bg-secondary" :title="item.key">
{{ $t('item.type_person') }}
</span>
<badge-entity
:entity="item.result"
:options="{ displayLong: true }">
</badge-entity>
<on-the-fly
type="person"
v-bind:id="item.result.id"
action="show">
</on-the-fly>
</div>
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
export default {
name: 'SuggestionPerson',
components: {
OnTheFly,
BadgeEntity
},
props: ['item'],
computed: {

View File

@ -17,33 +17,23 @@
</span>
</div>
</div>
<div class="right_actions">
<span class="badge bg-thirdparty-child" v-if="item.result.kind == 'child'">
{{ $t('thirdparty.child')}}
</span>
<span class="badge bg-thirdparty-company" v-else-if="item.result.kind == 'company'">
{{ $t('thirdparty.company')}}
</span>
<span class="badge bg-thirdparty-contact" v-else="item.result.kind == 'contact'">
{{ $t('thirdparty.contact')}}
</span>
<span class="badge rounded-pill bg-secondary" :title="item.key">
{{ $t('item.type_thirdparty') }}
</span>
<on-the-fly
type="thirdparty"
v-bind:id="item.result.id"
action="show">
</on-the-fly>
<badge-entity
:entity="item.result"
:options="{ displayLong: true }">
</badge-entity>
<on-the-fly
type="thirdparty"
v-bind:id="item.result.id"
action="show">
</on-the-fly>
</div>
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
const i18n = {
messages: {
@ -60,7 +50,8 @@ const i18n = {
export default {
name: 'SuggestionThirdParty',
components: {
OnTheFly
OnTheFly,
BadgeEntity
},
props: ['item'],
i18n,

View File

@ -18,12 +18,17 @@
<span class="firstname">{{ person.firstName }}</span>
<span class="lastname">{{ person.lastName }}</span>
<span v-if="person.deathdate" class="deathdate"> ()</span>
<span v-if="person.altNames && options.addAltNames == true" class="altnames">
<span :class="'altname altname-' + altNameKey">{{ altNameLabel }}</span>
</span>
<span v-if="options.addId == true" class="id-number" :title="'n° ' + person.id">{{ person.id }}</span>
<span v-if="options.addEntity == true" class="badge rounded-pill bg-secondary">{{ $t('renderbox.person') }}</span>
<badge-entity v-if="options.addEntity === true"
:entity="person"
:options="{ displayLong: options.entityDisplayLong }">
</badge-entity>
</div>
@ -139,12 +144,14 @@
import {dateToISO} from 'ChillMainAssets/chill/js/date.js';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
export default {
name: "PersonRenderBox",
components: {
AddressRenderBox,
Confidential
Confidential,
BadgeEntity
},
props: ['person', 'options', 'render', 'returnPath'],
computed: {

View File

@ -10,6 +10,7 @@
* addAge bool
* addCenter bool
* hLevel integer
* addDeath bool
* address_multiline bool
* customButtons [
'before' Twig\Markup, (injected with macro)
@ -24,7 +25,12 @@
{% macro raw(person, options) %}
<span class="firstname">{{ person.firstName }}</span>
<span class="lastname">{{ person.lastName }}</span>
<span class="lastname">
{{ person.lastName }}
{%- if options['addDeath'] -%}
{% if person.deathdate is not null %} (‡){% endif %}
{% endif %}
</span>
{%- if options['addAltNames'] -%}
<span class="altnames">
{%- for n in person.altNames -%}
@ -82,21 +88,17 @@
{{ 'Date of death'|trans }}:
{%- endif -%}
{#- must be on one line to avoid spaces with dash -#}
<time datetime="{{ person.deathdate|date('Y-m-d') }}" title="{{ 'Deathdate'|trans }}">{{ person.deathdate|format_date("medium") }}</time>
{% if options['addAge'] %}
<span class="age">
({{ 'years_old'|trans({ 'age': person.age }) }})
</span>
{% endif %}
<time datetime="{{ person.deathdate|date('Y-m-d') }}" title="{{ 'deathdate'|trans }}">{{ person.deathdate|format_date("medium") }}</time>
{%- if options['addAge'] -%}
<span class="age">{{ 'years_old'|trans({ 'age': person.age }) }}</span>
{%- endif -%}
{%- elseif person.birthdate is not null -%}
<time datetime="{{ person.birthdate|date('Y-m-d') }}" title="{{ 'Birthdate'|trans }}">
{{ 'Born the date'|trans({'gender': person.gender,
'birthdate': person.birthdate|format_date("medium") }) }}
</time>
{%- if options['addAge'] -%}
<span class="age">
{{- 'years_old'|trans({ 'age': person.age }) -}}
</span>
<span class="age">{{- 'years_old'|trans({ 'age': person.age }) -}}</span>
{%- endif -%}
{%- endif -%}
</p>

View File

@ -4,7 +4,7 @@
{% block title 'household.Edit household members'|trans %}
{% block content %}
<div class="household-members">
<div class="col-md-10 col-xxl household-members">
<h1>{{ block('title') }}</h1>
<div id="household_members_editor"></div>

View File

@ -83,7 +83,7 @@
<ul class="record_actions sticky-form-buttons">
<li class="dropdown">
<a class="btn btn-create dropdown-toggle"
href="#" role="button" id="newPersonMore" data-bs-toggle="dropdown" aria-expanded="false">
href="#" role="button" id="newPersonMore" data-bs-toggle="dropdown" aria-expanded="false">
{{ 'Add the person'|trans }}
</a>
<ul class="dropdown-menu" aria-labelledby="newPersonMore">
@ -93,10 +93,7 @@
<li>
{{ form_widget(form.createPeriod, { 'attr': { 'class': 'dropdown-item' }}) }}
</li>
<li>
{{ form_widget(form.createHousehold, { 'attr': { 'class': 'dropdown-item' }}) }}
</li>
</ul>
</ul>
</li>
</ul>
@ -106,5 +103,5 @@
{% endblock content %}
{% block js %}
{{ encore_entry_script_tags('mod_disablebuttons') }}
{# {{ encore_entry_script_tags('mod_disablebuttons') }} #}
{% endblock js %}

View File

@ -92,6 +92,13 @@ This view should receive those arguments:
{%- endif -%}
</dd>
{%- if chill_person.fields.deathdate == 'visible' -%}
{%- if person.deathdate is not null -%}
<dt>{{ 'Date of death'|trans }}&nbsp;:</dt>
<dd>{{ person.deathdate|format_date('long') }}</dd>
{%- endif -%}
{%- endif -%}
{%- if chill_person.fields.place_of_birth == 'visible' -%}
<dt>{{ 'Place of birth'|trans }}&nbsp;:</dt>
{% if person.placeOfBirth is not empty %}
@ -111,6 +118,7 @@ This view should receive those arguments:
{% endif %}
{% endapply %}</dd>
{%- endif -%}
</dl>
</figure>
</div>
@ -159,12 +167,27 @@ This view should receive those arguments:
</dd>
</dl>
{%- endif -%}
{%- if chill_person.fields.number_of_children == 'visible' -%}
<dl>
<dt>{{'Number of children'|trans}}&nbsp;:</dt>
<dd>
{% if person.numberOfChildren is not null %}
{{ person.numberOfChildren }}
{% else %}
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
{% endif %}
</dd>
</dl>
{%- endif -%}
{%- if chill_person.fields.marital_status == 'visible' -%}
<dl>
<dt>{{'Marital status'|trans}}&nbsp;:</dt>
<dd>
{% if person.maritalStatus is not null %}
{{ person.maritalStatus.name|localize_translatable_string }}
{% if person.maritalStatusDate is not null %}
{{ 'person.from_the'|trans }} {{ person.maritalStatusDate|format_date('long') }}
{% endif %}
{% else %}
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
{% endif %}
@ -217,6 +240,7 @@ This view should receive those arguments:
<dl>
<dt>{{ 'Mobilenumber'|trans }}&nbsp;:</dt>
<dd>{% if person.mobilenumber is not empty %}<a href="tel:{{ person.mobilenumber }}">{{ person.mobilenumber|chill_format_phonenumber }}</a>{% else %}<span class="chill-no-data-statement">{{ 'No data given'|trans }}{% endif %}</dd>
<p>{% if person.acceptSMS %}{{ 'Accept short text message'|trans }}{% endif %}</p>
</dl>
{% endif %}

View File

@ -51,6 +51,7 @@ class PersonRender extends AbstractChillEntityRender
'hLevel' => $options['hLevel'] ?? 3,
'customButtons' => $options['customButtons'] ?? [],
'customArea' => $options['customArea'] ?? [],
'addDeath' => $options['addDeath'] ?? true,
];
return

View File

@ -0,0 +1,14 @@
services:
accompanying_period_social_issue_consistency_with_action:
class: 'Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodSocialIssueConsistencyEntityListener'
tags:
-
name: 'doctrine.orm.entity_listener'
event: 'prePersist'
entity: 'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'
lazy: true
-
name: 'doctrine.orm.entity_listener'
event: 'preUpdate'
entity: 'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'
lazy: true

View File

@ -19,6 +19,7 @@ person:
woman {et elle-même}
other {et lui·elle-même}
}
from_the: depuis le
household:
Household: Ménage

View File

@ -124,8 +124,8 @@ 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 ET créer une période d'accompagnement"
'Add the person and create an household': "Créer la personne ET créer un ménage"
'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"
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'

View File

@ -128,6 +128,7 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
/**
* @ORM\Column(name="comment", type="text", nullable=true)
* @Groups({"read"})
*/
private ?string $comment = null;

View File

@ -1,16 +1,23 @@
@import 'ChillMainAssets/module/bootstrap/shared';
.badge {
&.bg-thirdparty-company {
//@extend .bg-info;
background-color: $yellow;
}
&.bg-thirdparty-child {
//@extend .bg-chill-blue;
background-color: $chill-blue;
}
&.bg-thirdparty-contact {
//@extedn .bg-secondary;
background-color: $secondary;
/// Specific badge rounded-pill
.badge.rounded-pill {
&.bg-thirdparty {
//@extend .$chill-ll-gray;
background-color: $chill-ll-gray;
color: $chill-pink;
}
}
/// force first column width in list
div.thirdparty-list {
div.flex-table {
div.item-bloc {
div.item-row {
div.item-col:first-child {
flex-basis: 25%;
}
}
}
}
}

View File

@ -7,30 +7,19 @@
<div class="entity-label">
<div :class="'denomination h' + options.hLevel">
<a v-if="this.options.addLink === true" href="#">
<a v-if="this.options.addLink === true" href="#">
<span class="name">{{ thirdparty.text }}</span>
</a>
<span class="name">{{ thirdparty.text }}</span>
<span class="name" v-else>{{ thirdparty.text }}</span>
<span class="badge bg-thirdparty-child" v-if="thirdparty.kind == 'child'">
{{ $t('thirdparty.child')}}
</span>
<span class="badge bg-thirdparty-company" v-else-if="thirdparty.kind == 'company'">
{{ $t('thirdparty.company')}}
</span>
<span class="badge bg-thirdparty-contact" v-else>
{{ $t('thirdparty.contact')}}
<span v-if="options.addId === true" class="id-number" :title="'n° ' + thirdparty.id">
{{ thirdparty.id }}
</span>
<span v-if="options.addId == true" class="id-number" :title="'n° ' + thirdparty.id">{{ thirdparty.id }}</span>
<span v-if="options.addEntity == true && thirdparty.type === 'thirdparty'" class="badge rounded-pill bg-secondary">{{ $t('renderbox.type.thirdparty') }}</span>
</div>
<div v-if="hasParent">
<span class="name tparty-parent">
> {{ thirdparty.parent.text }}
</span>
<badge-entity v-if="options.addEntity === true"
:entity="thirdparty"
:options="{ displayLong: options.entityDisplayLong }">
</badge-entity>
</div>
<p v-if="this.options.addInfo === true" class="moreinfo">
@ -38,13 +27,38 @@
</div>
</div>
<div class="item-col">
<div class="float-button bottom">
<div class="box">
<div class="action">
<slot name="record-actions"></slot>
</div>
<ul class="list-content fa-ul">
<li v-if="hasParent">
<i class="fa fa-li fa-hand-o-right"></i>
<b class="me-2">{{ $t('child_of') }}</b>
<span class="chill-entity badge-thirdparty">{{ thirdparty.parent.text }}</span>
<!-- console: [Vue warn]: Failed to resolve component: on-the-fly ...
<on-the-fly type="thirdparty" action="show" :id="thirdparty.parent.id"
:buttonText="thirdparty.parent.text" :displayBadge="'true' === 'true'"
></on-the-fly>
-->
</li>
<!-- TODO hasChildren
<li v-if="hasChildren">
<i class="fa fa-li fa-hand-o-right"></i>
<b class="me-2">{{ $t('children') }}</b>
<span v-for="child in thirdparty.activeChildren">
<on-the-fly type="thirdparty"
action="show"
:id="child.id"
:buttonText="child.text"
displayBadge="'true' === 'true'">
</on-the-fly>
</span>
</li>
-->
</ul>
<confidential v-if="thirdparty.contactDataAnonymous">
<template v-slot:confidential-content>
<ul class="list-content fa-ul">
@ -62,21 +76,24 @@
</li>
</ul>
</template>
</confidential>
<ul v-else class="list-content fa-ul">
<li v-if="thirdparty.address">
<i class="fa fa-li fa-map-marker"></i>
<address-render-box :address="thirdparty.address" :isMultiline="isMultiline"></address-render-box>
</li>
<li v-if="thirdparty.phonenumber">
<i class="fa fa-li fa-mobile"></i>
<a :href="'tel: ' + thirdparty.phonenumber">{{ thirdparty.phonenumber }}</a>
</li>
<li v-if="thirdparty.email">
<i class="fa fa-li fa-envelope-o"></i>
<a :href="'mailto: ' + thirdparty.email">{{ thirdparty.email }}</a>
</li>
</ul>
</confidential>
<ul v-else class="list-content fa-ul">
<li v-if="thirdparty.address">
<i class="fa fa-li fa-map-marker"></i>
<address-render-box :address="thirdparty.address" :isMultiline="isMultiline"></address-render-box>
</li>
<li v-if="thirdparty.phonenumber">
<i class="fa fa-li fa-mobile"></i>
<a :href="'tel: ' + thirdparty.phonenumber">{{ thirdparty.phonenumber }}</a>
</li>
<li v-if="thirdparty.email">
<i class="fa fa-li fa-envelope-o"></i>
<a :href="'mailto: ' + thirdparty.email">{{ thirdparty.email }}</a>
</li>
</ul>
<div v-if="options.addComment && !thirdparty.contactDataAnonymous && thirdparty.comment">
<blockquote class="chill-user-quote">{{ thirdparty.comment }}</blockquote>
</div>
</div>
</div>
</div>
@ -91,25 +108,24 @@
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
import {dateToISO} from 'ChillMainAssets/chill/js/date.js';
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
const i18n = {
messages: {
fr: {
tparty: {
contact: "Personne physique",
company: "Personne morale"
}
}
}
};
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
//import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
export default {
name: "ThirdPartyRenderBox",
components: {
AddressRenderBox,
Confidential
Confidential,
BadgeEntity,
//OnTheFly
},
i18n: {
messages: {
fr: {
children: "Personnes de contact: ",
child_of: "Contact de: ",
}}
},
i18n,
props: ['thirdparty', 'options'],
computed: {
isMultiline: function() {
@ -120,8 +136,13 @@ export default {
}
},
hasParent() {
return !(this.$props.thirdparty.parent === null || this.$props.thirdparty.parent === undefined);
}
return !(this.thirdparty.parent === null || this.thirdparty.parent === undefined);
},
/* TODO need backend normalizer to serve children without circular reference
hasChildren() {
//console.log(this.thirdparty.activeChildren.length > 0)
return false
} */
}
}
</script>

View File

@ -5,7 +5,8 @@
:thirdparty="thirdparty"
:options="{
addInfo: true,
addEntity: false,
addEntity: true,
entityDisplayLong: true,
addAltNames: true,
addId: true,
addLink: false,
@ -13,6 +14,7 @@
hLevel: 3,
addCenter: true,
addNoData: true,
addComment: true,
isMultiline: true
}"
></third-party-render-box>
@ -24,7 +26,7 @@
<div class="form-check">
<input class="form-check-input mt-0" type="radio" v-model="kind" value="company" id="tpartyKindInstitution">
<label for="tpartyKindInstitution" class="required">
<span class="badge bg-thirdparty-company" style="padding-top: 0;">
<span class="badge rounded-pill bg-thirdparty-company" style="padding-top: 0;">
{{ $t('tparty.company')}}
</span>
</label>
@ -32,7 +34,7 @@
<div class="form-check">
<input class="form-check-input mt-0" type="radio" v-model="kind" value="contact" id="tpartyKindContact">
<label for="tpartyKindContact" class="required">
<span class="badge bg-thirdparty-contact" style="padding-top: 0;">
<span class="badge rounded-pill bg-thirdparty-contact" style="padding-top: 0;">
{{ $t('tparty.contact')}}
</span>
</label>

View File

@ -82,7 +82,19 @@
<div class="item-row entity-bloc">
<div class="item-col">
{{ _self.label(thirdparty, options) }}
<span class="badge bg-thirdparty-{{ thirdparty.kind }}">{{ ('thirdparty.' ~ thirdparty.kind)|trans }}</span>
{% if thirdparty.kind == 'child' %}
<span class="badge rounded-pill bg-thirdparty">
<i class="fa fa-fw fa-user"></i>{{ 'thirdparty.child'|trans }}
</span>
{% elseif thirdparty.kind == 'company' %}
<span class="badge rounded-pill bg-thirdparty">
<i class="fa fa-fw fa-hospital-o"></i>{{ 'thirdparty.company'|trans }}
</span>
{% else %}
<span class="badge rounded-pill bg-thirdparty">
<i class="fa fa-fw fa-user-md"></i>{{ 'thirdparty.contact'|trans }}
</span>
{% endif %}
</div>
<div class="item-col">
{% if options['isConfidential'] %}
@ -160,26 +172,33 @@
</div>
{% if options['showContacts'] and thirdparty.activeChildren|length > 0 %}
<div class="item-row">
{{ 'thirdparty.Children'|trans }}&nbsp;:
{% for c in thirdparty.activeChildren %}
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
targetEntity: { name: 'thirdparty', id: c.id },
action: 'show',
displayBadge: true,
buttonText: c|chill_entity_render_string
} %}
{% endfor %}
<div class="item-col"></div>
<div class="item-col">
<h5 class="me-2">{{ 'thirdparty.Children'|trans ~ ': ' }}</h5>
{% for c in thirdparty.activeChildren %}
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
targetEntity: { name: 'thirdparty', id: c.id },
action: 'show',
displayBadge: true,
buttonText: c|chill_entity_render_string
} %}
{% endfor %}
</div>
</div>
{% endif %}
{% if options['showParent'] and thirdparty.isChild %}
<div class="item-row">
{{ 'thirdparty.Contact of'|trans }}&nbsp;:
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
targetEntity: { name: 'thirdparty', id: thirdparty.parent.id },
action: 'show',
displayBadge: true,
buttonText: thirdparty.parent|chill_entity_render_string
} %}
<div class="item-col"></div>
<div class="item-col">
<h5 class="me-2">{{ 'thirdparty.Contact of'|trans ~ ': ' }}</h5>
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
targetEntity: { name: 'thirdparty', id: thirdparty.parent.id },
action: 'show',
displayBadge: true,
buttonText: thirdparty.parent|chill_entity_render_string
} %}
</div>
</div>
{% endif %}

View File

@ -6,6 +6,26 @@
{% block content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% macro rowCustomButtons(tp) %}
{% if is_granted('CHILL_3PARTY_3PARTY_UPDATE', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_3party_3party_edit',
{ 'id': (tp.isParent ? tp.id : tp.parent.id) }) }}"
title="{{ 'Edit'|trans }}"
class="btn btn-sm btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_3PARTY_3PARTY_SHOW', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_3party_3party_view',
{ 'id': (tp.isParent ? tp.id : tp.parent.id) }) }}"
title="{{ 'Show'|trans }}"
class="btn btn-sm btn-show"></a>
</li>
{% endif %}
{% endmacro %}
{% block index_header %}
<h1>{{ 'List of third parties'|trans }}</h1>
{% endblock %}
@ -13,37 +33,25 @@
{% block table_entities %}
<div class="thirdparty-list my-5">
<div class="row justify-content-center">
<div>
<label class="counter">
<span>{{ paginator.totalItems }}</span> {{ 'third parties'|trans }}
</label>
<label class="counter text-end">
<span>{{ paginator.totalItems }}</span> {{ 'third parties'|trans }}
</label>
<div class="flex-table">
{% for tp in third_parties %}
<div class="item-bloc">
{{ tp|chill_entity_render_box({'render': 'bloc', 'addLink': false, 'showContacts': true, 'isConfidential': (tp.contactDataAnonymous ? true : false) }) }}
<div class="item-row separator">
<ul class="record_actions">
{% if is_granted('CHILL_3PARTY_3PARTY_UPDATE', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_3party_3party_edit',
{ 'id': (tp.isParent ? tp.id : tp.parent.id) }) }}" class="btn btn-sm btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_3PARTY_3PARTY_SHOW', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_3party_3party_view',
{ 'id': (tp.isParent ? tp.id : tp.parent.id) }) }}" class="btn btn-sm btn-show"></a>
</li>
{% endif %}
</ul>
</div>
</div>
{% endfor %}
</div>
<div class="flex-table">
{% for tp in third_parties %}
<div class="item-bloc">
{{ tp|chill_entity_render_box({
'render': 'bloc',
'showContacts': true,
'addLink': true,
'customButtons': { 'replace': _self.rowCustomButtons(tp) },
'isConfidential': (tp.contactDataAnonymous ? true : false)
}) }}
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}

View File

@ -12,10 +12,10 @@
{% block crud_content_header %}
<h1>
{{ title_ }}
<span class="badge bg-{{ thirdParty.active ? 'success' : 'danger' }}"
<span class="badge bg-{{ thirdParty.active ? 'success' : 'danger' }} float-end"
title="{{ (thirdParty.active ? 'shown to users' : 'not shown to users')|trans }}">
{{ (thirdParty.active ? 'Active' : 'Inactive')|trans }}
</span>
{{ (thirdParty.active ? 'Active' : 'Inactive')|trans }}
</span>
</h1>
{% endblock %}

View File

@ -45,6 +45,7 @@ class ThirdPartyNormalizer implements NormalizerAwareInterface, NormalizerInterf
'parent' => $this->normalizer->normalize($thirdParty->getParent(), $format, $context),
'civility' => $this->normalizer->normalize($thirdParty->getCivility(), $format, $context),
'contactDataAnonymous' => $thirdParty->isContactDataAnonymous(),
'comment' => $thirdParty->getComment(),
];
}