ChillPersonBundle: add employmentStatus property to Person

This commit is contained in:
Christophe Siraut 2024-11-21 10:08:52 +01:00
parent 1f96f76f87
commit 110db30748
17 changed files with 441 additions and 4 deletions

View File

@ -0,0 +1,26 @@
<?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\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class EmploymentStatusController extends CRUDController
{
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$query->addOrderBy('e.order', 'ASC');
return parent::orderQuery($action, $query, $request, $paginator);
}
}

View File

@ -0,0 +1,45 @@
<?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\DataFixtures\ORM;
use Chill\PersonBundle\Entity\EmploymentStatus;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Persistence\ObjectManager;
class LoadEmploymentStatus extends Fixture implements FixtureGroupInterface
{
public static function getGroups(): array
{
return ['employment_status'];
}
public function load(ObjectManager $manager): void
{
$status = [
['name' => ['fr' => 'Salarié·e']],
['name' => ['fr' => 'Indépendant·e']],
['name' => ['fr' => 'Chômeur·euse']],
['name' => ['fr' => 'Bénéficiaire du CPAS']],
['name' => ['fr' => 'Pensionsé·e']],
];
foreach ($status as $val) {
$employmentStatus = (new EmploymentStatus())
->setName($val['name'])
->setActive(true);
$manager->persist($employmentStatus);
}
$manager->flush();
}
}

View File

@ -15,10 +15,13 @@ use Chill\MainBundle\DependencyInjection\MissingBundleException;
use Chill\MainBundle\Security\Authorization\ChillExportVoter; use Chill\MainBundle\Security\Authorization\ChillExportVoter;
use Chill\PersonBundle\Controller\AccompanyingPeriodCommentApiController; use Chill\PersonBundle\Controller\AccompanyingPeriodCommentApiController;
use Chill\PersonBundle\Controller\AccompanyingPeriodResourceApiController; use Chill\PersonBundle\Controller\AccompanyingPeriodResourceApiController;
use Chill\PersonBundle\Controller\EmploymentStatusController;
use Chill\PersonBundle\Controller\HouseholdCompositionTypeApiController; use Chill\PersonBundle\Controller\HouseholdCompositionTypeApiController;
use Chill\PersonBundle\Controller\RelationApiController; use Chill\PersonBundle\Controller\RelationApiController;
use Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\EmploymentStatus;
use Chill\PersonBundle\Form\EmploymentStatusType;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
@ -192,6 +195,28 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
], ],
], ],
], ],
[
'class' => EmploymentStatus::class,
'name' => 'employment_status',
'base_path' => '/admin/employment',
'base_role' => 'ROLE_ADMIN',
'form_class' => EmploymentStatusType::class,
'controller' => EmploymentStatusController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillPerson/EmploymentStatus/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillPerson/EmploymentStatus/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillPerson/EmploymentStatus/edit.html.twig',
],
],
],
[ [
'class' => \Chill\PersonBundle\Entity\MaritalStatus::class, 'class' => \Chill\PersonBundle\Entity\MaritalStatus::class,
'name' => 'person_marital-status', 'name' => 'person_marital-status',

View File

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

View File

@ -0,0 +1,80 @@
<?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\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
#[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['chill_person_employment_status' => EmploymentStatus::class])]
#[ORM\Entity]
#[ORM\Table(name: 'chill_person_employment_status')]
class EmploymentStatus
{
#[Serializer\Groups(['read', 'docgen:read'])]
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
private ?int $id = null;
#[Serializer\Groups(['read', 'docgen:read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
#[Serializer\Context(['is-translatable' => true], groups: ['docgen:read'])]
private array $name = [];
#[Serializer\Groups(['read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
private bool $active = true;
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::FLOAT, name: 'ordering', nullable: true, options: ['default' => '0.0'])]
private float $order = 0;
public function getId(): ?int
{
return $this->id;
}
public function getActive(): ?bool
{
return $this->active;
}
public function getName(): ?array
{
return $this->name;
}
public function getOrder(): ?float
{
return $this->order;
}
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
public function setOrder(float $order): self
{
$this->order = $order;
return $this;
}
}

View File

@ -311,6 +311,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
#[PhonenumberConstraint(type: 'mobile')] #[PhonenumberConstraint(type: 'mobile')]
private ?PhoneNumber $mobilenumber = null; private ?PhoneNumber $mobilenumber = null;
/**
* The person's professional status.
*/
#[ORM\ManyToOne(targetEntity: EmploymentStatus::class)]
#[ORM\JoinColumn(nullable: true)]
private ?EmploymentStatus $employmentStatus = null;
/** /**
* The person's nationality. * The person's nationality.
*/ */
@ -1033,6 +1040,11 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->fullnameCanonical; return $this->fullnameCanonical;
} }
public function getEmploymentStatus(): ?EmploymentStatus
{
return $this->employmentStatus;
}
public function getGender(): ?Gender public function getGender(): ?Gender
{ {
return $this->gender; return $this->gender;
@ -1551,6 +1563,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this; return $this;
} }
public function setEmploymentStatus(?EmploymentStatus $employmentStatus): self
{
$this->employmentStatus = $employmentStatus;
return $this;
}
public function setGenderComment(CommentEmbeddable $genderComment): self public function setGenderComment(CommentEmbeddable $genderComment): self
{ {
$this->genderComment = $genderComment; $this->genderComment = $genderComment;

View File

@ -0,0 +1,44 @@
<?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;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Chill\PersonBundle\Entity\EmploymentStatus;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class EmploymentStatusType extends \Symfony\Component\Form\AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TranslatableStringFormType::class, [
'required' => true,
])
->add('active', ChoiceType::class, [
'choices' => [
'Active' => true,
'Inactive' => false,
],
])
->add('order', NumberType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => EmploymentStatus::class,
]);
}
}

View File

@ -26,6 +26,7 @@ use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonPhone; use Chill\PersonBundle\Entity\PersonPhone;
use Chill\PersonBundle\Form\Type\PersonAltNameType; use Chill\PersonBundle\Form\Type\PersonAltNameType;
use Chill\PersonBundle\Form\Type\PersonPhoneType; use Chill\PersonBundle\Form\Type\PersonPhoneType;
use Chill\PersonBundle\Form\Type\PickEmploymentStatusType;
use Chill\PersonBundle\Form\Type\PickGenderType; use Chill\PersonBundle\Form\Type\PickGenderType;
use Chill\PersonBundle\Form\Type\Select2MaritalStatusType; use Chill\PersonBundle\Form\Type\Select2MaritalStatusType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
@ -102,6 +103,11 @@ class PersonType extends AbstractType
->add('memo', ChillTextareaType::class, ['required' => false]); ->add('memo', ChillTextareaType::class, ['required' => false]);
} }
if ('visible' === $this->config['employment_status']) {
$builder
->add('employmentStatus', PickEmploymentStatusType::class, ['required' => false]);
}
if ('visible' === $this->config['place_of_birth']) { if ('visible' === $this->config['place_of_birth']) {
$builder->add('placeOfBirth', TextType::class, [ $builder->add('placeOfBirth', TextType::class, [
'required' => false, 'required' => false,

View File

@ -0,0 +1,50 @@
<?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 Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\EmploymentStatus;
class PickEmploymentStatusType extends AbstractType
{
public function __construct(
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('label', 'Employment status')
->setDefault(
'choice_label',
fn (EmploymentStatus $employmentStatus): string => $this->translatableStringHelper->localize($employmentStatus->getName())
)
->setDefault(
'query_builder',
static fn (EntityRepository $er): QueryBuilder => $er->createQueryBuilder('c')
->where('c.active = true')
->orderBy('c.order'),
)
->setDefault('placeholder', $this->translatableStringHelper->localize(['Select an option…']))
->setDefault('class', EmploymentStatus::class);
}
public function getParent()
{
return EntityType::class;
}
}

View File

@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem; use Knp\Menu\MenuItem;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class AdminPersonMenuBuilder implements LocalMenuBuilderInterface class AdminPersonMenuBuilder implements LocalMenuBuilderInterface
@ -22,9 +23,14 @@ class AdminPersonMenuBuilder implements LocalMenuBuilderInterface
*/ */
protected $authorizationChecker; protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker) private array $fields_visibility;
{
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
ParameterBagInterface $parameterBag,
) {
$this->authorizationChecker = $authorizationChecker; $this->authorizationChecker = $authorizationChecker;
$this->fields_visibility = $parameterBag->get('chill_person.person_fields');
} }
public function buildMenu($menuId, MenuItem $menu, array $parameters) public function buildMenu($menuId, MenuItem $menu, array $parameters)
@ -53,6 +59,12 @@ class AdminPersonMenuBuilder implements LocalMenuBuilderInterface
'route' => 'chill_crud_person_marital-status_index', 'route' => 'chill_crud_person_marital-status_index',
])->setExtras(['order' => 2030]); ])->setExtras(['order' => 2030]);
if ('visible' == $this->fields_visibility['employment_status']) {
$menu->addChild('Employment status', [
'route' => 'chill_crud_employment_status_index',
])->setExtras(['order' => 2035]);
}
$menu->addChild('person_admin.person_resource_kind', [ $menu->addChild('person_admin.person_resource_kind', [
'route' => 'chill_crud_person_resource-kind_index', 'route' => 'chill_crud_person_resource-kind_index',
])->setExtras(['order' => 2040]); ])->setExtras(['order' => 2040]);

View File

@ -0,0 +1,11 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock admin_content %}

View File

@ -0,0 +1,42 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block table_entities_thead_tr %}
<th>id</th>
<th>{{ 'name'|trans }}</th>
<th>{{ 'active'|trans }}</th>
<th>{{ 'ordering'|trans }}</th>
<th></th>
{% endblock %}
{% block table_entities_tbody %}
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.name|localize_translatable_string }}</td>
<td style="text-align:center;">
{%- if entity.active -%}
<i class="fa fa-check-square-o"></i>
{%- else -%}
<i class="fa fa-square-o"></i>
{%- endif -%}
</td>
<td>{{ entity.order }}</td>
<td>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_crud_employment_status_edit', { 'id': entity.id}) }}" class="btn btn-sm btn-edit btn-mini"></a>
</li>
</ul>
</td>
</tr>
{% endfor %}
{% endblock %}
{% block actions_before %}
<li class='cancel'>
<a href="{{ path('chill_main_admin_central') }}" class="btn btn-cancel">{{'Back to the admin'|trans}}</a>
</li>
{% endblock %}
{% endembed %}
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock admin_content %}

View File

@ -107,6 +107,9 @@
{%- if form.spokenLanguages is defined -%} {%- if form.spokenLanguages is defined -%}
{{ form_row(form.spokenLanguages, {'label' : 'Spoken languages'}) }} {{ form_row(form.spokenLanguages, {'label' : 'Spoken languages'}) }}
{%- endif -%} {%- endif -%}
{%- if form.employmentStatus is defined -%}
{{ form_row(form.employmentStatus, {'label' : 'Employment status'}) }}
{%- endif -%}
</fieldset> </fieldset>
{%- endif -%} {%- endif -%}

View File

@ -170,6 +170,18 @@ This view should receive those arguments:
</dd> </dd>
</dl> </dl>
{%- endif -%} {%- endif -%}
<dl>
{% if chill_person.fields.employment_status == 'visible' %}
<dt>{{ 'Employment status'|trans }}&nbsp;:</dt>
<dd>
{% if person.employmentStatus is not empty %}
{{ person.employmentStatus.name|localize_translatable_string }}
{% else %}
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
{% endif %}
</dd>
{% endif %}
</dl>
{%- if chill_person.fields.number_of_children == 'visible' -%} {%- if chill_person.fields.number_of_children == 'visible' -%}
<dl> <dl>
<dt>{{'Number of children'|trans}}&nbsp;:</dt> <dt>{{'Number of children'|trans}}&nbsp;:</dt>
@ -195,8 +207,8 @@ This view should receive those arguments:
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span> <span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
{% endif %} {% endif %}
</dd> </dd>
<dt>{{ 'Comment on the marital status'|trans }}&nbsp;:</dt> <dt>{{ 'Comment on the marital status'|trans }}&nbsp;:</dt>
<dd> <dd>
{% if person.maritalStatusComment.comment is not empty %} {% if person.maritalStatusComment.comment is not empty %}
<blockquote class="chill-user-quote"> <blockquote class="chill-user-quote">

View File

@ -0,0 +1,43 @@
<?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;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241121080214 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add employment status';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE SEQUENCE chill_person_employment_status_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_person_employment_status (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, ordering DOUBLE PRECISION DEFAULT \'0.0\', PRIMARY KEY(id))');
$this->addSql('ALTER TABLE chill_person_person ADD employmentstatus_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_person_person ADD CONSTRAINT FK_BF210A14BAE6AEE2 FOREIGN KEY (employmentstatus_id) REFERENCES chill_person_employment_status (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX BF210A14BAE6AEE2 ON chill_person_person (employmentstatus_id)');
}
public function down(Schema $schema): void
{
$this->addSql('DROP SEQUENCE chill_person_employment_status_id_seq CASCADE');
$this->addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A14BAE6AEE2');
$this->addSql('ALTER TABLE chill_person_person DROP employmentstatus_id');
$this->addSql('DROP TABLE chill_person_employment_status');
}
}

View File

@ -1,4 +1,5 @@
Edit: Modifier Edit: Modifier
Select an option…: Choisissez une option…
'First name': Prénom 'First name': Prénom
firstname: prénom firstname: prénom
firstName: prénom firstName: prénom
@ -98,7 +99,7 @@ memo: Commentaire
numberOfChildren: Nombre d'enfants numberOfChildren: Nombre d'enfants
contactInfo: Commentaire des contacts contactInfo: Commentaire des contacts
spokenLanguages: Langues parlées spokenLanguages: Langues parlées
Employment status: Situation professionelle
# dédoublonnage # dédoublonnage
@ -653,6 +654,12 @@ crud:
add_new: Ajouter un nouveau add_new: Ajouter un nouveau
title_new: Nouveau motif de clotûre title_new: Nouveau motif de clotûre
title_edit: Modifier le motif de clotûre title_edit: Modifier le motif de clotûre
employment_status:
index:
title: Situations professionelles
add_new: Ajouter une nouvelle
title_new: Ajouter une situation professionelle
title_edit: Modifier cette situation professionelle
origin: origin:
index: index:
title: Liste des origines de parcours title: Liste des origines de parcours