Merge branch '323-related-entity-permission-give-from-workflow' into signature-app-master

This commit is contained in:
2024-11-13 22:44:29 +01:00
86 changed files with 1444 additions and 446 deletions

View File

@@ -201,7 +201,7 @@ class PersonMove
private function getDeleteEntities(): array
{
return [
AccompanyingPeriod\AccompanyingPeriodWork::class,
// AccompanyingPeriod\AccompanyingPeriodWork::class,
Relationship::class,
];
}
@@ -216,7 +216,7 @@ class PersonMove
}
/**
* get the full table name with schema if it does exists.
* get the full table name with schema if it exists.
*/
private function getTableName(ClassMetadata $metadata): string
{

View File

@@ -15,11 +15,14 @@ use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\PostalCode;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\CenterRepository;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Repository\GenderRepository;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Repository\UserRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
@@ -77,12 +80,15 @@ class LoadPeople extends AbstractFixture implements ContainerAwareInterface, Ord
*/
protected array $cacheUsers = [];
/**
* @var array|Gender[]
*/
protected array $cacheGenders = [];
protected Generator $faker;
protected NativeLoader $loader;
private array $genders = [Person::MALE_GENDER, Person::FEMALE_GENDER, Person::BOTH_GENDER];
private array $peoples = [
[
'lastName' => 'Depardieu',
@@ -90,7 +96,7 @@ class LoadPeople extends AbstractFixture implements ContainerAwareInterface, Ord
'birthdate' => '1948-12-27',
'placeOfBirth' => 'Châteauroux',
'nationality' => 'RU',
'gender' => Person::MALE_GENDER,
'gender' => GenderEnum::MALE,
'center' => 'Center A',
'accompanyingPeriods' => [
[
@@ -119,7 +125,7 @@ class LoadPeople extends AbstractFixture implements ContainerAwareInterface, Ord
'maritalStatus' => 'ms_divorce',
],
[
// to have a person with same birthdate of Gérard Depardieu
// to have a person with same birthdate as Gérard Depardieu
'lastName' => 'Van Snick',
'firstName' => 'Bart',
'birthdate' => '1948-12-27',
@@ -131,7 +137,7 @@ class LoadPeople extends AbstractFixture implements ContainerAwareInterface, Ord
'lastName' => 'Depardieu',
'firstName' => 'Charline',
'birthdate' => '1970-10-15',
'gender' => Person::FEMALE_GENDER,
'gender' => GenderEnum::FEMALE,
'center' => 'Center A',
'maritalStatus' => 'ms_legalco',
],
@@ -228,6 +234,7 @@ class LoadPeople extends AbstractFixture implements ContainerAwareInterface, Ord
protected MaritalStatusRepository $maritalStatusRepository,
protected ScopeRepository $scopeRepository,
protected UserRepository $userRepository,
protected GenderRepository $genderRepository,
) {
$this->faker = Factory::create('fr_FR');
$this->faker->addProvider($this);
@@ -272,9 +279,17 @@ class LoadPeople extends AbstractFixture implements ContainerAwareInterface, Ord
/**
* @internal This method is public and called by faker as a custom generator
*/
public function getRandomGender(): string
public function getRandomGender(int $nullPercentage = 50): ?Gender
{
return $this->genders[array_rand($this->genders)];
if (0 === \count($this->cacheGenders)) {
$this->cacheGenders = $this->genderRepository->findByActiveOrdered();
}
if (\random_int(0, 100) > $nullPercentage) {
return null;
}
return $this->cacheGenders[array_rand($this->cacheGenders)];
}
/**

View File

@@ -21,6 +21,7 @@ use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\Language;
use Chill\MainBundle\Entity\User;
@@ -62,19 +63,11 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[HouseholdMembershipSequential(groups: ['household_memberships'])]
class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateInterface, \Stringable
{
final public const BOTH_GENDER = 'both';
// have days in commun
final public const ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD = 2; // where there exist
final public const ERROR_PERIODS_ARE_COLLAPSING = 1; // when two different periods
final public const FEMALE_GENDER = 'woman';
final public const MALE_GENDER = 'man';
final public const NO_INFORMATION = 'unknown';
/**
* Accept receiving email.
*/
@@ -245,11 +238,11 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
private ?string $fullnameCanonical = '';
/**
* The person's gender.
* NEW column : The person's gender.
*/
#[Assert\NotNull(message: 'The gender must be set')]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 9, nullable: true)]
private ?string $gender = null;
#[ORM\ManyToOne(targetEntity: Gender::class)]
private ?Gender $gender = null;
/**
* Comment on gender.
@@ -1041,7 +1034,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->fullnameCanonical;
}
public function getGender(): ?string
public function getGender(): ?Gender
{
return $this->gender;
}
@@ -1051,24 +1044,6 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->genderComment;
}
/**
* return gender as a Numeric form.
* This is used for translations.
*
* @return int
*
* @deprecated Keep for legacy. Used in Chill 1.5 for feminize before icu translations
*/
public function getGenderNumeric()
{
return match ($this->getGender()) {
self::FEMALE_GENDER => 1,
self::MALE_GENDER => 0,
self::BOTH_GENDER => 2,
default => -1,
};
}
public function getHouseholdAddresses(): Collection
{
return $this->householdAddresses;
@@ -1570,7 +1545,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
public function setGender(?string $gender): self
public function setGender(?Gender $gender): self
{
$this->gender = $gender;

View File

@@ -55,7 +55,7 @@ readonly class ReferrerScopeAggregator implements AggregatorInterface, DataTrans
$qb->expr()->gte('COALESCE(acp.closingDate, CURRENT_TIMESTAMP())', "{$p}_userHistory.startDate"),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_userHistory.endDate"),
$qb->expr()->lt('COALESCE(acp.closingDate, CURRENT_TIMESTAMP())', "{$p}_userHistory.endDate")
$qb->expr()->lt('COALESCE(acp.openingDate, CURRENT_TIMESTAMP())', "{$p}_userHistory.endDate")
)
),
$qb->expr()->andX(

View File

@@ -12,7 +12,8 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Repository\GenderRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
@@ -20,7 +21,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
final readonly class GenderAggregator implements AggregatorInterface
{
public function __construct(private TranslatorInterface $translator) {}
public function __construct(private TranslatorInterface $translator, private TranslatableStringHelperInterface $translatableStringHelper, private GenderRepository $repository) {}
public function addRole(): ?string
{
@@ -29,7 +30,8 @@ final readonly class GenderAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->addSelect('person.gender as gender');
$qb->leftJoin('person.gender', 'g');
$qb->addSelect('g.id as gender');
$qb->addGroupBy('gender');
}
@@ -48,30 +50,20 @@ final readonly class GenderAggregator implements AggregatorInterface
public function getLabels($key, array $values, $data)
{
return function ($value) {
switch ($value) {
case Person::FEMALE_GENDER:
return $this->translator->trans('woman');
case Person::MALE_GENDER:
return $this->translator->trans('man');
case Person::BOTH_GENDER:
return $this->translator->trans('both');
case Person::NO_INFORMATION:
return $this->translator->trans('unknown');
case null:
case '':
return $this->translator->trans('Not given');
case '_header':
return $this->translator->trans('Gender');
default:
throw new \LogicException(sprintf('The value %s is not valid', $value));
return function (int|string|null $value) {
if (null === $value || '' === $value) {
return '';
}
if ('_header' === $value) {
return $this->translator->trans('Gender');
}
if (null === $gender = $this->repository->find((int) $value)) {
return '';
}
return (string) $this->translatableStringHelper->localize($gender->getLabel());
};
}

View File

@@ -11,11 +11,13 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Filter\PersonFilters;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Export\DataTransformerInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Repository\GenderRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -24,17 +26,15 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class GenderFilter implements
ExportElementValidatedInterface,
FilterInterface
FilterInterface,
DataTransformerInterface
{
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
// inject gender repository and find the active genders so that you can pass them to the ChoiceType (ordered by ordering)
public function __construct(
private readonly TranslatorInterface $translator,
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly GenderRepository $genderRepository,
) {}
public function addRole(): ?string
{
@@ -46,23 +46,17 @@ class GenderFilter implements
$where = $qb->getDQLPart('where');
$isIn = $qb->expr()->in('person.gender', ':person_gender');
if (!\in_array('null', $data['accepted_genders'], true)) {
$acceptedGenders = $data['accepted_genders_entity'];
$nullIncluded = in_array(null, $acceptedGenders ?? [], true);
if (!$nullIncluded) {
$clause = $isIn;
} else {
$clause = $qb->expr()->orX($isIn, $qb->expr()->isNull('person.gender'));
}
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('person_gender', \array_filter(
$data['accepted_genders'],
static fn ($el) => 'null' !== $el
));
$qb->andWhere($clause);
$qb->setParameter('person_gender', array_filter($acceptedGenders ?? [], fn ($gender) => null !== $gender));
}
public function applyOn()
@@ -72,19 +66,42 @@ class GenderFilter implements
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_genders', ChoiceType::class, [
'choices' => [
'Woman' => Person::FEMALE_GENDER,
'Man' => Person::MALE_GENDER,
'Both' => Person::BOTH_GENDER,
'Unknown' => Person::NO_INFORMATION,
'Not given' => 'null',
],
$genderChoices = $this->genderRepository->findByActiveOrdered();
$choices = ['None' => null];
foreach ($genderChoices as $gender) {
$choices[$this->translatableStringHelper->localize($gender->getLabel())] = $gender->getId();
}
$builder->add('accepted_genders_entity', ChoiceType::class, [
'choices' => $choices,
'multiple' => true,
'expanded' => true,
'placeholder' => 'Select gender',
]);
}
public function transformData(?array $before): array
{
$transformedData = [];
$transformedData['accepted_genders_entity'] = $before['accepted_genders_entity'] ?? [];
if (array_key_exists('accepted_genders', $before)) {
foreach ($before['accepted_genders'] as $genderBefore) {
foreach ($this->genderRepository->findByGenderTranslation(
match ($genderBefore) {
'both' => 'neutral',
default => $genderBefore,
}
) as $gender) {
$transformedData['accepted_genders_entity'][] = $gender;
}
}
}
return $transformedData;
}
public function getFormDefaultData(): array
{
return [];
@@ -94,11 +111,11 @@ class GenderFilter implements
{
$genders = [];
foreach ($data['accepted_genders'] as $g) {
if ('null' === $g) {
$genders[] = $this->translator->trans('Not given');
foreach ($data['accepted_genders_entity'] as $g) {
if (null === $g) {
$genders[] = $this->translator->trans('export.filter.person.gender.no_gender');
} else {
$genders[] = $this->translator->trans($g);
$genders[] = $this->translatableStringHelper->localize($this->genderRepository->find($g)->getLabel());
}
}
@@ -120,7 +137,7 @@ class GenderFilter implements
public function validateForm($data, ExecutionContextInterface $context)
{
if (!\is_array($data['accepted_genders']) || 0 === \count($data['accepted_genders'])) {
if (!\is_iterable($data['accepted_genders_entity']) || 0 === \count($data['accepted_genders_entity'])) {
$context->buildViolation('You should select an option')
->addViolation();
}

View File

@@ -16,6 +16,7 @@ use Chill\MainBundle\Export\Helper\ExportAddressHelper;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\CivilityRepositoryInterface;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Repository\GenderRepository;
use Chill\MainBundle\Repository\LanguageRepositoryInterface;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
@@ -80,6 +81,7 @@ final readonly class ListPersonHelper
private TranslatableStringHelper $translatableStringHelper,
private TranslatorInterface $translator,
private UserRepositoryInterface $userRepository,
private GenderRepository $genderRepository,
/**
* @var iterable<CustomizeListPersonHelperInterface>
*/
@@ -173,6 +175,11 @@ final readonly class ListPersonHelper
break;
case 'gender':
$qb->addSelect('IDENTITY(person.gender) AS gender');
break;
case 'maritalStatus':
$qb->addSelect('IDENTITY(person.maritalStatus) AS maritalStatus');
@@ -325,7 +332,13 @@ final readonly class ListPersonHelper
return $this->translator->trans($key);
}
return $this->translator->trans($value);
if (null === $value) {
return '';
}
$gender = $this->genderRepository->find($value);
return $this->translatableStringHelper->localize($gender->getLabel());
};
case 'maritalStatus':

View File

@@ -20,8 +20,8 @@ use Chill\MainBundle\Form\Type\PickCenterType;
use Chill\MainBundle\Form\Type\PickCivilityType;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\Type\GenderType;
use Chill\PersonBundle\Form\Type\PersonAltNameType;
use Chill\PersonBundle\Form\Type\PickGenderType;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use libphonenumber\PhoneNumberType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
@@ -60,7 +60,7 @@ final class CreationPersonType extends AbstractType
'label' => 'Civility',
'placeholder' => 'choose civility',
])
->add('gender', GenderType::class, [
->add('gender', PickGenderType::class, [
'required' => true, 'placeholder' => null,
])
->add('birthdate', ChillDateType::class, [

View File

@@ -24,9 +24,9 @@ use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonPhone;
use Chill\PersonBundle\Form\Type\GenderType;
use Chill\PersonBundle\Form\Type\PersonAltNameType;
use Chill\PersonBundle\Form\Type\PersonPhoneType;
use Chill\PersonBundle\Form\Type\PickGenderType;
use Chill\PersonBundle\Form\Type\Select2MaritalStatusType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
@@ -80,7 +80,7 @@ class PersonType extends AbstractType
'input' => 'datetime_immutable',
'widget' => 'single_text',
])
->add('gender', GenderType::class, [
->add('gender', PickGenderType::class, [
'required' => true,
])
->add('genderComment', CommentType::class, [

View File

@@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Form\Type;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* A type to select the civil union state.
*/
class GenderType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$a = [
Person::MALE_GENDER => Person::MALE_GENDER,
Person::FEMALE_GENDER => Person::FEMALE_GENDER,
Person::BOTH_GENDER => Person::BOTH_GENDER,
];
$resolver->setDefaults([
'choices' => $a,
'expanded' => true,
'multiple' => false,
'placeholder' => null,
]);
}
public function getParent()
{
return ChoiceType::class;
}
}

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Form\Type;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* A type to select the civil union state.
*/
class PickGenderType extends AbstractType
{
public function __construct(private readonly TranslatableStringHelper $translatableStringHelper) {}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('label', 'Gender')
->setDefault(
'choice_label',
fn (Gender $gender): string => $this->translatableStringHelper->localize($gender->getLabel())
)
->setDefault(
'query_builder',
static fn (EntityRepository $er): QueryBuilder => $er->createQueryBuilder('g')
->where('g.active = true')
->orderBy('g.order'),
)
->setDefault('placeholder', 'choose gender')
->setDefault('class', Gender::class);
}
public function getParent()
{
return EntityType::class;
}
}

View File

@@ -45,13 +45,17 @@ class AdminPersonMenuBuilder implements LocalMenuBuilderInterface
'route' => 'chill_crud_main_civility_index',
])->setExtras(['order' => 2010]);
$menu->addChild('Gender', [
'route' => 'chill_crud_main_gender_index',
])->setExtras(['order' => 2020]);
$menu->addChild('Marital status', [
'route' => 'chill_crud_person_marital-status_index',
])->setExtras(['order' => 2020]);
])->setExtras(['order' => 2030]);
$menu->addChild('person_admin.person_resource_kind', [
'route' => 'chill_crud_person_resource-kind_index',
])->setExtras(['order' => 2030]);
])->setExtras(['order' => 2040]);
}
public static function getMenuIds(): array

View File

@@ -34,7 +34,7 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,
@@ -62,7 +62,7 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,
@@ -96,7 +96,7 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,
@@ -202,7 +202,7 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
}
if (null !== $gender) {
$query->andWhereClause('person.gender = ?', [$gender]);
$query->andWhereClause('person.gender_id = ?', [$gender]);
}
return $query;
@@ -253,7 +253,7 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,

View File

@@ -23,7 +23,7 @@ interface PersonACLAwareRepositoryInterface
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,
@@ -36,7 +36,7 @@ interface PersonACLAwareRepositoryInterface
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,
@@ -55,7 +55,7 @@ interface PersonACLAwareRepositoryInterface
?\DateTimeInterface $birthdate = null,
?\DateTimeInterface $birthdateBefore = null,
?\DateTimeInterface $birthdateAfter = null,
?string $gender = null,
?int $gender = null,
?string $countryCode = null,
?string $phonenumber = null,
?string $city = null,

View File

@@ -128,7 +128,7 @@ export default {
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = payload.data.gender;
body.gender = {id: payload.data.gender.id, type: payload.data.gender.type };
if (payload.data.civility !== null) { body.civility = {id: payload.data.civility.id, type: payload.data.civility.type }; }
makeFetch('PATCH', `/api/1.0/person/person/${payload.data.id}.json`, body)

View File

@@ -153,7 +153,7 @@ export default {
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = payload.data.gender;
body.gender = {id: payload.data.gender.id, type: payload.data.gender.type };
if (payload.data.civility !== null) { body.civility = {id: payload.data.civility.id, type: payload.data.civility.type}; }
makeFetch('PATCH', `/api/1.0/person/person/${payload.data.id}.json`, body)

View File

@@ -8,7 +8,7 @@
{{ $t('household_members_editor.holder') }}
</span>
</div>
<div v-if="conc.person.birthdate !== null">{{ $t('person.born', {'gender': conc.person.gender} ) }}</div>
<div v-if="conc.person.birthdate !== null">{{ $t('person.born', {'gender': conc.person.gender.genderTranslation} ) }}</div>
</div>
<div class="item-col">
<ul class="list-content fa-ul">

View File

@@ -12,10 +12,6 @@ const visMessages = {
Holder: 'Titulaire',
Legend: 'Calques',
concerned: 'concerné',
// both: 'neutre, non binaire',
woman: 'féminin',
man: 'masculin',
undefined: "genre non précisé",
years: 'ans',
click_to_expand: 'cliquez pour étendre',
add_relationship_link: "Créer un lien de filiation",
@@ -64,7 +60,7 @@ const visMessages = {
placeholder: "Choisissez le genre de l'usager",
woman: "Féminin",
man: "Masculin",
both: "Neutre, non binaire",
neutral: "Neutre, non binaire",
undefined: "Non renseigné",
unknown: "Non renseigné"
}

View File

@@ -1,6 +1,6 @@
import { createStore } from 'vuex'
import { getHouseholdByPerson, getCoursesByPerson, getRelationshipsByPerson } from './api'
import { getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle, getRelationshipDirection, splitId, getGender, getAge } from './vis-network'
import { getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle, getRelationshipDirection, splitId, getAge } from './vis-network'
import {visMessages} from "./i18n";
import { darkBlue, darkBrown, darkGreen, lightBlue, lightBrown, lightGreen } from './colors';
@@ -148,7 +148,7 @@ const store = createStore({
person.group = person.type
person._id = person.id
person.id = `person_${person.id}`
person.label = `*${person.text}${person.deathdate ? ' (‡)' : ''}*\n_${getGender(person.gender)}${age}_${debug}`
person.label = `*${person.text}${person.deathdate ? ' (‡)' : ''}*\n_${person.gender.label.fr}${age}_${debug}`
person.folded = false
// folded is used for missing persons
if (options.folded) {

View File

@@ -141,25 +141,6 @@ window.options = {
}
}
/**
* @param gender
* @returns {string}
*/
const getGender = (gender) => {
switch (gender) {
case 'both':
return visMessages.fr.visgraph.both
case 'woman':
return visMessages.fr.visgraph.woman
case 'man':
return visMessages.fr.visgraph.man
case 'unknown':
return visMessages.fr.visgraph.unknown
default:
return visMessages.fr.visgraph.undefined
}
}
/**
* TODO only one abstract function (-> getAge() is repeated in PersonRenderBox.vue)
* @param person
@@ -251,7 +232,6 @@ const splitId = (id, position) => {
}
export {
getGender,
getAge,
getHouseholdLabel,
getHouseholdWidth,

View File

@@ -24,6 +24,13 @@ const getCivilities = () =>
throw Error('Error with request resource response');
});
const getGenders = () => makeFetch("GET", '/api/1.0/main/gender.json')
// .then(response => {
// console.log(response)
// if (response.ok) { return response.json(); }
// throw Error('Error with request resource response');
// });
const getCentersForPersonCreation = () => makeFetch('GET', '/api/1.0/person/creation/authorized-centers', null);
/*
@@ -63,10 +70,11 @@ const patchPerson = (id, body) => {
};
export {
getCentersForPersonCreation,
getCentersForPersonCreation,
getPerson,
getPersonAltNames,
getCivilities,
getGenders,
postPerson,
patchPerson
};

View File

@@ -37,10 +37,9 @@
</div>
<p v-if="options.addInfo === true" class="moreinfo">
<i :class="'fa fa-fw ' + getGenderIcon" :title="$t(getGender)"></i>
<gender-icon-render-box v-if="person.gender" :gender="person.gender"></gender-icon-render-box>
<time v-if="person.birthdate && !person.deathdate" :datetime="person.birthdate" :title="birthdate">
{{ $t(getGenderTranslation) + ' ' + $d(birthdate, 'text') }}
{{ $t(person.gender ? `renderbox.birthday.${person.gender.genderTranslation}` : 'renderbox.birthday.neutral') + ' ' + $d(birthdate, 'text') }}
</time>
<time v-else-if="person.birthdate && person.deathdate" :datetime="person.deathdate"
@@ -180,6 +179,7 @@
<script>
import {dateToISO, ISOToDate} from 'ChillMainAssets/chill/js/date';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
import GenderIconRenderBox from 'ChillMainAssets/vuejs/_components/Entity/GenderIconRenderBox.vue'
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
@@ -190,6 +190,7 @@ export default {
name: "PersonRenderBox",
components: {
AddressRenderBox,
GenderIconRenderBox,
Confidential,
BadgeEntity,
PersonText,
@@ -222,15 +223,6 @@ export default {
return false
}
},
getGenderIcon: function () {
return this.person.gender === 'woman' ? 'fa-venus' : this.person.gender === 'man' ? 'fa-mars' : this.person.gender === 'both' ? 'fa-neuter' : 'fa-genderless';
},
getGenderTranslation: function () {
return this.person.gender === 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
},
getGender() {
return this.person.gender === 'woman' ? 'person.gender.woman' : this.person.gender === 'man' ? 'person.gender.man' : this.person.gender === 'both' ? 'person.gender.both' : 'person.gender.undefined';
},
birthdate: function () {
if (this.person.birthdate !== null || this.person.birthdate === "undefined") {
return ISOToDate(this.person.birthdate.datetime);

View File

@@ -73,17 +73,16 @@
<!-- TODO fix placeholder if undefined
-->
<div class="form-floating mb-3">
<select
<select
class="form-select form-select-lg"
id="gender"
v-model="gender"
@change="checkErrors"
>
<option selected disabled >{{ $t('person.gender.placeholder') }}</option>
<option value="woman">{{ $t('person.gender.woman') }}</option>
<option value="man">{{ $t('person.gender.man') }}</option>
<option value="both">{{ $t('person.gender.both') }}</option>
</select>
>
<option selected disabled >{{ $t('person.gender.placeholder') }}</option>
<option v-for="g in config.genders" :value="g.id" :key="g.id">
{{ g.label.fr }}
</option>
</select>
<label>{{ $t('person.gender.title') }}</label>
</div>
@@ -178,7 +177,7 @@
</template>
<script>
import { getCentersForPersonCreation, getCivilities, getPerson, getPersonAltNames } from '../../_api/OnTheFly';
import { getCentersForPersonCreation, getCivilities, getGenders, getPerson, getPersonAltNames } from '../../_api/OnTheFly';
import PersonRenderBox from '../Entity/PersonRenderBox.vue';
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
@@ -204,6 +203,7 @@ export default {
altNames: [],
civilities: [],
centers: [],
genders: []
},
showCenters: false, // NOTE: must remains false if the form is not in create mode
showAddressFormValue: false,
@@ -237,8 +237,8 @@ export default {
get() { return this.person.lastName; }
},
gender: {
set(value) { this.person.gender = value; },
get() { return this.person.gender; }
set(value) { this.person.gender = {id: value, type: 'chill_main_gender'}; },
get() { return this.person.gender ? this.person.gender.id : null; }
},
civility: {
set(value) { this.person.civility = {id: value, type: 'chill_main_civility'}; },
@@ -300,13 +300,13 @@ export default {
}
},
genderTranslation() {
switch (this.person.gender) {
switch (this.person.gender.genderTranslation) {
case 'woman':
return 'person.gender.woman';
case 'man':
return 'person.gender.man';
case 'both':
return 'person.gender.both';
case 'neutral':
return 'person.gender.neutral';
case 'unknown':
return 'person.gender.unknown';
default:
@@ -334,6 +334,12 @@ export default {
this.config.civilities = civilities.results;
}
});
getGenders()
.then(genders => {
if ('results' in genders) {
this.config.genders = genders.results;
}
});
if (this.action !== 'create') {
this.loadData();
} else {

View File

@@ -15,7 +15,7 @@ const personMessages = {
person: {
firstname: "Prénom",
lastname: "Nom",
born: (ctx: {gender: "man"|"woman"|"unknown"}) => {
born: (ctx: {gender: "man"|"woman"|"neutral"}) => {
if (ctx.gender === 'man') {
return 'Né le';
} else if (ctx.gender === 'woman') {
@@ -36,7 +36,7 @@ const personMessages = {
placeholder: "Choisissez le genre de l'usager",
woman: "Féminin",
man: "Masculin",
both: "Neutre, non binaire",
neutral: "Neutre, non binaire",
unknown: "Non renseigné",
undefined: "Non renseigné"
},

View File

@@ -33,7 +33,7 @@
{% if w.referrers %}
<li>
<span class="item-key">{{ 'Referrers'|trans ~ ' : ' }}</span>
{% for rh in w.referrersHistory %}
{% for rh in w.referrersHistoryCurrent %}
<span class="badge-user">{{ rh.user|chill_entity_render_box({'at_date': rh.startDate}) }}</span>
{% endfor %}
{% if w.referrers|length == 0 %}

View File

@@ -85,13 +85,8 @@
{%- endif -%}
</div>
{%- if options['addInfo'] -%}
{% set gender = (person.gender == 'woman') ? 'fa-venus' :
(person.gender == 'man') ? 'fa-mars' : (person.gender == 'both') ? 'fa-neuter' : 'fa-genderless' %}
{% set genderTitle = (person.gender == 'woman') ? 'woman' :
(person.gender == 'man') ? 'man' : (person.gender == 'both') ? 'both' : 'Not given'|trans %}
<p class="moreinfo">
<i class="fa fa-fw {{ gender }}" title="{{ genderTitle|trans }}"></i>
{% if person.gender is not null %}{{ person.gender.icon|chill_entity_render_box }}{% endif %}
{%- if person.deathdate is not null -%}
{%- if person.birthdate is not null -%}
{# must be on one line to avoid spaces with dash #}
@@ -106,7 +101,7 @@
{%- 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,
{{ 'Born the date'|trans({'gender': person.gender ? person.gender.genderTranslation.value : 'neutral',
'birthdate': person.birthdate|format_date("medium") }) }}
</time>
{%- if options['addAge'] -%}

View File

@@ -45,7 +45,7 @@
<div class="ms-auto">
{% if acp.requestoranonymous == false and acp.requestorPerson is same as(person) %}
<span class="as-requestor badge bg-info" title="{{ 'Requestor'|trans|e('html_attr') }}">
{{ 'Requestor'|trans({'gender': person.gender}) }}
{{ 'Requestor'|trans({'gender': person.gender ? person.gender.genderTranslation.value : 'neutral'}) }}
</span>
{% endif %}
@@ -119,7 +119,7 @@
{% endif %}
{% endfor %}
{% if participating %}
{{ 'person.and_himself'|trans({'gender': person.gender}) }}
{{ 'person.And himself'|trans({'gender': person.gender ? person.gender.genderTranslation.value : 'neutral'}) }}
{% endif %}
</div>
</div>
@@ -131,7 +131,7 @@
<div class="wl-col title">
<h3>
{% if acp.requestorPerson is not null %}
{{ 'Requestor'|trans({'gender': acp.requestorPerson.gender}) }}
{{ 'Requestor'|trans({'gender': acp.requestorPerson.gender ? person.gender.genderTranslation.value : 'neutral'}) }}
{% else %}
{{ 'Requestor'|trans({'gender': 'other'})}}
{% endif %}

View File

@@ -73,8 +73,11 @@ This view should receive those arguments:
{% endfor %}
<dt>{{ 'Gender'|trans }}&nbsp;:</dt>
<dd>{{ ( person.gender|default('Not given'))|trans }}</dd>
{% if person.gender %}
<dd>{{ ( person.gender.label|localize_translatable_string ) }}</dd>
{% else %}
<dd>{{ 'gender.not defined'|trans }}</dd>
{% endif %}
</dl>
</figure>
</div>
@@ -253,7 +256,6 @@ This view should receive those arguments:
<dd>{% if el.description is not empty %}{{ el.description }}&nbsp;:&nbsp;{% endif %}<a href="tel:{{ el.phonenumber|phone_number_format('E164') }}">{{ el.phonenumber|chill_format_phonenumber }}</a></dd>
{% endif %}
{% endfor %}
</ul>
</dl>
{% endif %}
{% endif %}

View File

@@ -2,7 +2,7 @@
<ul>
<li><b>{{ 'gender'|trans }}</b>:
{{ person.gender|trans }}</li>
{{ person.gender.label|localize_translatable_string }}</li>
<li><b>{{ 'maritalStatus'|trans }}</b>:
{% if person.maritalStatus %}{{ person.maritalStatus.name|localize_translatable_string }}{% endif %}</li>
<li><b>{{ 'birthdate'|trans }}</b>:

View File

@@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Search;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\GenderRepository;
use Chill\MainBundle\Search\AbstractSearch;
use Chill\MainBundle\Search\HasAdvancedSearchFormInterface;
use Chill\MainBundle\Search\ParsingException;
@@ -21,7 +22,7 @@ use Chill\MainBundle\Search\SearchInterface;
use Chill\MainBundle\Search\Utils\ExtractDateFromPattern;
use Chill\MainBundle\Search\Utils\ExtractPhonenumberFromPattern;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\Type\GenderType;
use Chill\PersonBundle\Form\Type\PickGenderType;
use Chill\PersonBundle\Repository\PersonACLAwareRepositoryInterface;
use libphonenumber\PhoneNumber;
use Symfony\Component\Form\Extension\Core\Type\TextType;
@@ -36,7 +37,14 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
'birthdate-after', 'gender', 'nationality', 'phonenumber', 'city',
];
public function __construct(private readonly \Twig\Environment $templating, private readonly ExtractDateFromPattern $extractDateFromPattern, private readonly ExtractPhonenumberFromPattern $extractPhonenumberFromPattern, private readonly PaginatorFactory $paginatorFactory, private readonly PersonACLAwareRepositoryInterface $personACLAwareRepository) {}
public function __construct(
private readonly \Twig\Environment $templating,
private readonly ExtractDateFromPattern $extractDateFromPattern,
private readonly ExtractPhonenumberFromPattern $extractPhonenumberFromPattern,
private readonly PaginatorFactory $paginatorFactory,
private readonly PersonACLAwareRepositoryInterface $personACLAwareRepository,
private readonly GenderRepository $genderRepository,
) {}
public function buildForm(FormBuilderInterface $builder)
{
@@ -69,7 +77,7 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
'required' => false,
'label' => 'Part of the phonenumber',
])
->add('gender', GenderType::class, [
->add('gender', PickGenderType::class, [
'label' => 'Gender',
'required' => false,
'expanded' => false,
@@ -87,7 +95,7 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
$string .= !isset($data['_default']) ? '' : $data['_default'].' ';
foreach (['firstname', 'lastname', 'gender', 'city'] as $key) {
foreach (['firstname', 'lastname', 'city'] as $key) {
$string .= !isset($data[$key]) ? '' : $key.':'.
// add quote if contains spaces
(str_contains((string) $data[$key], ' ') ? '"'.$data[$key].'"' : $data[$key])
@@ -103,6 +111,8 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
$string .= !isset($data['phonenumber']) ? '' : 'phonenumber:'.$data['phonenumber']->getNationalNumber();
$string .= !isset($data['gender']) ? '' : 'gender:"'.$data['gender']->getId().'"';
return $string;
}
@@ -110,7 +120,7 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
{
$data = [];
foreach (['firstname', 'lastname', 'gender', '_default', 'phonenumber', 'city'] as $key) {
foreach (['firstname', 'lastname', '_default', 'phonenumber', 'city'] as $key) {
$data[$key] = $terms[$key] ?? null;
}
@@ -137,6 +147,10 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
$data['phonenumber'] = $phonenumber;
}
if (array_key_exists('gender', $terms)) {
$data['gender'] = $this->genderRepository->find((int) $terms['gender']);
}
return $data;
}
@@ -256,7 +270,7 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
$birthdate,
$birthdateBefore,
$birthdateAfter,
$gender,
null !== $gender ? (int) $gender : null,
$countryCode,
$phonenumber,
$city
@@ -316,7 +330,7 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf
$birthdate,
$birthdateBefore,
$birthdateAfter,
$gender,
null !== $gender ? (int) $gender : null,
$countryCode,
$phonenumber,
$city

View File

@@ -14,7 +14,7 @@ namespace Chill\PersonBundle\Security\Authorization\StoredObjectVoter;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkEvaluationDocumentVoter;
@@ -25,7 +25,7 @@ class AccompanyingPeriodWorkEvaluationDocumentStoredObjectVoter extends Abstract
public function __construct(
private readonly AccompanyingPeriodWorkEvaluationDocumentRepository $repository,
Security $security,
WorkflowStoredObjectPermissionHelper $workflowDocumentService,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
) {
parent::__construct($security, $workflowDocumentService);
}

View File

@@ -16,6 +16,7 @@ use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
@@ -30,7 +31,6 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Contracts\Translation\TranslatorInterface;
class PersonDocGenNormalizer implements
ContextAwareNormalizerInterface,
@@ -40,7 +40,7 @@ class PersonDocGenNormalizer implements
private const CIRCULAR_KEY = 'person:circular';
public function __construct(private readonly PersonRenderInterface $personRender, private readonly RelationshipRepository $relationshipRepository, private readonly TranslatorInterface $translator, private readonly TranslatableStringHelper $translatableStringHelper, private readonly SummaryBudgetInterface $summaryBudget) {}
public function __construct(private readonly PersonRenderInterface $personRender, private readonly RelationshipRepository $relationshipRepository, private readonly TranslatableStringHelper $translatableStringHelper, private readonly SummaryBudgetInterface $summaryBudget) {}
public function normalize($person, $format = null, array $context = [])
{
@@ -67,6 +67,7 @@ class PersonDocGenNormalizer implements
// when a person reference the same person... take care of circular references
AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => fn ($object, $format, $context) => $this->normalizer->normalize(null, $format, $context),
]);
$genderContext = array_merge($context, ['docgen:expects' => Gender::class]);
if (null === $person) {
return $this->normalizeNullValue($format, $context);
@@ -94,7 +95,7 @@ class PersonDocGenNormalizer implements
'age' => (int) $person->getAge(),
'birthdate' => $this->normalizer->normalize($person->getBirthdate(), $format, $dateContext),
'deathdate' => $this->normalizer->normalize($person->getDeathdate(), $format, $dateContext),
'gender' => $this->translator->trans($person->getGender()),
'gender' => $this->normalizer->normalize($person->getGender(), $format, $genderContext),
'maritalStatus' => null !== ($ms = $person->getMaritalStatus()) ? $this->translatableStringHelper->localize($ms->getName()) : '',
'maritalStatusDate' => $this->normalizer->normalize($person->getMaritalStatusDate(), $format, $dateContext),
'maritalStatusComment' => $this->normalizer->normalize($person->getMaritalStatusComment(), $format, $dateContext),

View File

@@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Phonenumber\PhoneNumberHelperInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
@@ -112,7 +113,9 @@ class PersonJsonNormalizer implements DenormalizerAwareInterface, NormalizerAwar
break;
case 'gender':
$person->setGender($data[$item]);
$gender = $this->denormalizer->denormalize($data[$item], Gender::class, $format, []);
$person->setGender($gender);
break;
@@ -199,7 +202,7 @@ class PersonJsonNormalizer implements DenormalizerAwareInterface, NormalizerAwar
'phonenumber' => $this->normalizer->normalize($person->getPhonenumber(), $format, $context),
'mobilenumber' => $this->normalizer->normalize($person->getMobilenumber(), $format, $context),
'email' => $person->getEmail(),
'gender' => $person->getGender(),
'gender' => $this->normalizer->normalize($person->getGender(), $format, $context),
'civility' => $this->normalizer->normalize($person->getCivility(), $format, $context),
];

View File

@@ -11,6 +11,9 @@ declare(strict_types=1);
namespace Tests\Controller\AccompanyingCoursWorkApiController;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
@@ -129,8 +132,15 @@ class ConflictTest extends WebTestCase
$period = new AccompanyingPeriod();
$em->persist($period);
$gender = new Gender();
$gender->setGenderTranslation(GenderEnum::MALE);
$gender->setLabel(['fr' => 'homme']);
$gender->setIcon(GenderIconEnum::MALE);
$em->persist($gender);
$period->addPerson(($p = new Person())->setFirstName('test')->setLastName('test')
->setBirthdate(new \DateTime('1980-01-01'))->setGender(Person::BOTH_GENDER));
->setBirthdate(new \DateTime('1980-01-01'))->setGender($gender));
$em->persist($p);
$issue = (new SocialIssue())->setTitle(['fr' => 'test']);
$em->persist($issue);

View File

@@ -14,6 +14,9 @@ namespace Chill\PersonBundle\Tests\Controller;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\AddressReference;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Household\Household;
@@ -51,9 +54,15 @@ final class HouseholdApiControllerTest extends WebTestCase
->setMaxResults(1)
->getQuery()->getSingleResult();
$gender = new Gender();
$gender->setGenderTranslation(GenderEnum::MALE);
$gender->setLabel(['fr' => 'homme']);
$gender->setIcon(GenderIconEnum::MALE);
$em->persist($gender);
$p = new Person();
$p->setFirstname('test')->setLastName('test lastname')
->setGender(Person::BOTH_GENDER)
->setGender($gender)
->setCenter($centerA);
$em->persist($p);
$h = new Household();

View File

@@ -112,24 +112,24 @@ final class PersonControllerCreateTest extends WebTestCase
$genderType = $form->get(self::GENDER_INPUT);
$this->assertEquals(
'radio',
'select',
$genderType->getType(),
'The gender input has radio buttons'
'The gender input is a select form to select a gender entity'
);
$this->assertEquals(
3,
\count($genderType->availableOptionValues()),
'The gender input has three options: man, women and undefined'
);
$this->assertTrue(
\in_array('man', $genderType->availableOptionValues(), true),
'gender has "homme" option'
);
$this->assertTrue(
\in_array('woman', $genderType->availableOptionValues(), true),
'gender has "femme" option'
);
$this->assertFalse($genderType->hasValue(), 'The gender input is not checked');
/* $this->assertEquals(
3,
\count($genderType->availableOptionValues()),
'The gender input has three options: man, women and undefined'
);
$this->assertTrue(
\in_array('man', $genderType->availableOptionValues(), true),
'gender has "homme" option'
);
$this->assertTrue(
\in_array('woman', $genderType->availableOptionValues(), true),
'gender has "femme" option'
);
$this->assertFalse($genderType->hasValue(), 'The gender input is not checked');*/
return $form;
}
@@ -226,7 +226,8 @@ final class PersonControllerCreateTest extends WebTestCase
) {
$creationForm->get(self::FIRSTNAME_INPUT)->setValue($firstname.'_'.uniqid());
$creationForm->get(self::LASTNAME_INPUT)->setValue($lastname.'_'.uniqid());
$creationForm->get(self::GENDER_INPUT)->select('man');
// Todo change hardcoded id
$creationForm->get(self::GENDER_INPUT)->select(5);
$date = $birthdate ?? new \DateTime('1947-02-01');
$creationForm->get(self::BIRTHDATE_INPUT)->setValue($date->format('Y-m-d'));

View File

@@ -12,6 +12,9 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Controller;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Person;
@@ -160,12 +163,18 @@ final class PersonControllerUpdateTest extends WebTestCase
$em = self::getContainer()->get(EntityManagerInterface::class);
$center = $centerRepository->findOneBy(['name' => 'Center A']);
$gender = new Gender();
$gender->setGenderTranslation(GenderEnum::MALE);
$gender->setLabel(['fr' => 'homme']);
$gender->setIcon(GenderIconEnum::MALE);
$em->persist($gender);
$person = new Person();
$person
->setFirstName('Foo')
->setLastName('Bar')
->setBirthdate(new \DateTime('2017-09-30'))
->setGender(Person::MALE_GENDER)
->setGender($gender)
->setCenter($center);
$em->persist($person);

View File

@@ -11,6 +11,9 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Controller;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Person;
@@ -99,12 +102,18 @@ final class PersonControllerViewTest extends WebTestCase
$em = self::getContainer()->get(EntityManagerInterface::class);
$center = $centerRepository->findOneBy(['name' => 'Center A']);
$gender = new Gender();
$gender->setGenderTranslation(GenderEnum::MALE);
$gender->setLabel(['fr' => 'homme']);
$gender->setIcon(GenderIconEnum::MALE);
$em->persist($gender);
$person = new Person();
$person
->setFirstName('Foo')
->setLastName('Bar')
->setBirthdate(new \DateTime('2017-09-30'))
->setGender(Person::MALE_GENDER)
->setGender($gender)
->setCenter($center);
$em->persist($person);

View File

@@ -41,13 +41,13 @@ final class GenderFilterTest extends AbstractFilterTest
{
return [
[
'accepted_genders' => [Person::FEMALE_GENDER],
'accepted_genders' => ['man'],
],
[
'accepted_genders' => [Person::MALE_GENDER],
'accepted_genders' => ['woman'],
],
[
'accepted_genders' => [Person::MALE_GENDER, Person::BOTH_GENDER],
'accepted_genders' => ['man', 'both'],
],
];
}

View File

@@ -257,7 +257,7 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
$personDocGenNormalizer = new PersonDocGenNormalizer(
$personRender ?? self::getContainer()->get(PersonRender::class),
$relationshipRepository ?? self::getContainer()->get(RelationshipRepository::class),
$translator ?? self::getContainer()->get(TranslatorInterface::class),
// $translator ?? self::getContainer()->get(TranslatorInterface::class),
$translatableStringHelper ?? self::getContainer()->get(TranslatableStringHelperInterface::class),
$summaryBudget->reveal(),
);
@@ -299,7 +299,7 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
$normalizer = new PersonDocGenNormalizer(
$personRender ?? self::getContainer()->get(PersonRender::class),
$relationshipRepository,
$translator ?? self::getContainer()->get(TranslatorInterface::class),
// $translator ?? self::getContainer()->get(TranslatorInterface::class),
$translatableStringHelper ?? self::getContainer()->get(TranslatableStringHelperInterface::class),
$summaryBudget->reveal()
);

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\Person;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20240926100337 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add foreign key gender property to person and transfer values';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_person_person ADD gender_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_person_person ADD CONSTRAINT FK_BF210A14708A0E0 FOREIGN KEY (gender_id) REFERENCES chill_main_gender (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_BF210A14708A0E0 ON chill_person_person (gender_id)');
// transfer gender values to point to corresponding gender entity within new column
$this->addSql("
UPDATE chill_person_person AS p
SET gender_id = g.id
FROM chill_main_gender AS g
WHERE g.genderTranslation = p.gender AND p.gender IN ('man', 'woman', 'unknown')
OR (g.genderTranslation = 'neutral' AND p.gender = 'both')
");
// delete old gender column
$this->addSql('ALTER TABLE chill_person_person DROP gender');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_person_person ADD gender VARCHAR(9) DEFAULT NULL');
$this->addSql('ALTER TABLE chill_person_person DROP gender_id');
}
}

View File

@@ -2,6 +2,7 @@ Born the date: >-
{gender, select,
man {Né le {birthdate}}
woman {Née le {birthdate}}
neutral {Né·e le {birthdate}}
other {Né·e le {birthdate}}
}
@@ -9,17 +10,18 @@ Requestor: >-
{gender, select,
man {Demandeur}
woman {Demandeuse}
other {Demandeur·euse}
neutral {Demandeur·euse}
}
person:
and_himself: >-
from_the: depuis le
And himself: >-
{gender, select,
man {et lui-même}
woman {et elle-même}
neutral {et lui·elle-même}
other {et lui·elle-même}
}
from_the: depuis le
household:
Household: Ménage

View File

@@ -64,6 +64,7 @@ Female: Femme
#Both: Neutre
man: Homme
woman: Femme
neutral: Neutre
#both: Neutre
Man: Homme
Woman: Femme
@@ -1192,6 +1193,8 @@ export:
date_after: Après le
date_before: Avant le
title: Filtrer les usagers n'ayant été associés à aucun parcours
gender:
no_gender: genre non specifié
course:
not_having_address_reference: