Compare commits

...

76 Commits

Author SHA1 Message Date
635b1ee537 merge upgrade-sf5 branch to have latest fixes 2024-06-06 13:01:12 +02:00
3fd6e52e9d remove unnecessary constraints from 3party properties acronym and nameCompany 2024-05-29 11:37:42 +02:00
f60a595ab6 Update vue toast version and implementation 2024-05-29 11:37:04 +02:00
436ef33dbc final fix for appellation selector: define metier when appellation already exists 2024-05-23 14:05:14 +02:00
405aad7333 fix rome appellation selector and admin 2024-05-23 13:47:33 +02:00
a5c2576124 Fix the appellation selection for projet professional 2024-05-23 12:46:12 +02:00
33a6f9996e remove dumps 2024-05-22 21:02:17 +02:00
b96cbc5594 rector fixes 2024-05-22 17:13:27 +02:00
854d72fa42 php cs fixes 2024-05-22 17:12:49 +02:00
cd6fd091dc resolve merge conflicts 2024-05-22 16:57:28 +02:00
cb5ade3d14 add changie for module emploi 2024-05-22 16:49:45 +02:00
dddb6d66bc php cs fixes after merge 2024-05-22 16:44:02 +02:00
d34f9450b8 Merge branch 'add-module-emploi' of gitlab.com:Chill-Projet/chill-bundles into add-module-emploi 2024-05-22 16:43:02 +02:00
9ce1788a14 phpstan en rector fixes 2024-05-22 16:42:47 +02:00
2895638f3b php cs fixes 2024-05-22 15:26:23 +02:00
2708bafb1f Export for list person with cs_person columns fixed 2024-05-22 15:24:39 +02:00
7d309136b1 minor last fixes for immersion and remove of dumps 2024-05-22 08:53:56 +02:00
82d3ec4d6f Merge branch 'add-module-emploi' of gitlab.com:Chill-Projet/chill-bundles into add-module-emploi 2024-05-22 08:40:46 +02:00
cad2dea148 Wip: add jsonb fields to export 2024-05-16 09:26:40 +02:00
bff14aa700 minor last fixes for immersion and remove of dumps 2024-05-15 16:02:14 +02:00
66570cd430 merge add-module-emploi into testing 2024-05-15 15:19:24 +02:00
53df2ec9ba Merge branch 'master' into testing-2024-03 2024-05-15 15:17:49 +02:00
068503a830 Merge branch 'master' into add-module-emploi 2024-05-15 14:36:36 +02:00
c07a728f1d Wip: add jsonb fields to export 2024-05-15 14:35:51 +02:00
b7e61c6747 merge master into module emploi branch 2024-05-15 14:26:51 +02:00
97846a5877 add basic fields csperson to list person export 2024-05-14 11:01:45 +02:00
4ed9d3d8e2 Fix API call 2024-05-14 07:49:48 +02:00
d82d534a4c Try to fix API: adjust to new urls, but still receiving error code 400 2024-05-07 11:15:10 +02:00
684f28291a reinstate exports 2024-05-07 11:14:39 +02:00
526882a5b6 phpstan, rector and cs fixes 2024-04-29 15:39:05 +02:00
422b6b99eb Change translation for the group of voter rights 2024-04-29 15:28:13 +02:00
02b150b0a5 fix delete of reports in crud config + template 2024-04-29 15:25:15 +02:00
20c27c100c Name change from CSConnecte to Job 2024-04-29 15:20:23 +02:00
12a22bcc13 template + form + property fixes for emploi reports 2024-04-29 14:13:37 +02:00
cba8a342d5 more template fixes 2024-04-24 18:02:06 +02:00
6f55ba15d6 Split crud controllers for each report entity 2024-04-24 17:40:31 +02:00
454ab73303 WIP fix emploi reports 2024-04-24 17:11:26 +02:00
800942bc92 Add missing columns to report tables 2024-04-24 17:10:30 +02:00
c4e7683e48 fix templates for personal situation 2024-04-24 15:02:24 +02:00
28c986fddf controller with crud logic + templates fixed for dispositif 2024-04-24 14:52:19 +02:00
adca4f0d6a php cs fixes 2024-04-24 12:28:55 +02:00
7b25c8e390 New migration to take care of everything needed for ChillJobBundle 2024-04-24 12:27:49 +02:00
0b5be0419b Move old migrations to directory 'old' just in case 2024-04-24 12:27:23 +02:00
650e85c481 Fix crudconfig 2024-04-24 11:44:14 +02:00
56d5d08ed3 Run rector on ListCSPerson file 2024-04-24 11:34:06 +02:00
d3390ca334 Phpstan error for unused parameter fixed 2024-04-24 10:49:19 +02:00
511c0af5fa Last php cs fix 2024-04-24 10:40:09 +02:00
4c354c47c9 Fix construct method for ListCSPerson 2024-04-24 10:39:46 +02:00
d8b6cef7b4 rector fixes 2024-04-24 10:18:07 +02:00
e312929d86 php cs fixes 2024-04-24 10:16:54 +02:00
20b38af812 Create phpstan baseline for level 5 taking into account new bundles 2024-04-24 10:16:16 +02:00
2f07be0843 Revert "adjust phpstan baselines"
This reverts commit a71573136a.
2024-04-24 10:11:02 +02:00
11c069a2ff Revert "phpstan baseline 5 updated"
This reverts commit deaab80270.
2024-04-24 10:10:55 +02:00
3929602f59 Revert "php style fixes"
This reverts commit 38fcccfd83.
2024-04-24 10:09:25 +02:00
38fcccfd83 php style fixes 2024-04-23 21:22:29 +02:00
deaab80270 phpstan baseline 5 updated 2024-04-23 21:22:19 +02:00
a71573136a adjust phpstan baselines 2024-04-23 21:12:57 +02:00
b1082f6a55 fix phpstan errors level 3 2024-04-23 21:03:42 +02:00
dcc285e976 fix phpstan errors level 2 2024-04-23 20:52:22 +02:00
ed3e0f889e Rector changes + namespace changes 2024-04-23 17:43:23 +02:00
63fe8070c4 Rector passed again on JobBundle entities 2024-04-19 11:30:47 +02:00
8e3322f578 rector rules for upgrade to php 8.2 and symfony 5.4 applied + php cs fixer 2024-04-19 10:56:49 +02:00
00756a3bde Move migrations directory to src 2024-04-19 10:33:40 +02:00
2c68224e9c Add jobBundle and FranceTravailApiBundle 2024-04-19 10:21:17 +02:00
166d7fe0b0 Merge branch 'master' into testing-2024-03 2024-03-26 22:14:51 +01:00
ab9d5439c1 Release 2.18.1 2024-03-26 22:08:30 +01:00
0737838dd6 Fix layout in admin document generation
A layout issue in the admin document generation has been fixed, particularly in the ChillDocGeneratorBundle. Unnecessary elements such as table headers and multiple entity data rows in DocGeneratorTemplate have been removed, simplifying the view page and improving its performance.
2024-03-26 22:08:01 +01:00
88bac5b5d8 Merge remote-tracking branch 'origin/145-permettre-de-visualiser-les-documents-dans-libreoffice-en-utilisant-webdav' into testing-2024-03 2024-03-26 21:34:15 +01:00
cf1df462dc optional parameter after the required one 2024-01-15 21:18:51 +01:00
a0328b9d68 Apply new CS rules on the webdav feature 2024-01-15 20:38:03 +01:00
813a80d6f9 Dav: add UI to edit document 2024-01-15 20:22:14 +01:00
ab95bb157e Dav: add some documentation on classes 2024-01-15 20:19:03 +01:00
18fd1dbc4a Dav: Introduce access control inside de dav controller 2024-01-15 20:19:03 +01:00
a35f7656cb Dav: refactor WebdavController 2024-01-15 20:19:03 +01:00
ff05f9f48a Dav: implements JWT extraction from the URL, and add the access_token in dav urls 2024-01-15 20:19:02 +01:00
482c494034 Webdav: fully implements the controller and response
The controller is tested from real request scraped from apache mod_dav implementation. The requests were scraped using a wireshark-like tool. Those requests have been adapted to suit to our xml.
2024-01-15 20:19:02 +01:00
162 changed files with 12554 additions and 155 deletions

View File

@@ -0,0 +1,5 @@
kind: Feature
body: Add job bundle (module emploi)
time: 2024-05-22T16:49:33.730465146+02:00
custom:
Issue: ""

View File

@@ -115,6 +115,8 @@
"Chill\\DocGeneratorBundle\\": "src/Bundle/ChillDocGeneratorBundle",
"Chill\\DocStoreBundle\\": "src/Bundle/ChillDocStoreBundle",
"Chill\\EventBundle\\": "src/Bundle/ChillEventBundle",
"Chill\\FranceTravailApiBundle\\": "src/Bundle/ChillFranceTravailApiBundle/src",
"Chill\\JobBundle\\": "src/Bundle/ChillJobBundle/src",
"Chill\\MainBundle\\": "src/Bundle/ChillMainBundle",
"Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle",
"Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle",

View File

@@ -21,7 +21,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
class BirthdateFilter implements ExportElementValidatedInterface, FilterInterface
{
// add specific role for this filter
public function addRole()
public function addRole(): ?string
{
// we do not need any new role for this filter, so we return null
return null;

View File

@@ -27,7 +27,7 @@
"popper.js": "^1.16.1",
"postcss-loader": "^7.0.2",
"raw-loader": "^4.0.2",
"sass-loader": "^13.0.0",
"sass-loader": "^14.0.0",
"select2": "^4.0.13",
"select2-bootstrap-theme": "0.1.0-beta.10",
"style-loader": "^3.3.1",
@@ -56,7 +56,7 @@
"vue": "^3.2.37",
"vue-i18n": "^9.1.6",
"vue-multiselect": "3.0.0-alpha.2",
"vue-toast-notification": "^2.0",
"vue-toast-notification": "^3.1.2",
"vuex": "^4.0.0"
},
"browserslist": [

View File

@@ -1,34 +1,29 @@
parameters:
ignoreErrors:
-
message: "#^Foreach overwrites \\$key with its key variable\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
message: "#^Property Chill\\\\CustomFieldsBundle\\\\Entity\\\\CustomField\\:\\:\\$required \\(false\\) does not accept bool\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/PersonType.php
path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
message: "#^Parameter \\#1 \\$user of method Chill\\\\DocStoreBundle\\\\Entity\\\\Document\\:\\:setUser\\(\\) expects Chill\\\\MainBundle\\\\Entity\\\\User\\|null, Symfony\\\\Component\\\\Security\\\\Core\\\\User\\\\UserInterface\\|null given\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Repository/NotificationRepository.php
path: src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php
-
message: "#^Foreach overwrites \\$key with its key variable\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php
message: "#^Parameter \\#1 \\$user of method Chill\\\\DocStoreBundle\\\\Entity\\\\Document\\:\\:setUser\\(\\) expects Chill\\\\MainBundle\\\\Entity\\\\User\\|null, Symfony\\\\Component\\\\Security\\\\Core\\\\User\\\\UserInterface\\|null given\\.$#"
count: 2
path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php
-
message: "#^Variable \\$participation might not be defined\\.$#"
@@ -40,6 +35,106 @@ parameters:
count: 1
path: src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php
-
message: "#^Comparison operation \"\\>\" between \\(bool\\|int\\|Redis\\) and 0 results in an error\\.$#"
count: 1
path: src/Bundle/ChillFranceTravailApiBundle/src/ApiHelper/ApiWrapper.php
-
message: "#^Variable \\$response might not be defined\\.$#"
count: 1
path: src/Bundle/ChillFranceTravailApiBundle/src/ApiHelper/ApiWrapper.php
-
message: "#^Function GuzzleHttp\\\\Psr7\\\\get not found\\.$#"
count: 1
path: src/Bundle/ChillFranceTravailApiBundle/src/ApiHelper/PartenaireRomeAppellation.php
-
message: "#^Function GuzzleHttp\\\\Psr7\\\\str not found\\.$#"
count: 2
path: src/Bundle/ChillFranceTravailApiBundle/src/ApiHelper/PartenaireRomeAppellation.php
-
message: "#^Parameter \\#1 \\$seconds of function sleep expects int, string given\\.$#"
count: 1
path: src/Bundle/ChillFranceTravailApiBundle/src/ApiHelper/PartenaireRomeAppellation.php
-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Controller/CSPersonController.php
-
message: "#^Parameter \\#1 \\$interval of method DateTimeImmutable\\:\\:add\\(\\) expects DateInterval, string\\|null given\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Entity/Immersion.php
-
message: "#^Parameter \\#1 \\$object of static method DateTimeImmutable\\:\\:createFromMutable\\(\\) expects DateTime, DateTimeInterface given\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Entity/Immersion.php
-
message: "#^Property Chill\\\\JobBundle\\\\Entity\\\\Rome\\\\Metier\\:\\:\\$appellations is never read, only written\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Entity/Rome/Metier.php
-
message: "#^Method Chill\\\\JobBundle\\\\Export\\\\ListCSPerson\\:\\:splitArrayToColumns\\(\\) never returns Closure so it can be removed from the return type\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Export/ListCSPerson.php
-
message: "#^Variable \\$f might not be defined\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Export/ListCSPerson.php
-
message: "#^Method Chill\\\\JobBundle\\\\Export\\\\ListFrein\\:\\:splitArrayToColumns\\(\\) never returns Closure so it can be removed from the return type\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Export/ListFrein.php
-
message: "#^Method Chill\\\\JobBundle\\\\Export\\\\ListProjetProfessionnel\\:\\:splitArrayToColumns\\(\\) never returns Closure so it can be removed from the return type\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Export/ListProjetProfessionnel.php
-
message: "#^Property Chill\\\\JobBundle\\\\Form\\\\ChoiceLoader\\\\RomeAppellationChoiceLoader\\:\\:\\$appellationRepository \\(Chill\\\\JobBundle\\\\Repository\\\\Rome\\\\AppellationRepository\\) does not accept Doctrine\\\\ORM\\\\EntityRepository\\<Chill\\\\JobBundle\\\\Entity\\\\Rome\\\\Appellation\\>\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Form/ChoiceLoader/RomeAppellationChoiceLoader.php
-
message: "#^Result of && is always false\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Form/ChoiceLoader/RomeAppellationChoiceLoader.php
-
message: "#^Strict comparison using \\=\\=\\= between array\\{\\} and Symfony\\\\Component\\\\Validator\\\\ConstraintViolationListInterface will always evaluate to false\\.$#"
count: 2
path: src/Bundle/ChillJobBundle/src/Form/ChoiceLoader/RomeAppellationChoiceLoader.php
-
message: "#^Strict comparison using \\=\\=\\= between null and string will always evaluate to false\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Form/ChoiceLoader/RomeAppellationChoiceLoader.php
-
message: "#^Variable \\$metier might not be defined\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Form/ChoiceLoader/RomeAppellationChoiceLoader.php
-
message: "#^Parameter \\#1 \\$interval of method DateTimeImmutable\\:\\:add\\(\\) expects DateInterval, string\\|null given\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Security/Authorization/CSConnectesVoter.php
-
message: "#^Parameter \\#1 \\$object of static method DateTimeImmutable\\:\\:createFromMutable\\(\\) expects DateTime, DateTimeInterface given\\.$#"
count: 1
path: src/Bundle/ChillJobBundle/src/Security/Authorization/CSConnectesVoter.php
-
message: "#^Cannot unset offset '_token' on array\\{formatter\\: mixed, export\\: mixed, centers\\: mixed, alias\\: string\\}\\.$#"
count: 1
@@ -65,11 +160,31 @@ parameters:
count: 1
path: src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Repository/NotificationRepository.php
-
message: "#^Parameter \\#1 \\$user of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\:\\:userHasAccessForCenter\\(\\) expects Chill\\\\MainBundle\\\\Entity\\\\User, Symfony\\\\Component\\\\Security\\\\Core\\\\User\\\\UserInterface given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php
-
message: "#^Foreach overwrites \\$value with its value variable\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/PersonType.php
-
message: "#^Foreach overwrites \\$value with its value variable\\.$#"
count: 1

View File

@@ -28,6 +28,9 @@ return static function (RectorConfig $rectorConfig): void {
// register a single rule
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
$rectorConfig->rule(Rector\TypeDeclaration\Rector\ClassMethod\AddParamTypeFromPropertyTypeRector::class);
$rectorConfig->rule(Rector\TypeDeclaration\Rector\Class_\MergeDateTimePropertyTypeDeclarationRector::class);
$rectorConfig->rule(Rector\TypeDeclaration\Rector\ClassMethod\AddReturnTypeDeclarationBasedOnParentClassMethodRector::class);
// part of the symfony 54 rules
$rectorConfig->rule(\Rector\Symfony\Symfony53\Rector\StaticPropertyFetch\KernelTestCaseContainerPropertyDeprecationRector::class);
@@ -36,12 +39,8 @@ return static function (RectorConfig $rectorConfig): void {
//define sets of rules
$rectorConfig->sets([
\Rector\Symfony\Set\SymfonySetList::SYMFONY_50,
\Rector\Symfony\Set\SymfonySetList::SYMFONY_50_TYPES,
\Rector\Symfony\Set\SymfonySetList::SYMFONY_51,
\Rector\Symfony\Set\SymfonySetList::SYMFONY_52,
\Rector\Symfony\Set\SymfonySetList::SYMFONY_53,
\Rector\Symfony\Set\SymfonySetList::SYMFONY_54,
\Rector\Set\ValueObject\LevelSetList::UP_TO_PHP_82,
\Rector\Symfony\Set\SymfonyLevelSetList::UP_TO_SYMFONY_54,
\Rector\Doctrine\Set\DoctrineSetList::DOCTRINE_CODE_QUALITY,
\Rector\Doctrine\Set\DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
]);

View File

@@ -79,11 +79,9 @@ class ActivityReason
/**
* Set active.
*
* @param bool $active
*
* @return ActivityReason
*/
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;
@@ -110,11 +108,9 @@ class ActivityReason
/**
* Set name.
*
* @param array $name
*
* @return ActivityReason
*/
public function setName($name)
public function setName(array $name)
{
$this->name = $name;

View File

@@ -100,7 +100,7 @@ class Charge extends AbstractElement implements HasCentersInterface
return $this;
}
public function setHelp($help)
public function setHelp(?string $help)
{
$this->help = $help;

View File

@@ -172,11 +172,9 @@ class CustomField
/**
* Set active.
*
* @param bool $active
*
* @return CustomField
*/
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;
@@ -224,18 +222,16 @@ class CustomField
/**
* Set order.
*
* @param float $order
*
* @return CustomField
*/
public function setOrdering($order)
public function setOrdering(?float $order)
{
$this->ordering = $order;
return $this;
}
public function setRequired($required)
public function setRequired(bool $required)
{
$this->required = $required;
@@ -245,7 +241,7 @@ class CustomField
/**
* @return $this
*/
public function setSlug($slug)
public function setSlug(?string $slug)
{
$this->slug = $slug;
@@ -255,11 +251,9 @@ class CustomField
/**
* Set type.
*
* @param string $type
*
* @return CustomField
*/
public function setType($type)
public function setType(?string $type)
{
$this->type = $type;

View File

@@ -129,7 +129,7 @@ class Option
/**
* @return $this
*/
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;
@@ -139,7 +139,7 @@ class Option
/**
* @return $this
*/
public function setInternalKey($internal_key)
public function setInternalKey(string $internal_key)
{
$this->internalKey = $internal_key;
@@ -149,7 +149,7 @@ class Option
/**
* @return $this
*/
public function setKey($key)
public function setKey(?string $key)
{
$this->key = $key;

View File

@@ -69,7 +69,7 @@ class CustomFieldsDefaultGroup
*
* @return CustomFieldsDefaultGroup
*/
public function setCustomFieldsGroup($customFieldsGroup)
public function setCustomFieldsGroup(?CustomFieldsGroup $customFieldsGroup)
{
$this->customFieldsGroup = $customFieldsGroup;
@@ -79,11 +79,9 @@ class CustomFieldsDefaultGroup
/**
* Set entity.
*
* @param string $entity
*
* @return CustomFieldsDefaultGroup
*/
public function setEntity($entity)
public function setEntity(?string $entity)
{
$this->entity = $entity;

View File

@@ -165,11 +165,9 @@ class CustomFieldsGroup
/**
* Set entity.
*
* @param string $entity
*
* @return CustomFieldsGroup
*/
public function setEntity($entity)
public function setEntity(?string $entity)
{
$this->entity = $entity;

View File

@@ -129,7 +129,7 @@ class Document implements TrackCreationInterface, TrackUpdateInterface
return $this;
}
public function setUser($user): self
public function setUser(?\Chill\MainBundle\Entity\User $user): self
{
$this->user = $user;

View File

@@ -86,7 +86,7 @@ class DocumentCategory
return $this;
}
public function setDocumentClass($documentClass): self
public function setDocumentClass(?string $documentClass): self
{
$this->documentClass = $documentClass;

View File

@@ -55,14 +55,14 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt
return $this->scope;
}
public function setPerson($person): self
public function setPerson(Person $person): self
{
$this->person = $person;
return $this;
}
public function setScope($scope): self
public function setScope(?Scope $scope): self
{
$this->scope = $scope;

View File

@@ -418,7 +418,6 @@ final class EventController extends AbstractController
$builder->add('event_id', HiddenType::class, [
'data' => $event->getId(),
]);
dump($event->getId());
return $builder->getForm();
}

View File

@@ -47,7 +47,7 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
private ?Scope $circle = null;
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_MUTABLE)]
private ?\DateTime $date;
private ?\DateTime $date = null;
#[ORM\Id]
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
@@ -265,11 +265,9 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
/**
* Set label.
*
* @param string $label
*
* @return Event
*/
public function setName($label)
public function setName(?string $label)
{
$this->name = $label;

View File

@@ -146,11 +146,9 @@ class EventType
/**
* Set active.
*
* @param bool $active
*
* @return EventType
*/
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;

View File

@@ -81,11 +81,9 @@ class Role
/**
* Set active.
*
* @param bool $active
*
* @return Role
*/
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;

View File

@@ -81,11 +81,9 @@ class Status
/**
* Set active.
*
* @param bool $active
*
* @return Status
*/
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;

View File

@@ -0,0 +1,84 @@
<?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\FranceTravailApiBundle\ApiHelper;
use Chill\MainBundle\Redis\ChillRedis;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
/**
* Wraps the pole emploi api.
*/
class ApiWrapper
{
/**
* @var Client
*/
private $client;
/**
* key for the bearer for the api pole emploi.
*
* This bearer is shared across users
*/
public const UNPERSONAL_BEARER = 'api_pemploi_bear_';
public function __construct(private $clientId, private $clientSecret, private readonly ChillRedis $redis)
{
$this->client = new Client([
'base_uri' => 'https://entreprise.francetravail.fr/connexion/oauth2/access_token',
]);
}
public function getPublicBearer($scopes): string
{
$cacheKey = $this->getCacheKey($scopes);
if ($this->redis->exists($cacheKey) > 0) {
$data = \unserialize($this->redis->get($cacheKey));
return $data->access_token;
}
try {
$response = $this->client->post('', [
'query' => ['realm' => '/partenaire'],
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'form_params' => [
'grant_type' => 'client_credentials',
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'scope' => \implode(' ', \array_merge($scopes, ['application_'.$this->clientId])),
],
]);
} catch (ClientException $e) {
dump($e->getResponse());
}
$data = \json_decode((string) $response->getBody());
// set the key with an expiry time
$this->redis->setex(
$cacheKey,
$data->expires_in - 2,
\serialize($data)
);
return $data->access_token;
}
protected function getCacheKey($scopes)
{
return self::UNPERSONAL_BEARER.implode('', $scopes);
}
}

View File

@@ -0,0 +1,106 @@
<?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\FranceTravailApiBundle\ApiHelper;
use GuzzleHttp\Client;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
/**
* Queries for ROME partenaires api.
*/
class PartenaireRomeAppellation
{
use ProcessRequestTrait;
/**
* @var ApiWrapper
*/
protected $wrapper;
/**
* @var Client
*/
protected $client;
/**
* @var LoggerInterface
*/
protected $logger;
private const BASE = 'https://api.pole-emploi.io/partenaire/rome-metiers/v1/metiers/';
public function __construct(
ApiWrapper $wrapper,
LoggerInterface $logger,
private \Symfony\Contracts\HttpClient\HttpClientInterface $httpClient,
) {
$this->wrapper = $wrapper;
$this->logger = $logger;
$this->client = new Client([
'base_uri' => 'https://api.pole-emploi.io/partenaire/rome-metiers/v1/metiers/',
]);
}
private function getBearer()
{
return $this->wrapper->getPublicBearer([
'api_rome-metiersv1',
'nomenclatureRome',
]);
}
public function getListeAppellation(string $search): array
{
$bearer = $this->getBearer();
try {
$response = $this->httpClient->request(
'GET',
self::BASE.'appellation/requete',
[
'headers' => [
'Authorization' => 'Bearer '.$bearer,
'Accept' => 'application/json',
],
'query' => [
'q' => $search,
],
]
);
return $response->toArray()['resultats'];
} catch (HttpExceptionInterface $exception) {
throw $exception;
}
}
public function getAppellation(string $code): array
{
$bearer = $this->getBearer();
try {
$response = $this->httpClient->request('GET', sprintf(self::BASE.'appellation/%s', $code), [
'headers' => [
'Authorization' => 'Bearer '.$bearer,
'Accept' => 'application/json',
],
'query' => [
'champs' => 'code,libelle,metier(code,libelle)',
],
]);
return $response->toArray();
} catch (HttpExceptionInterface $exception) {
throw $exception;
}
}
}

View File

@@ -0,0 +1,100 @@
<?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\FranceTravailApiBundle\ApiHelper;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Psr7;
use Psr\Log\LoggerInterface;
/**
* Methods to process request against the api, and handle the
* Exceptions.
*/
trait ProcessRequestTrait
{
/**
* Handle a request and 429 errors.
*
* @param Request $request the request
* @param array $parameters the requests parameters
*/
protected function handleRequest(
Request $request,
array $parameters,
Client $client,
LoggerInterface $logger
) {
return $this->handleRequestRecursive(
$request,
$parameters,
$client,
$logger
);
}
/**
* internal method to handle recursive requests.
*
* @throws BadResponseException
*/
private function handleRequestRecursive(
Request $request,
array $parameters,
Client $client,
LoggerInterface $logger,
$counter = 0
) {
try {
return $client->send($request, $parameters);
} catch (BadResponseException $e) {
if (
// get 429 exceptions
$e instanceof ClientException
&& 429 === $e->getResponse()->getStatusCode()
&& count($e->getResponse()->getHeader('Retry-After')) > 0) {
if ($counter > 5) {
$logger->error('too much 429 response', [
'request' => Psr7\get($e->getRequest()),
]);
throw $e;
}
$delays = $e->getResponse()->getHeader('Retry-After');
$delay = \end($delays);
sleep($delay);
return $this->handleRequestRecursive(
$request,
$parameters,
$client,
$logger,
$counter + 1
);
}
// handling other errors
$logger->error('Error while querying ROME api', [
'status_code' => $e->getResponse()->getStatusCode(),
'part' => 'appellation',
'request' => $e->getRequest()->getBody()->getContents(),
'response' => $e->getResponse()->getBody()->getContents(),
]);
throw $e;
}
}
}

View File

@@ -0,0 +1,16 @@
<?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\FranceTravailApiBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillFranceTravailApiBundle extends Bundle {}

View File

@@ -0,0 +1,56 @@
<?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\FranceTravailApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
class RomeController extends AbstractController
{
/**
* @var PartenaireRomeAppellation
*/
protected $apiAppellation;
public function __construct(PartenaireRomeAppellation $apiAppellation)
{
$this->apiAppellation = $apiAppellation;
}
#[Route(path: '/{_locale}/france-travail/appellation/search.{_format}', name: 'chill_france_travail_api_appellation_search')]
public function appellationSearchAction(Request $request)
{
if (false === $request->query->has('q')) {
return new JsonResponse([]);
}
$appellations = $this->apiAppellation
->getListeAppellation($request->query->get('q'));
$results = [];
foreach ($appellations as $appellation) {
$appellation['id'] = 'original-'.$appellation['code'];
$appellation['text'] = $appellation['libelle'];
$results[] = $appellation;
}
$computed = new \stdClass();
$computed->pagination = (new \stdClass());
$computed->pagination->more = false;
$computed->results = $results;
return new JsonResponse($computed);
}
}

View File

@@ -0,0 +1,52 @@
<?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\FranceTravailApiBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration.
*
* @see http://symfony.com/doc/current/cookbook/bundles/extension.html
*/
class ChillFranceTravailApiExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
public function prepend(ContainerBuilder $container): void
{
$this->prependRoute($container);
}
protected function prependRoute(ContainerBuilder $container): void
{
// declare routes for france travail api bundle
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
'@ChillFranceTravailApiBundle/Resources/config/routing.yml',
],
],
]);
}
}

View File

@@ -0,0 +1,34 @@
<?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\FranceTravailApiBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files.
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_france_travail_api');
$rootNode = $treeBuilder->getRootNode();
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}

View File

@@ -0,0 +1,3 @@
chill_france_travail_api_controllers:
resource: "@ChillFranceTravailApiBundle/Controller"
type: annotation

View File

@@ -0,0 +1,16 @@
services:
_defaults:
autowire: true
autoconfigure: true
Chill\FranceTravailApiBundle\ApiHelper\ApiWrapper:
$clientId: '%env(FRANCE_TRAVAIL_CLIENT_ID)%'
$clientSecret: '%env(FRANCE_TRAVAIL_CLIENT_SECRET)%'
$redis: '@Chill\MainBundle\Redis\ChillRedis'
Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation: ~
Chill\FranceTravailApiBundle\Controller\RomeController:
autowire: true
autoconfigure: true
tags: ['controller.service_arguments']

View File

@@ -0,0 +1,93 @@
<?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\FranceTravailApiBundle\Tests\ApiHelper;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation;
/**
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*
* @internal
*
* @coversNothing
*/
class PartenaireRomeAppellationTest extends KernelTestCase
{
protected function setUp(): void
{
parent::setUp();
self::bootKernel();
}
public function testGetListeMetiersSimple()
{
/** @var PartenaireRomeAppellation $appellations */
$appellations = self::$kernel
->getContainer()
->get(PartenaireRomeAppellation::class)
;
$data = $appellations->getListeAppellation('arb');
$this->assertTrue(\is_array($data));
$this->assertNotNull($data[0]->libelle);
$this->assertNotNull($data[0]->code);
}
public function testGetListeMetiersTooMuchRequests()
{
/** @var PartenaireRomeMetier $appellations */
$appellations = self::$kernel
->getContainer()
->get(PartenaireRomeAppellation::class)
;
$appellations->getListeAppellation('arb');
$appellations->getListeAppellation('ing');
$appellations->getListeAppellation('rob');
$appellations->getListeAppellation('chori');
$data = $appellations->getListeAppellation('camion');
$this->assertTrue(
$data[0] instanceof \stdClass,
'assert that first index of data is an instance of stdClass'
);
}
public function testGetAppellation()
{
/** @var PartenaireRomeMetier $appellations */
$appellations = self::$kernel
->getContainer()
->get(PartenaireRomeAppellation::class)
;
$a = $appellations->getListeAppellation('arb');
$full = $appellations->getAppellation($a[0]->code);
$this->assertNotNull(
$full->libelle,
'assert that libelle is not null'
);
$this->assertTrue(
$full->metier instanceof \stdClass,
'assert that metier is returned'
);
$this->assertNotNull(
$full->metier->libelle,
'assert that metier->libelle is not null'
);
}
}

View File

@@ -0,0 +1,29 @@
<?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\FranceTravailApiBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* @internal
*
* @coversNothing
*/
class RomeControllerTest extends WebTestCase
{
public function testAppellationsearch()
{
$client = static::createClient();
$crawler = $client->request('GET', '/{_locale}/pole-emploi/appellation/search');
}
}

View File

@@ -0,0 +1,16 @@
<?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\JobBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillJobBundle extends Bundle {}

View File

@@ -0,0 +1,123 @@
<?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\JobBundle\Controller;
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Chill\JobBundle\Entity\Immersion;
use Symfony\Component\HttpFoundation\Response;
/**
* CRUD Controller for reports (Frein, ...).
*/
class CSCrudReportController extends EntityPersonCRUDController
{
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
{
$next = $request->request->get('submit', 'save-and-close');
return match ($next) {
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
'person' => $entity->getPerson()->getId(),
]),
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
};
}
protected function duplicateEntity(string $action, Request $request)
{
if ('cscv' === $this->getCrudName()) {
$id = $request->query->get('duplicate_id', 0);
/** @var \Chill\JobBundle\Entity\CV $cv */
$cv = $this->getEntity($action, $id, $request);
$em = $this->managerRegistry->getManager();
$em->detach($cv);
foreach ($cv->getExperiences() as $experience) {
$cv->removeExperience($experience);
$em->detach($experience);
$cv->addExperience($experience);
}
foreach ($cv->getFormations() as $formation) {
$cv->removeFormation($formation);
$em->detach($formation);
$cv->addFormation($formation);
}
return $cv;
}
if ('projet_prof' === $this->getCrudName()) {
$id = $request->query->get('duplicate_id', 0);
/** @var \Chill\JobBundle\Entity\ProjetProfessionnel $original */
$original = $this->getEntity($action, $id, $request);
$new = parent::duplicateEntity($action, $request);
foreach ($original->getSouhait() as $s) {
$new->addSouhait($s);
}
foreach ($original->getValide() as $s) {
$new->addValide($s);
}
return $new;
}
return parent::duplicateEntity($action, $request);
}
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
{
if ($entity instanceof Immersion) {
if ('edit' === $action || 'new' === $action) {
return parent::createFormFor($action, $entity, $formClass, [
'center' => $entity->getPerson()->getCenter(),
]);
}
if ('bilan' === $action) {
return parent::createFormFor($action, $entity, $formClass, [
'center' => $entity->getPerson()->getCenter(),
'step' => 'bilan',
]);
}
if ('delete' === $action) {
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
throw new \LogicException("this step {$action} is not supported");
}
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request)
{
// for immersion / edit-bilan action
if ('bilan' === $action) {
/* @var $entity Immersion */
$entity->setIsBilanFullfilled(true);
}
parent::onPreFlush($action, $entity, $form, $request);
}
/**
* Edit immersion bilan.
*
* @param int $id
*/
public function editBilan(Request $request, $id): Response
{
return $this->formEditAction('bilan', $request, $id);
}
}

View File

@@ -0,0 +1,150 @@
<?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\JobBundle\Controller;
use Chill\PersonBundle\CRUD\Controller\OneToOneEntityPersonCRUDController;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Chill\JobBundle\Form\CSPersonPersonalSituationType;
use Chill\JobBundle\Form\CSPersonDispositifsType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class CSPersonController extends OneToOneEntityPersonCRUDController
{
#[Route(path: '{_locale}/person/job/personal_situation/{id}/edit', name: 'chill_crud_job_personal_situation_edit')]
public function personalSituationEdit(Request $request, $id): Response
{
return $this->formEditAction(
'ps_situation_edit',
$request,
$id,
CSPersonPersonalSituationType::class
);
}
#[Route(path: '{_locale}/person/job/dispositifs/{id}/edit', name: 'chill_crud_job_dispositifs_edit')]
public function dispositifsEdit(Request $request, $id)
{
return $this->formEditAction(
'dispositifs_edit',
$request,
$id,
CSPersonDispositifsType::class
);
}
#[Route(path: '{_locale}/person/job/{person}/personal_situation', name: 'chill_crud_job_personal_situation_view')]
public function personalSituationView(Request $request, $person): Response
{
return $this->viewAction('ps_situation_view', $request, $person);
}
#[Route(path: '{_locale}/person/job/{person}/dispositifs', name: 'chill_crud_job_dispositifs_view')]
public function dispositifsView(Request $request, $person): Response
{
return $this->viewAction('dispositifs_view', $request, $person);
}
protected function generateRedirectOnCreateRoute($action, Request $request, $entity): string
{
$route = '';
switch ($action) {
case 'ps_situation_view':
$route = 'chill_crud_job_personal_situation_edit';
break;
case 'dispositifs_view':
$route = 'chill_crud_job_dispositifs_edit';
break;
default:
parent::generateRedirectOnCreateRoute($action, $request, $entity);
}
return $this->generateUrl($route, ['id' => $entity->getPerson()->getId()]);
}
protected function checkACL($action, $entity): void
{
match ($action) {
'ps_situation_edit', 'dispositifs_edit' => $this->denyAccessUnlessGranted(
PersonVoter::UPDATE,
$entity->getPerson()
),
'ps_situation_view', 'dispositifs_view' => $this->denyAccessUnlessGranted(
PersonVoter::SEE,
$entity->getPerson()
),
default => parent::checkACL($action, $entity),
};
}
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
{
return match ($action) {
'ps_situation_edit' => $this->redirectToRoute(
'chill_crud_'.$this->getCrudName().'_personal_situation_view',
['person' => $entity->getId()]
),
'dispositifs_edit' => $this->redirectToRoute(
'chill_crud_'.$this->getCrudName().'_dispositifs_view',
['person' => $entity->getId()]
),
default => null,
};
}
protected function getTemplateFor($action, $entity, Request $request): string
{
return match ($action) {
'ps_situation_edit' => '@ChillJob/CSPerson/personal_situation_edit.html.twig',
'dispositifs_edit' => '@ChillJob/CSPerson/dispositifs_edit.html.twig',
'ps_situation_view' => '@ChillJob/CSPerson/personal_situation_view.html.twig',
'dispositifs_view' => '@ChillJob/CSPerson/dispositifs_view.html.twig',
default => parent::getTemplateFor($action, $entity, $request),
};
}
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
{
switch ($action) {
case 'ps_situation_edit':
case 'dispositifs_edit':
$form = $this->createForm($formClass, $entity, \array_merge(
$formOptions,
['center' => $entity->getPerson()->getCenter()]
));
$this->customizeForm($action, $form);
return $form;
default:
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
}
protected function generateLabelForButton($action, $formName, $form): string
{
switch ($action) {
case 'ps_situation_edit':
case 'dispositifs_edit':
if ('submit' === $formName) {
return 'Enregistrer';
}
throw new \LogicException("this formName is not supported: {$formName}");
break;
default:
return 'Enregistrer';
}
}
}

View File

@@ -0,0 +1,73 @@
<?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\JobBundle\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\HttpFoundation\Response;
use Chill\JobBundle\Entity\Frein;
use Chill\JobBundle\Entity\CV;
use Chill\JobBundle\Entity\Immersion;
use Chill\JobBundle\Entity\ProjetProfessionnel;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\JobBundle\Security\Authorization\JobVoter;
class CSReportController extends AbstractController
{
public function __construct(private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry) {}
#[Route(path: '{_locale}/person/job/{person}/report', name: 'chill_job_report_index')]
public function index(Person $person): Response
{
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person, 'The access to '
.'person is denied');
$reports = $this->getReports($person);
return $this->render('@ChillJob/Report/index.html.twig', \array_merge([
'person' => $person,
], $reports));
}
protected function getReports(Person $person): array
{
$results = [];
$kinds = [];
if ($this->isGranted(JobVoter::REPORT_CV, $person)) {
$kinds['cvs'] = CV::class;
}
if ($this->isGranted(JobVoter::REPORT_NEW, $person)) {
$kinds = \array_merge($kinds, [
'cvs' => CV::class,
'freins' => Frein::class,
'immersions' => Immersion::class,
'projet_professionnels' => ProjetProfessionnel::class,
]);
}
foreach ($kinds as $key => $className) {
$ordering = match ($key) {
'immersions' => ['debutDate' => 'DESC'],
default => ['reportDate' => 'DESC'],
};
$results[$key] = $this->managerRegistry->getManager()
->getRepository($className)
->findBy(['person' => $person], $ordering);
}
return $results;
}
}

View File

@@ -0,0 +1,62 @@
<?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\JobBundle\Controller;
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* CRUD Controller for reports (Frein, ...).
*/
class CVCrudController extends EntityPersonCRUDController
{
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
{
$next = $request->request->get('submit', 'save-and-close');
return match ($next) {
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
'person' => $entity->getPerson()->getId(),
]),
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
};
}
protected function duplicateEntity(string $action, Request $request)
{
if ('cv' === $this->getCrudName()) {
$id = $request->query->get('duplicate_id', 0);
/** @var \Chill\JobBundle\Entity\CV $cv */
$cv = $this->getEntity($action, $id, $request);
$em = $this->managerRegistry->getManager();
$em->detach($cv);
foreach ($cv->getExperiences() as $experience) {
$cv->removeExperience($experience);
$em->detach($experience);
$cv->addExperience($experience);
}
foreach ($cv->getFormations() as $formation) {
$cv->removeFormation($formation);
$em->detach($formation);
$cv->addFormation($formation);
}
return $cv;
}
return parent::duplicateEntity($action, $request);
}
}

View File

@@ -0,0 +1,35 @@
<?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\JobBundle\Controller;
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* CRUD Controller for reports (Frein, ...).
*/
class FreinCrudController extends EntityPersonCRUDController
{
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
{
$next = $request->request->get('submit', 'save-and-close');
return match ($next) {
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
'person' => $entity->getPerson()->getId(),
]),
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
};
}
}

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\JobBundle\Controller;
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Chill\JobBundle\Entity\Immersion;
use Symfony\Component\HttpFoundation\Response;
/**
* CRUD Controller for reports (Frein, ...).
*/
class ImmersionCrudController extends EntityPersonCRUDController
{
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
{
$next = $request->request->get('submit', 'save-and-close');
return match ($next) {
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
'person' => $entity->getPerson()->getId(),
]),
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
};
}
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
{
if ($entity instanceof Immersion) {
if ('edit' === $action || 'new' === $action) {
return parent::createFormFor($action, $entity, $formClass, [
'center' => $entity->getPerson()->getCenter(),
]);
}
if ('bilan' === $action) {
return parent::createFormFor($action, $entity, $formClass, [
'center' => $entity->getPerson()->getCenter(),
'step' => 'bilan',
]);
}
if ('delete' === $action) {
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
throw new \LogicException("this step {$action} is not supported");
}
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request)
{
// for immersion / edit-bilan action
if ('bilan' === $action) {
/* @var $entity Immersion */
$entity->setIsBilanFullfilled(true);
}
parent::onPreFlush($action, $entity, $form, $request);
}
/**
* Edit immersion bilan.
*
* @param int $id
*/
public function bilan(Request $request, $id): Response
{
return $this->formEditAction('bilan', $request, $id);
}
}

View File

@@ -0,0 +1,57 @@
<?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\JobBundle\Controller;
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* CRUD Controller for reports (Frein, ...).
*/
class ProjetProfessionnelCrudController extends EntityPersonCRUDController
{
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
{
$next = $request->request->get('submit', 'save-and-close');
return match ($next) {
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
'person' => $entity->getPerson()->getId(),
]),
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
};
}
protected function duplicateEntity(string $action, Request $request)
{
if ('projet_prof' === $this->getCrudName()) {
$id = $request->query->get('duplicate_id', 0);
/** @var \Chill\JobBundle\Entity\ProjetProfessionnel $original */
$original = $this->getEntity($action, $id, $request);
$new = parent::duplicateEntity($action, $request);
foreach ($original->getSouhait() as $s) {
$new->addSouhait($s);
}
foreach ($original->getValide() as $s) {
$new->addValide($s);
}
return $new;
}
return parent::duplicateEntity($action, $request);
}
}

View File

@@ -0,0 +1,196 @@
<?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\JobBundle\DependencyInjection;
use Chill\JobBundle\Controller\CSPersonController;
use Chill\JobBundle\Controller\CVCrudController;
use Chill\JobBundle\Controller\FreinCrudController;
use Chill\JobBundle\Controller\ImmersionCrudController;
use Chill\JobBundle\Controller\ProjetProfessionnelCrudController;
use Chill\JobBundle\Entity\CSPerson;
use Chill\JobBundle\Entity\CV;
use Chill\JobBundle\Entity\Frein;
use Chill\JobBundle\Entity\Immersion;
use Chill\JobBundle\Entity\ProjetProfessionnel;
use Chill\JobBundle\Form\CVType;
use Chill\JobBundle\Form\FreinType;
use Chill\JobBundle\Form\ImmersionType;
use Chill\JobBundle\Form\ProjetProfessionnelType;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration.
*
* @see http://symfony.com/doc/current/cookbook/bundles/extension.html
*/
class ChillJobExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$loader->load('services/3party_type.yml');
$loader->load('services/controller.yml');
$loader->load('services/form.yml');
$loader->load('services/export.yml');
$loader->load('services/menu.yml');
$loader->load('services/security.yml');
}
public function prepend(ContainerBuilder $container): void
{
$this->prependRoute($container);
$this->prependCruds($container);
}
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'cruds' => [
[
'class' => CSPerson::class,
'controller' => CSPersonController::class,
'name' => 'job',
'base_role' => 'ROLE_USER',
'base_path' => '/person/job/',
],
[
'class' => CV::class,
'controller' => CVCrudController::class,
'name' => 'cscv',
'base_role' => 'ROLE_USER',
'base_path' => '/person/report/cv',
'form_class' => CVType::class,
'actions' => [
'view' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/CV/view.html.twig',
],
'new' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/CV/new.html.twig',
],
'edit' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/CV/edit.html.twig',
],
'delete' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Report/delete.html.twig',
],
],
],
[
'class' => ProjetProfessionnel::class,
'controller' => ProjetProfessionnelCrudController::class,
'name' => 'projet_prof',
'base_role' => 'ROLE_USER',
'base_path' => '/person/report/projet-professionnel',
'form_class' => ProjetProfessionnelType::class,
'actions' => [
'view' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/ProjetProfessionnel/view.html.twig',
],
'new' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/ProjetProfessionnel/new.html.twig',
],
'edit' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/ProjetProfessionnel/edit.html.twig',
],
'delete' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Report/delete.html.twig',
],
],
],
[
'class' => Frein::class,
'controller' => FreinCrudController::class,
'name' => 'csfrein',
'base_role' => 'ROLE_USER',
'base_path' => '/person/report/frein',
'form_class' => FreinType::class,
'actions' => [
'view' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Frein/view.html.twig',
],
'new' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Frein/new.html.twig',
],
'edit' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Frein/edit.html.twig',
],
'delete' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Report/delete.html.twig',
],
],
],
[
'class' => Immersion::class,
'controller' => ImmersionCrudController::class,
'name' => 'immersion',
'base_role' => 'ROLE_USER',
'base_path' => '/person/report/immersion',
'form_class' => ImmersionType::class,
'actions' => [
'view' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Immersion/view.html.twig',
],
'new' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Immersion/new.html.twig',
],
'bilan' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Immersion/edit-bilan.html.twig',
],
'edit' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Immersion/edit.html.twig',
],
'delete' => [
'role' => 'ROLE_USER',
'template' => '@ChillJob/Report/delete.html.twig',
],
],
],
],
]);
}
protected function prependRoute(ContainerBuilder $container): void
{
// declare routes for job bundle
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
'@ChillJobBundle/Resources/config/routing.yml',
],
],
]);
}
}

View File

@@ -0,0 +1,35 @@
<?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\JobBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files.
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_job');
$rootNode = $treeBuilder->getRootNode();
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,303 @@
<?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\JobBundle\Entity;
use Doctrine\Common\Collections\Order;
use Doctrine\ORM\Mapping as ORM;
use Chill\PersonBundle\Entity\Person;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* CV.
*/
#[ORM\Table(name: 'chill_job.cv')]
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\CVRepository::class)]
class CV implements \Stringable
{
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
/**
* @Assert\NotNull()
*/
#[ORM\Column(name: 'reportDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE)]
private ?\DateTimeInterface $reportDate = null;
public const FORMATION_LEVEL = [
'sans_diplome',
'BEP_CAP',
'BAC',
'BAC+2',
'BAC+3',
'BAC+4',
'BAC+5',
'BAC+8',
];
/**
* @Assert\NotBlank()
*/
#[ORM\Column(name: 'formationLevel', type: \Doctrine\DBAL\Types\Types::STRING, length: 255, nullable: true)]
private ?string $formationLevel = null;
public const FORMATION_TYPE = [
'formation_initiale',
'formation_continue',
];
#[ORM\Column(name: 'formationType', type: \Doctrine\DBAL\Types\Types::STRING, length: 255, nullable: true)]
private ?string $formationType = null;
/**
* @var string[]|null
*/
#[ORM\Column(name: 'spokenLanguages', type: \Doctrine\DBAL\Types\Types::JSON, nullable: true)]
private $spokenLanguages;
#[ORM\Column(name: 'notes', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
private ?string $notes = null;
/**
* @Assert\Valid(traverse=true)
*
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\CV\Formation>
*/
#[ORM\OneToMany(targetEntity: CV\Formation::class, mappedBy: 'CV', cascade: ['persist', 'remove', 'detach'], orphanRemoval: true)]
// #[ORM\OrderBy(['startDate' => Order::Descending, 'endDate' => 'DESC'])]
private Collection $formations;
/**
* @Assert\Valid(traverse=true)
*
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\CV\Experience>
*/
#[ORM\OneToMany(targetEntity: CV\Experience::class, mappedBy: 'CV', cascade: ['persist', 'remove', 'detach'], orphanRemoval: true)]
// #[ORM\OrderBy(['startDate' => Order::Descending, 'endDate' => 'DESC'])]
private Collection $experiences;
#[ORM\ManyToOne(targetEntity: Person::class)]
private ?Person $person = null;
public function __construct()
{
$this->formations = new ArrayCollection();
$this->experiences = new ArrayCollection();
$this->reportDate = new \DateTime('now');
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set reportDate.
*/
public function setReportDate(\DateTime $reportDate): self
{
$this->reportDate = $reportDate;
return $this;
}
/**
* Get reportDate.
*/
public function getReportDate(): ?\DateTimeInterface
{
return $this->reportDate;
}
/**
* Set formationLevel.
*/
public function setFormationLevel(?string $formationLevel = null): self
{
$this->formationLevel = $formationLevel;
return $this;
}
/**
* Get formationLevel.
*
* @return string|null
*/
public function getFormationLevel()
{
return $this->formationLevel;
}
/**
* Set formationType.
*/
public function setFormationType(string $formationType): self
{
$this->formationType = $formationType;
return $this;
}
/**
* Get formationType.
*/
public function getFormationType(): ?string
{
return $this->formationType;
}
/**
* Set spokenLanguages.
*
* @param mixed|null $spokenLanguages
*/
public function setSpokenLanguages($spokenLanguages = null): self
{
$this->spokenLanguages = $spokenLanguages;
return $this;
}
/**
* Get spokenLanguages.
*/
public function getSpokenLanguages(): array
{
return $this->spokenLanguages ?? [];
}
/**
* Set notes.
*/
public function setNotes(?string $notes = null): self
{
$this->notes = $notes;
return $this;
}
/**
* Get notes.
*/
public function getNotes(): ?string
{
return $this->notes;
}
public function getFormations(): Collection
{
return $this->formations;
}
public function getExperiences(): Collection
{
return $this->experiences;
}
public function setFormations(Collection $formations): self
{
foreach ($formations as $formation) {
/* @var CV\Formation $formation */
$formation->setCV($this);
}
$this->formations = $formations;
return $this;
}
public function addFormation(CV\Formation $formation): self
{
if ($this->formations->contains($formation)) {
return $this;
}
$this->formations->add($formation);
$formation->setCV($this);
return $this;
}
public function removeFormation(CV\Formation $formation): self
{
if (false === $this->formations->contains($formation)) {
return $this;
}
$formation->setCV(null);
$this->formations->removeElement($formation);
return $this;
}
public function setExperiences(Collection $experiences): self
{
foreach ($experiences as $experience) {
/* @var CV\Experience $experience */
$experience->setCV($this);
}
$this->experiences = $experiences;
return $this;
}
public function addExperience(CV\Experience $experience): self
{
if ($this->experiences->contains($experience)) {
return $this;
}
$experience->setCV($this);
$this->experiences->add($experience);
return $this;
}
public function removeExperience(CV\Experience $experience): self
{
if (false === $this->experiences->contains($experience)) {
return $this;
}
$this->experiences->removeElement($experience);
$experience->setCV(null);
return $this;
}
public function getPerson(): Person
{
return $this->person;
}
public function setPerson(Person $person)
{
$this->person = $person;
return $this;
}
public function __toString(): string
{
return 'CV de '.$this->getPerson().' daté du '.
$this->getReportDate()->format('d-m-Y');
}
}

View File

@@ -0,0 +1,205 @@
<?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\JobBundle\Entity\CV;
use Doctrine\ORM\Mapping as ORM;
use Chill\JobBundle\Entity\CV;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Experience.
*/
#[ORM\Table(name: 'chill_job.cv_experience')]
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\CV\ExperienceRepository::class)]
class Experience
{
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
#[ORM\Column(name: 'poste', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
private ?string $poste = null;
#[ORM\Column(name: 'structure', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
private ?string $structure = null;
#[ORM\Column(name: 'startDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $startDate = null;
/**
* @Assert\GreaterThan(propertyPath="startDate", message="La date de fin doit être postérieure à la date de début")
*/
#[ORM\Column(name: 'endDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $endDate = null;
public const CONTRAT_TYPE = [
'cddi',
'cdd-6mois',
'cdd+6mois',
'interim',
'apprentissage',
'contrat_prof',
'cui',
'cae',
'cdi',
'stage',
'volontariat',
'benevolat',
'autres',
];
#[ORM\Column(name: 'contratType', type: \Doctrine\DBAL\Types\Types::STRING, length: 100)]
private ?string $contratType = null;
#[ORM\Column(name: 'notes', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
private ?string $notes = null;
#[ORM\ManyToOne(targetEntity: CV::class, inversedBy: 'experiences')]
private ?CV $CV = null;
/**
* Get id.
*/
public function getId(): ?int
{
return $this->id;
}
/**
* Set poste.
*/
public function setPoste(?string $poste = null): self
{
$this->poste = $poste;
return $this;
}
/**
* Get poste.
*/
public function getPoste(): ?string
{
return $this->poste;
}
/**
* Set structure.
*/
public function setStructure(?string $structure = null): self
{
$this->structure = $structure;
return $this;
}
/**
* Get structure.
*/
public function getStructure(): ?string
{
return $this->structure;
}
/**
* Set startDate.
*
* @param \DateTime|null $startDate
*/
public function setStartDate(?\DateTimeInterface $startDate = null): self
{
$this->startDate = $startDate;
return $this;
}
/**
* Get startDate.
*
* @return \DateTimeInterface
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* Set endDate.
*
* @param \DateTime|null $endDate
*/
public function setEndDate(?\DateTimeInterface $endDate = null): self
{
$this->endDate = $endDate;
return $this;
}
/**
* Get endDate.
*
* @return \DateTimeInterface
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* Set contratType.
*/
public function setContratType(?string $contratType): self
{
$this->contratType = $contratType;
return $this;
}
/**
* Get contratType.
*/
public function getContratType(): ?string
{
return $this->contratType;
}
/**
* Set notes.
*/
public function setNotes(?string $notes): self
{
$this->notes = $notes;
return $this;
}
/**
* Get notes.
*/
public function getNotes(): ?string
{
return $this->notes;
}
public function getCV(): CV
{
return $this->CV;
}
public function setCV(?CV $CV = null): self
{
$this->CV = $CV;
return $this;
}
}

View File

@@ -0,0 +1,214 @@
<?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\JobBundle\Entity\CV;
use Doctrine\ORM\Mapping as ORM;
use Chill\JobBundle\Entity\CV;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Formation.
*/
#[ORM\Table(name: 'chill_job.cv_formation')]
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\CV\FormationRepository::class)]
class Formation
{
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
/**
* @Assert\Length(min=3)
*
* @Assert\NotNull()
*/
#[ORM\Column(name: 'title', type: \Doctrine\DBAL\Types\Types::TEXT)]
private ?string $title = null;
#[ORM\Column(name: 'startDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $startDate = null;
/**
* @Assert\GreaterThan(propertyPath="startDate", message="La date de fin doit être postérieure à la date de début")
*/
#[ORM\Column(name: 'endDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $endDate = null;
public const DIPLOMA_OBTAINED = [
'fr', 'non-fr', 'aucun',
];
#[ORM\Column(name: 'diplomaObtained', type: \Doctrine\DBAL\Types\Types::STRING, nullable: true)]
private ?string $diplomaObtained = null;
public const DIPLOMA_RECONNU = [
'oui', 'non', 'nsp',
];
#[ORM\Column(name: 'diplomaReconnue', type: \Doctrine\DBAL\Types\Types::STRING, length: 50, nullable: true)]
private ?string $diplomaReconnue = null;
#[ORM\Column(name: 'organisme', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
private ?string $organisme = null;
#[ORM\ManyToOne(targetEntity: CV::class, inversedBy: 'formations')]
private ?CV $CV = null;
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set title.
*
* @return Formation
*/
public function setTitle(?string $title)
{
$this->title = $title;
return $this;
}
/**
* Get title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set startDate.
*
* @param \DateTime|null $startDate
*
* @return Formation
*/
public function setStartDate(?\DateTimeInterface $startDate = null)
{
$this->startDate = $startDate;
return $this;
}
/**
* Get startDate.
*
* @return \DateTimeInterface
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* Set endDate.
*
* @param \DateTime|null $endDate
*
* @return Formation
*/
public function setEndDate(?\DateTimeInterface $endDate = null)
{
$this->endDate = $endDate;
return $this;
}
/**
* Get endDate.
*
* @return \DateTimeInterface
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* Set diplomaObtained.
*
* @return Formation
*/
public function setDiplomaObtained(?string $diplomaObtained = null)
{
$this->diplomaObtained = $diplomaObtained;
return $this;
}
/**
* Get diplomaObtained.
*/
public function getDiplomaObtained()
{
return $this->diplomaObtained;
}
/**
* Set diplomaReconnue.
*/
public function setDiplomaReconnue(?string $diplomaReconnue = null): self
{
$this->diplomaReconnue = $diplomaReconnue;
return $this;
}
/**
* Get diplomaReconnue.
*/
public function getDiplomaReconnue(): ?string
{
return $this->diplomaReconnue;
}
/**
* Set organisme.
*/
public function setOrganisme(?string $organisme): self
{
$this->organisme = $organisme;
return $this;
}
/**
* Get organisme.
*/
public function getOrganisme(): ?string
{
return $this->organisme;
}
public function getCV(): ?CV
{
return $this->CV;
}
public function setCV(?CV $CV = null): self
{
$this->CV = $CV;
return $this;
}
}

View File

@@ -0,0 +1,192 @@
<?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\JobBundle\Entity;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\Mapping as ORM;
use Chill\PersonBundle\Entity\HasPerson;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Frein.
*/
#[ORM\Table(name: 'chill_job.frein')]
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\FreinRepository::class)]
class Frein implements HasPerson, \Stringable
{
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
/**
* @Assert\NotNull()
*
* @Assert\GreaterThan("5 years ago",
* message="La date du rapport ne peut pas être plus de cinq ans dans le passé"
* )
*/
#[ORM\Column(name: 'reportDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE)]
private ?\DateTimeInterface $reportDate = null;
public const FREINS_PERSO = [
'situation_administrative',
'situation_personnelle_et_familiale',
'comportement',
'etat_de_sante',
'precarite_situation_materielle',
'condition_ou_absence_logement',
'autres',
];
/**
* @var string[]
*/
#[ORM\Column(name: 'freinsPerso', type: \Doctrine\DBAL\Types\Types::JSON)]
private $freinsPerso = [];
#[ORM\Column(name: 'notesPerso', type: \Doctrine\DBAL\Types\Types::TEXT)]
private ?string $notesPerso = '';
public const FREINS_EMPLOI = [
'garde_d_enfants',
'sante',
'famille',
'finances',
'maitrise_de_la_langue',
'autres',
];
/**
* @var string[]
*/
#[ORM\Column(name: 'freinsEmploi', type: \Doctrine\DBAL\Types\Types::JSON)]
private $freinsEmploi = [];
#[ORM\Column(name: 'notesEmploi', type: \Doctrine\DBAL\Types\Types::TEXT)]
private ?string $notesEmploi = '';
/**
* @Assert\NotNull()
*/
#[ORM\ManyToOne(targetEntity: Person::class)]
private Person $person;
public function __construct()
{
$this->reportDate = new \DateTime('today');
}
public function getId(): ?int
{
return $this->id;
}
public function setReportDate(?\DateTimeInterface $reportDate): self
{
$this->reportDate = $reportDate;
return $this;
}
public function getReportDate(): ?\DateTimeInterface
{
return $this->reportDate;
}
public function setFreinsPerso(array $freinsPerso = []): self
{
$this->freinsPerso = $freinsPerso;
return $this;
}
public function getFreinsPerso(): array
{
return $this->freinsPerso;
}
public function setNotesPerso(?string $notesPerso = null): self
{
$this->notesPerso = (string) $notesPerso;
return $this;
}
public function getNotesPerso(): ?string
{
return $this->notesPerso;
}
public function setFreinsEmploi(array $freinsEmploi = []): self
{
$this->freinsEmploi = $freinsEmploi;
return $this;
}
public function getFreinsEmploi(): array
{
return $this->freinsEmploi;
}
public function setNotesEmploi(?string $notesEmploi = null): self
{
$this->notesEmploi = (string) $notesEmploi;
return $this;
}
public function getNotesEmploi(): ?string
{
return $this->notesEmploi;
}
public function getPerson(): ?Person
{
return $this->person;
}
public function setPerson(?Person $person = null): HasPerson
{
$this->person = $person;
return $this;
}
/**
* @Assert\Callback()
*/
public function validateFreinsCount(ExecutionContextInterface $context, $payload): void
{
$nb = count($this->getFreinsEmploi()) + count($this->getFreinsPerso());
if (0 === $nb) {
$msg = 'Indiquez au moins un frein parmi les freins '
."liés à l'emploi et les freins liés à la situation personnelle.";
$context->buildViolation($msg)
->atPath('freinsEmploi')
->addViolation();
$context->buildViolation($msg)
->atPath('freinsPerso')
->addViolation();
}
}
public function __toString(): string
{
return 'Rapport "frein" de '.$this->getPerson().' daté du '.
$this->getReportDate()->format('d-m-Y');
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
<?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\JobBundle\Entity;
use Chill\JobBundle\Repository\ProjetProfessionnelRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Chill\PersonBundle\Entity\Person;
use Chill\JobBundle\Entity\Rome\Appellation;
/**
* ProjetProfessionnel.
*/
#[ORM\Table(name: 'chill_job.projet_professionnel')]
#[ORM\Entity(repositoryClass: ProjetProfessionnelRepository::class)]
class ProjetProfessionnel implements \Stringable
{
#[ORM\Column(name: 'id', type: Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
/**
* @Assert\NotNull()
*/
#[ORM\ManyToOne(targetEntity: Person::class)]
private ?Person $person = null;
/**
* @Assert\NotNull()
*/
#[ORM\Column(name: 'reportDate', type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $reportDate = null;
/**
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\Rome\Appellation>
*/
#[ORM\JoinTable(name: 'chill_job.projetprofessionnel_souhait')]
#[ORM\ManyToMany(targetEntity: Appellation::class, cascade: ['persist'])]
private Collection $souhait;
#[ORM\Column(name: 'domaineActiviteSouhait', type: Types::TEXT, nullable: true)]
private ?string $domaineActiviteSouhait = null;
public const TYPE_CONTRAT = [
'cdd', 'cdi', 'contrat_insertion',
'interim', 'indifferent', 'apprentissage',
'personnalisation', 'creation_entreprise',
];
/**
* @var array|null
*
* @Assert\Count(min=1, minMessage="Indiquez au moins un type de contrat")
*/
#[ORM\Column(name: 'typeContrat', type: Types::JSON, nullable: true)]
private $typeContrat;
#[ORM\Column(name: 'typeContratNotes', type: Types::TEXT, nullable: true)]
private ?string $typeContratNotes = null;
public const VOLUME_HORAIRES = [
'temps_plein',
'temps_partiel',
];
/**
* @var array|null
*
* @Assert\Count(min=1, minMessage="Indiquez un volume horaire souhaité")
*/
#[ORM\Column(name: 'volumeHoraire', type: Types::JSON, nullable: true)]
private $volumeHoraire;
#[ORM\Column(name: 'volumeHoraireNotes', type: Types::TEXT, nullable: true)]
private ?string $volumeHoraireNotes = null;
#[ORM\Column(name: 'idee', type: Types::TEXT, nullable: true)]
private ?string $idee = null;
#[ORM\Column(name: 'enCoursConstruction', type: Types::TEXT, nullable: true)]
private ?string $enCoursConstruction = null;
/**
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\Rome\Appellation>
*/
#[ORM\JoinTable(name: 'chill_job.projetprofessionnel_valide')]
#[ORM\ManyToMany(targetEntity: Appellation::class)]
private Collection $valide;
#[ORM\Column(name: 'domaineActiviteValide', type: Types::TEXT, nullable: true)]
private ?string $domaineActiviteValide = null;
#[ORM\Column(name: 'valideNotes', type: Types::TEXT, nullable: true)]
private ?string $valideNotes = null;
#[ORM\Column(name: 'projetProfessionnelNote', type: Types::TEXT, nullable: true)]
private ?string $projetProfessionnelNote = null;
public function __construct()
{
$this->valide = new ArrayCollection();
$this->souhait = new ArrayCollection();
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set reportDate.
*
* @param \DateTime $reportDate
*
* @return ProjetProfessionnel
*/
public function setReportDate(?\DateTimeInterface $reportDate)
{
$this->reportDate = $reportDate;
return $this;
}
/**
* Get reportDate.
*
* @return \DateTimeInterface
*/
public function getReportDate()
{
return $this->reportDate;
}
/**
* Set typeContrat.
*
* @param mixed|null $typeContrat
*
* @return ProjetProfessionnel
*/
public function setTypeContrat($typeContrat = null)
{
$this->typeContrat = $typeContrat;
return $this;
}
/**
* Get typeContrat.
*/
public function getTypeContrat()
{
return $this->typeContrat;
}
/**
* Set typeContratNotes.
*
* @return ProjetProfessionnel
*/
public function setTypeContratNotes(?string $typeContratNotes = null)
{
$this->typeContratNotes = $typeContratNotes;
return $this;
}
/**
* Get typeContratNotes.
*
* @return string|null
*/
public function getTypeContratNotes()
{
return $this->typeContratNotes;
}
/**
* Set volumeHoraire.
*
* @param mixed|null $volumeHoraire
*
* @return ProjetProfessionnel
*/
public function setVolumeHoraire($volumeHoraire = null)
{
$this->volumeHoraire = $volumeHoraire;
return $this;
}
/**
* Get volumeHoraire.
*/
public function getVolumeHoraire()
{
return $this->volumeHoraire;
}
/**
* Set volumeHoraireNotes.
*
* @return ProjetProfessionnel
*/
public function setVolumeHoraireNotes(?string $volumeHoraireNotes = null)
{
$this->volumeHoraireNotes = $volumeHoraireNotes;
return $this;
}
/**
* Get volumeHoraireNotes.
*
* @return string|null
*/
public function getVolumeHoraireNotes()
{
return $this->volumeHoraireNotes;
}
/**
* Set idee.
*
* @return ProjetProfessionnel
*/
public function setIdee(?string $idee = null)
{
$this->idee = $idee;
return $this;
}
/**
* Get idee.
*
* @return string|null
*/
public function getIdee()
{
return $this->idee;
}
/**
* Set enCoursConstruction.
*
* @return ProjetProfessionnel
*/
public function setEnCoursConstruction(?string $enCoursConstruction = null)
{
$this->enCoursConstruction = $enCoursConstruction;
return $this;
}
/**
* Get enCoursConstruction.
*
* @return string|null
*/
public function getEnCoursConstruction()
{
return $this->enCoursConstruction;
}
/**
* Set valideNotes.
*
* @return ProjetProfessionnel
*/
public function setValideNotes(?string $valideNotes = null)
{
$this->valideNotes = $valideNotes;
return $this;
}
/**
* Get valideNotes.
*
* @return string|null
*/
public function getValideNotes()
{
return $this->valideNotes;
}
/**
* Set projetProfessionnelNote.
*
* @return ProjetProfessionnel
*/
public function setProjetProfessionnelNote(?string $projetProfessionnelNote = null)
{
$this->projetProfessionnelNote = $projetProfessionnelNote;
return $this;
}
/**
* Get projetProfessionnelNote.
*
* @return string|null
*/
public function getProjetProfessionnelNote()
{
return $this->projetProfessionnelNote;
}
public function getPerson(): Person
{
return $this->person;
}
public function getSouhait(): Collection
{
return $this->souhait;
}
public function getValide(): Collection
{
return $this->valide;
}
public function setPerson(Person $person)
{
$this->person = $person;
return $this;
}
public function setSouhait(Collection $souhait)
{
$this->souhait = $souhait;
return $this;
}
public function addSouhait(Appellation $souhait)
{
$this->souhait->add($souhait);
return $this;
}
public function setValide(Collection $valide)
{
$this->valide = $valide;
return $this;
}
public function addValide(Appellation $valide)
{
$this->valide->add($valide);
return $this;
}
public function getDomaineActiviteSouhait(): ?string
{
return $this->domaineActiviteSouhait;
}
public function getDomaineActiviteValide(): ?string
{
return $this->domaineActiviteValide;
}
public function setDomaineActiviteSouhait(?string $domaineActiviteSouhait = null)
{
$this->domaineActiviteSouhait = $domaineActiviteSouhait;
return $this;
}
public function setDomaineActiviteValide(?string $domaineActiviteValide = null)
{
$this->domaineActiviteValide = $domaineActiviteValide;
return $this;
}
public function __toString(): string
{
return 'Rapport "projet professionnel" de '.$this->getPerson().' daté du '.
$this->getReportDate()->format('d-m-Y');
}
}

View File

@@ -0,0 +1,107 @@
<?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\JobBundle\Entity\Rome;
use Doctrine\ORM\Mapping as ORM;
/**
* Appellation.
*/
#[ORM\Table(name: 'chill_job.rome_appellation')]
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\Rome\AppellationRepository::class)]
class Appellation implements \Stringable
{
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
#[ORM\Column(name: 'code', type: \Doctrine\DBAL\Types\Types::STRING, length: 40, unique: true)]
private ?string $code = '';
#[ORM\Column(name: 'libelle', type: \Doctrine\DBAL\Types\Types::TEXT)]
private ?string $libelle = '';
#[ORM\ManyToOne(targetEntity: Metier::class, inversedBy: 'appellations', cascade: ['persist'])]
private ?Metier $metier = null;
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set code.
*
* @return Appellation
*/
public function setCode(?string $code)
{
$this->code = $code;
return $this;
}
/**
* Get code.
*
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set libelle.
*
* @return Appellation
*/
public function setLibelle(?string $libelle)
{
$this->libelle = $libelle;
return $this;
}
/**
* Get libelle.
*
* @return string
*/
public function getLibelle()
{
return $this->libelle;
}
public function getMetier(): Metier
{
return $this->metier;
}
public function setMetier(Metier $metier)
{
$this->metier = $metier;
return $this;
}
public function __toString(): string
{
return (string) $this->libelle;
}
}

View File

@@ -0,0 +1,100 @@
<?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\JobBundle\Entity\Rome;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Metier.
*/
#[ORM\Table(name: 'chill_job.rome_metier')]
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\Rome\MetierRepository::class)]
class Metier
{
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
#[ORM\Column(name: 'libelle', type: \Doctrine\DBAL\Types\Types::TEXT)]
private ?string $libelle = '';
#[ORM\Column(name: 'code', type: \Doctrine\DBAL\Types\Types::STRING, length: 20, unique: true)]
private ?string $code = '';
/**
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\Rome\Appellation>
*/
#[ORM\OneToMany(targetEntity: Appellation::class, mappedBy: 'metier')]
private \Doctrine\Common\Collections\Collection $appellations;
public function __construct()
{
$this->appellations = new ArrayCollection();
// $this->appellation = new ArrayCollection();
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set libelle.
*
* @return Metier
*/
public function setLibelle(?string $libelle)
{
$this->libelle = $libelle;
return $this;
}
/**
* Get libelle.
*
* @return string
*/
public function getLibelle()
{
return $this->libelle;
}
/**
* Set code.
*
* @return Metier
*/
public function setCode(?string $code)
{
$this->code = $code;
return $this;
}
/**
* Get code.
*
* @return string
*/
public function getCode()
{
return $this->code;
}
}

View File

@@ -0,0 +1,188 @@
<?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\JobBundle\Export;
use Chill\JobBundle\Entity\CSPerson;
use Chill\PersonBundle\Export\Helper\CustomizeListPersonHelperInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class ListCSPerson.
*
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
*/
class AddCSPersonToPersonListHelper implements CustomizeListPersonHelperInterface
{
public function __construct(private readonly TranslatorInterface $translator) {}
private const CSPERSON_FIELDS = [
'dateFinDernierEmploi',
/* 'prescripteur__name',
'prescripteur__email',
'prescripteur__phone',*/
'poleEmploiId',
'cafId',
'cafInscriptionDate',
'dateContratIEJ',
'cERInscriptionDate',
'pPAEInscriptionDate',
'pPAESignataire',
'cERSignataire',
'nEETCommissionDate',
'fSEMaDemarcheCode',
'enfantACharge',
'nEETEligibilite',
'situationProfessionnelle',
];
public function alterKeys(array $existing): array
{
$ressources = array_map(static fn ($key) => 'ressources__'.$key, CSPerson::RESSOURCES);
$moyenTransport = array_map(static fn ($key) => 'moyen_transport__'.$key, CSPerson::MOBILITE_MOYEN_TRANSPORT);
$accompagnements = array_map(static fn ($key) => 'accompagnements__'.$key, CSPerson::ACCOMPAGNEMENTS);
$permisConduire = array_map(static fn ($key) => 'permis_conduire__'.$key, CSPerson::PERMIS_CONDUIRE);
$typeContrat = array_map(static fn ($key) => 'type_contrat__'.$key, CSPerson::TYPE_CONTRAT);
return [
...$existing,
...self::CSPERSON_FIELDS,
...$ressources,
...$moyenTransport,
...$accompagnements,
...$permisConduire,
...$typeContrat,
];
}
public function alterSelect(QueryBuilder $qb, \DateTimeImmutable $computedDate): void
{
$qb
->leftJoin(CSPerson::class, 'cs_person', Query\Expr\Join::WITH, 'cs_person.person = person');
foreach (self::CSPERSON_FIELDS as $f) {
$qb->addSelect(sprintf('cs_person.%s as %s', $f, $f));
}
/* $qb->addSelect('cs_person.situationProfessionnelle as situation_prof');
$qb->addSelect('cs_person.nEETEligibilite as nEETEligibilite');*/
$i = 0;
foreach (CSPerson::RESSOURCES as $key) {
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.ressources, :param_{$i}) AS ressources__".$key)
->setParameter('param_'.$i, $key);
++$i;
}
foreach (CSPerson::MOBILITE_MOYEN_TRANSPORT as $key) {
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.mobiliteMoyenDeTransport, :param_{$i}) AS moyen_transport__".$key)
->setParameter('param_'.$i, $key);
++$i;
}
foreach (CSPerson::TYPE_CONTRAT as $key) {
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.typeContrat, :param_{$i}) AS type_contrat__".$key)
->setParameter('param_'.$i, $key);
++$i;
}
foreach (CSPerson::ACCOMPAGNEMENTS as $key) {
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.accompagnement, :param_{$i}) AS accompagnements__".$key)
->setParameter('param_'.$i, $key);
++$i;
}
foreach (CSPerson::PERMIS_CONDUIRE as $key) {
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.permisConduire, :param_{$i}) AS permis_conduire__".$key)
->setParameter('param_'.$i, $key);
++$i;
}
}
public function getLabels(string $key, array $values, array $data): ?callable
{
if (str_contains($key, '__')) {
return function (string|bool|null $value) use ($key): string {
if ('_header' === $value) {
[$domain, $v] = explode('__', $key);
return 'export.list.cs_person.'.$domain.'.'.$v;
}
if ('1' === $value || true === $value || 't' === $value) {
return 'x';
}
return '';
};
}
return match ($key) {
'nEETEligibilite' => function (string|bool|null $value): string {
if ('_header' === $value) {
return 'export.list.cs_person.neet_eligibility';
}
if ('1' === $value || true === $value || 't' === $value) {
return 'x';
}
return '';
},
'situationProfessionnelle' => function ($value) {
if ('_header' === $value) {
return 'export.list.cs_person.situation_professionelle';
}
return $value;
},
'cerinscriptiondate', 'ppaeinscriptiondate', 'neetcommissiondate', 'findernieremploidate', 'cafinscriptiondate', 'contratiejdate' => function ($value) use ($key) {
if ('_header' === $value) {
return $this->translator->trans($key);
}
if (null === $value) {
return '';
}
// warning: won't work with DateTimeImmutable as we reset time a few lines later
$date = \DateTime::createFromFormat('Y-m-d', $value);
$hasTime = false;
if (false === $date) {
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $value);
$hasTime = true;
}
// check that the creation could occur.
if (false === $date) {
throw new \Exception(sprintf('The value %s could not be converted to %s', $value, \DateTime::class));
}
if (!$hasTime) {
$date->setTime(0, 0, 0);
}
return $date;
},
default => function ($value) use ($key) {
if ('_header' === $value) {
return $this->translator->trans($key);
}
return $value;
},
};
}
}

View File

@@ -0,0 +1,395 @@
<?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\JobBundle\Export;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Entity\Person;
use Chill\JobBundle\Security\Authorization\ExportsJobVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Class ListCV.
*
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
*/
class ListCV implements ListInterface, ExportElementValidatedInterface
{
/**
* @var array
*/
public const FIELDS = [
'id' => 'integer',
'firstname' => 'string',
'lastname' => 'string',
'gender' => 'string',
'birthdate' => 'date',
'placeofbirth' => 'string',
'countryofbirth' => 'json',
'formationlevel' => 'string',
];
/**
* @var array
*/
protected $personIds = [];
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* ListAcquisition constructor.
*/
public function __construct(EntityManagerInterface $em)
{
$this->entityManager = $em;
}
/**
* validate the form's data and, if required, build a contraint
* violation on the data.
*
* @param mixed $data the data, as returned by the user
*/
public function validateForm($data, ExecutionContextInterface $context) {}
/**
* get a title, which will be used in UI (and translated).
*
* @return string
*/
public function getTitle()
{
return 'Liste des CVs par personne';
}
/**
* Add a form to collect data from the user.
*/
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('fields', ChoiceType::class, [
'multiple' => true,
'expanded' => true,
// 'choices_as_values' => true,
'label' => 'Fields to include in export',
'choices' => array_combine($this->getFields(), $this->getFields()),
'data' => array_combine($this->getFields(), $this->getFields()),
'choice_attr' => [],
'attr' => ['class' => ''],
'constraints' => [new Callback([
'callback' => function ($selected, ExecutionContextInterface $context) {
if (0 === count($selected)) {
$context
->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
}
},
])],
])
->add('reportdate_min', ChillDateType::class, [
'label' => 'Date du rapport après le',
'required' => false,
'label_attr' => [
'class' => 'reportdate_range',
],
'attr' => [
'class' => 'reportdate_range',
],
])
->add('reportdate_max', ChillDateType::class, [
'label' => 'Date du rapport avant le',
'required' => false,
'label_attr' => [
'class' => 'report_date_range',
],
'attr' => [
'class' => 'report_date_range',
],
])
;
}
/**
* Return the Export's type. This will inform _on what_ export will apply.
* Most of the type, it will be a string which references an entity.
*
* Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE
*
* @return string
*/
public function getType()
{
return Person::class;
}
/**
* A description, which will be used in the UI to explain what the export does.
* This description will be translated.
*
* @return string
*/
public function getDescription()
{
return 'Crée une liste des CVs en fonction de différents paramètres.';
}
/**
* The initial query, which will be modified by ModifiersInterface
* (i.e. AggregatorInterface, FilterInterface).
*
* This query should take into account the `$acl` and restrict result only to
* what the user is allowed to see. (Do not show personal data the user
* is not allowed to see).
*
* The returned object should be an instance of QueryBuilder or NativeQuery.
*
* @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )`
* @param array $data the data from the form, if any
*
* @return QueryBuilder|\Doctrine\ORM\NativeQuery the query to execute
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
return $this->entityManager->createQueryBuilder()
->from('ChillPersonBundle:Person', 'person');
}
/**
* Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface)
* are allowed. The modifiers should be an array of types the _modifier_ apply on
* (@see ModifiersInterface::applyOn()).
*
* @return string[]
*/
public function supportsModifiers()
{
return ['cv', 'person'];
}
/**
* Return the required Role to execute the Export.
*/
public function requiredRole(): string
{
return ExportsJobVoter::EXPORT;
}
/**
* Return which formatter type is allowed for this report.
*
* @return string[]
*/
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_LIST];
}
/**
* give the list of keys the current export added to the queryBuilder in
* self::initiateQuery.
*
* Example: if your query builder will contains `SELECT count(id) AS count_id ...`,
* this function will return `array('count_id')`.
*
* @param mixed[] $data the data from the export's form (added by self::buildForm)
*
* @return array
*/
public function getQueryKeys($data)
{
return array_keys($data['fields']);
}
/**
* Return array FIELDS keys only.
*
* @return array
*/
private function getFields()
{
return array_keys(self::FIELDS);
}
/**
* Return the results of the query builder.
*
* @param QueryBuilder|\Doctrine\ORM\NativeQuery $qb
* @param mixed[] $data the data from the export's form (added by self::buildForm)
*/
public function getResult($qb, $data)
{
$qb->select('person.id');
$ids = $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
$this->personIds = array_map(fn ($e) => $e['id'], $ids);
$personIdsParameters = '?'.\str_repeat(', ?', count($this->personIds) - 1);
$query = \str_replace('%person_ids%', $personIdsParameters, self::QUERY);
$rsm = new Query\ResultSetMapping();
foreach (self::FIELDS as $name => $type) {
if (null !== $data['fields'][$name]) {
$rsm->addScalarResult($name, $name, $type);
}
}
$nq = $this->entityManager->createNativeQuery($query, $rsm);
$idx = 1;
for ($i = 1; $i <= count($this->personIds); ++$i) {
++$idx;
$nq->setParameter($i, $this->personIds[$i - 1]);
}
$nq->setParameter($idx++, $data['reportdate_min'], 'date');
$nq->setParameter($idx, $data['reportdate_max'], 'date');
return $nq->getResult();
}
/**
* transform the results to viewable and understable string.
*
* The callable will have only one argument: the `value` to translate.
*
* The callable should also be able to return a key `_header`, which
* will contains the header of the column.
*
* The string returned **must** be already translated if necessary,
* **with an exception** for the string returned for `_header`.
*
* Example :
*
* ```
* protected $translator;
*
* public function getLabels($key, array $values, $data)
* {
* return function($value) {
* case $value
* {
* case '_header' :
* return 'my header not translated';
* case true:
* return $this->translator->trans('true');
* case false:
* return $this->translator->trans('false');
* default:
* // this should not happens !
* throw new \LogicException();
* }
* }
* ```
*
* **Note:** Why each string must be translated with an exception for
* the `_header` ? For performance reasons: most of the value will be number
* which do not need to be translated, or value already translated in
* database. But the header must be, in every case, translated.
*
* @param string $key The column key, as added in the query
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
* @param mixed $data The data from the export's form (as defined in `buildForm`
*/
public function getLabels($key, array $values, $data)
{
return match ($key) {
'birthdate' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $value->format('d-m-Y');
},
'countryofbirth' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
return $value['fr'];
},
'gender' => function ($value) use ($key) {
$gend_array = ['man' => 'Homme', 'woman' => 'Femme', 'both' => 'Indéterminé'];
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $gend_array[$value];
},
default => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
return $value;
},
};
}
/**
* Native Query SQL.
*/
public const QUERY = <<<'SQL'
SELECT
p.id as id,
p.firstname as firstname,
p.lastname as lastname,
p.gender as gender,
p.birthdate as birthdate,
p.place_of_birth as placeofbirth,
cn.name as countryofbirth,
cv.formationlevel as formationlevel
FROM
public.chill_person_person AS p
LEFT JOIN chill_job.cv AS cv
ON p.id = cv.person_id
LEFT JOIN public.country AS cn
ON p.countryofbirth_id = cn.id
-- condition 1
WHERE p.id IN (%person_ids%)
-- condition 2
AND (
cv.reportdate
BETWEEN COALESCE(?::date, '1900-01-01')
AND COALESCE(?::date, '2100-01-01')
)
ORDER BY cv.reportdate DESC
SQL;
public function getFormDefaultData(): array
{
return [];
}
}

View File

@@ -0,0 +1,497 @@
<?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\JobBundle\Export;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Entity\Person;
use Chill\JobBundle\Entity\Frein;
use Chill\JobBundle\Security\Authorization\ExportsJobVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Class ListFrein.
*
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
*/
class ListFrein implements ListInterface, ExportElementValidatedInterface
{
/**
* @var array
*/
public const FREINS = [
'freinsperso' => Frein::FREINS_PERSO,
'freinsemploi' => Frein::FREINS_EMPLOI,
];
/**
* @var array
*/
public const FIELDS = [
'id' => 'integer',
'firstname' => 'string',
'lastname' => 'string',
'gender' => 'string',
'birthdate' => 'date',
'placeofbirth' => 'string',
'countryofbirth' => 'json',
'reportdate' => 'date',
'freinsperso' => 'json',
'notesperso' => 'string',
'freinsemploi' => 'json',
'notesemploi' => 'string',
];
/**
* @var array
*/
protected $personIds = [];
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* ListAcquisition constructor.
*/
public function __construct(EntityManagerInterface $em)
{
$this->entityManager = $em;
}
/**
* validate the form's data and, if required, build a contraint
* violation on the data.
*
* @param mixed $data the data, as returned by the user
*/
public function validateForm($data, ExecutionContextInterface $context) {}
/**
* get a title, which will be used in UI (and translated).
*
* @return string
*/
public function getTitle()
{
return 'Liste des freins identifiés par personne';
}
/**
* Add a form to collect data from the user.
*/
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('fields', ChoiceType::class, [
'multiple' => true,
'expanded' => true,
// 'choices_as_values' => true,
'label' => 'Fields to include in export',
'choices' => array_combine($this->getFields(), $this->getFields()),
'data' => array_combine($this->getFields(), $this->getFields()),
'choice_attr' => [],
'attr' => ['class' => ''],
'constraints' => [new Callback([
'callback' => function ($selected, ExecutionContextInterface $context) {
if (0 === count($selected)) {
$context
->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
}
},
])],
])
->add('reportdate_min', ChillDateType::class, [
'label' => 'Date du rapport après le',
'required' => false,
'label_attr' => [
'class' => 'reportdate_range',
],
'attr' => [
'class' => 'reportdate_range',
],
])
->add('reportdate_max', ChillDateType::class, [
'label' => 'Date du rapport avant le',
'required' => false,
'label_attr' => [
'class' => 'report_date_range',
],
'attr' => [
'class' => 'report_date_range',
],
])
;
}
/**
* Return the Export's type. This will inform _on what_ export will apply.
* Most of the type, it will be a string which references an entity.
*
* Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE
*
* @return string
*/
public function getType()
{
return Person::class;
}
/**
* A description, which will be used in the UI to explain what the export does.
* This description will be translated.
*
* @return string
*/
public function getDescription()
{
return 'Crée une liste des personnes et de leurs freins identifiés en fonction de différents paramètres.';
}
/**
* The initial query, which will be modified by ModifiersInterface
* (i.e. AggregatorInterface, FilterInterface).
*
* This query should take into account the `$acl` and restrict result only to
* what the user is allowed to see. (Do not show personal data the user
* is not allowed to see).
*
* The returned object should be an instance of QueryBuilder or NativeQuery.
*
* @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )`
* @param array $data the data from the form, if any
*
* @return QueryBuilder|\Doctrine\ORM\NativeQuery the query to execute
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
return $this->entityManager->createQueryBuilder()
->from(Person::class, 'person');
}
/**
* Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface)
* are allowed. The modifiers should be an array of types the _modifier_ apply on
* (@see ModifiersInterface::applyOn()).
*
* @return string[]
*/
public function supportsModifiers()
{
return ['frein', 'person'];
}
/**
* Return the required Role to execute the Export.
*/
public function requiredRole(): string
{
return ExportsJobVoter::EXPORT;
}
/**
* Return which formatter type is allowed for this report.
*
* @return string[]
*/
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_LIST];
}
/**
* Return array FIELDS keys only.
*
* @return array
*/
private function getFields()
{
return array_keys(self::FIELDS);
}
/**
* give the list of keys the current export added to the queryBuilder in
* self::initiateQuery.
*
* Example: if your query builder will contains `SELECT count(id) AS count_id ...`,
* this function will return `array('count_id')`.
*
* @param mixed[] $data the data from the export's form (added by self::buildForm)
*
* @return array
*/
public function getQueryKeys($data)
{
$freins = self::FREINS;
$fields = [];
foreach ($data['fields'] as $key) {
switch ($key) {
case 'freinsperso':
case 'freinsemploi':
foreach ($freins[$key] as $item) {
$this->translationCompatKey($item, $key);
$fields[] = $item;
}
break;
default:
$fields[] = $key;
}
}
return $fields;
}
/**
* Make key compatible with YAML messages ids
* for fields that are splitted in columns.
*
* @param string $item (&) passed by reference
* @param string $key
*/
private function translationCompatKey(&$item, $key)
{
$prefix = substr_replace($key, 'freins_', 0, 6);
$item = $prefix.'.'.$item;
}
/**
* Some fields values are arrays that have to be splitted in columns.
* This function split theses fields.
*
* @param array $rows
*
* @return array|\Closure
*/
private function splitArrayToColumns($rows)
{
$freins = self::FREINS;
$results = [];
foreach ($rows as $row) {
/**
* @var string $key
*/
$res = [];
foreach ($row as $key => $value) {
switch ($key) {
case 'freinsperso':
case 'freinsemploi':
foreach ($freins[$key] as $item) {
$this->translationCompatKey($item, $key);
if (0 === count($value)) {
$res[$item] = '';
} else {
foreach ($value as $v) {
$this->translationCompatKey($v, $key);
if ($item === $v) {
$res[$item] = 'x';
break;
}
$res[$item] = '';
}
}
}
break;
default:
$res[$key] = $value;
}
}
$results[] = $res;
}
return $results;
}
/**
* Return the results of the query builder.
*
* @param QueryBuilder|\Doctrine\ORM\NativeQuery $qb
* @param mixed[] $data the data from the export's form (added by self::buildForm)
*/
public function getResult($qb, $data)
{
$qb->select('person.id');
$ids = $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
$this->personIds = array_map(fn ($e) => $e['id'], $ids);
$personIdsParameters = '?'.\str_repeat(', ?', count($this->personIds) - 1);
$query = \str_replace('%person_ids%', $personIdsParameters, self::QUERY);
$rsm = new Query\ResultSetMapping();
foreach (self::FIELDS as $name => $type) {
if (null !== $data['fields'][$name]) {
$rsm->addScalarResult($name, $name, $type);
}
}
$nq = $this->entityManager->createNativeQuery($query, $rsm);
$idx = 1;
for ($i = 1; $i <= count($this->personIds); ++$i) {
++$idx;
$nq->setParameter($i, $this->personIds[$i - 1]);
}
$nq->setParameter($idx++, $data['reportdate_min'], 'date');
$nq->setParameter($idx, $data['reportdate_max'], 'date');
return $this->splitArrayToColumns(
$nq->getResult()
);
}
/**
* transform the results to viewable and understable string.
*
* The callable will have only one argument: the `value` to translate.
*
* The callable should also be able to return a key `_header`, which
* will contains the header of the column.
*
* The string returned **must** be already translated if necessary,
* **with an exception** for the string returned for `_header`.
*
* Example :
*
* ```
* protected $translator;
*
* public function getLabels($key, array $values, $data)
* {
* return function($value) {
* case $value
* {
* case '_header' :
* return 'my header not translated';
* case true:
* return $this->translator->trans('true');
* case false:
* return $this->translator->trans('false');
* default:
* // this should not happens !
* throw new \LogicException();
* }
* }
* ```
*
* **Note:** Why each string must be translated with an exception for
* the `_header` ? For performance reasons: most of the value will be number
* which do not need to be translated, or value already translated in
* database. But the header must be, in every case, translated.
*
* @param string $key The column key, as added in the query
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
* @param mixed $data The data from the export's form (as defined in `buildForm`
*/
public function getLabels($key, array $values, $data)
{
return match ($key) {
'reportdate', 'birthdate' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $value->format('d-m-Y');
},
'countryofbirth' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
return $value['fr'];
},
'gender' => function ($value) use ($key) {
$gend_array = ['man' => 'Homme', 'woman' => 'Femme', 'both' => 'Indéterminé'];
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $gend_array[$value];
},
default => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $value;
},
};
}
/**
* Native Query SQL.
*/
public const QUERY = <<<'SQL'
SELECT
p.id as id,
p.firstname as firstname,
p.lastname as lastname,
p.gender as gender,
p.birthdate as birthdate,
p.place_of_birth as placeofbirth,
cn.name as countryofbirth,
fr.reportdate as reportdate,
fr.freinsperso as freinsperso,
fr.notesperso as notesperso,
fr.freinsemploi as freinsemploi,
fr.notesemploi as notesemploi
FROM
public.chill_person_person AS p
LEFT JOIN chill_job.frein AS fr
ON p.id = fr.person_id
LEFT JOIN public.country AS cn
ON p.countryofbirth_id = cn.id
-- condition 1
WHERE p.id IN (%person_ids%)
-- condition 2
AND (
fr.reportdate
BETWEEN COALESCE(?::date, '1900-01-01')
AND COALESCE(?::date, '2100-01-01')
)
ORDER BY fr.reportdate DESC
SQL;
public function getFormDefaultData(): array
{
return [];
}
}

View File

@@ -0,0 +1,586 @@
<?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\JobBundle\Export;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Entity\Person;
use Chill\JobBundle\Entity\ProjetProfessionnel;
use Chill\JobBundle\Security\Authorization\ExportsJobVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Class ListProjetProfessionnel.
*
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
*/
class ListProjetProfessionnel implements ListInterface, ExportElementValidatedInterface
{
/**
* @var array
*/
public const PPROF = [
'projet_prof__type_contrat__label' => ProjetProfessionnel::TYPE_CONTRAT,
'projet_prof__volume_horaire__label' => ProjetProfessionnel::VOLUME_HORAIRES,
];
/**
* @var array
*/
public const FIELDS = [
'id' => 'integer',
'firstname' => 'string',
'lastname' => 'string',
'gender' => 'string',
'birthdate' => 'date',
'placeofbirth' => 'string',
'countryofbirth' => 'json',
'projet_prof__souhait__code' => 'string',
'projet_prof__type_contrat__label' => 'json',
'projet_prof__type_contrat__note' => 'string',
'projet_prof__volume_horaire__label' => 'json',
'projet_prof__volume_horaire__note' => 'string',
'projet_prof__idee' => 'string',
'projet_prof__encoursdeconstruction' => 'string',
'projet_prof__valide__note' => 'string',
'projet_prof__valide__code' => 'string',
'projet_prof__note' => 'string',
];
/**
* @var array
*/
protected $personIds = [];
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* ListAcquisition constructor.
*/
public function __construct(EntityManagerInterface $em)
{
$this->entityManager = $em;
}
/**
* validate the form's data and, if required, build a contraint
* violation on the data.
*
* @param mixed $data the data, as returned by the user
*/
public function validateForm($data, ExecutionContextInterface $context) {}
/**
* get a title, which will be used in UI (and translated).
*
* @return string
*/
public function getTitle()
{
return 'Liste des projets professionnels par personne';
}
/**
* Add a form to collect data from the user.
*/
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('fields', ChoiceType::class, [
'multiple' => true,
'expanded' => true,
// 'choices_as_values' => true,
'label' => 'Fields to include in export',
'choice_label' => fn ($key) => str_replace('__', '.', (string) $key),
'choices' => array_combine($this->getFields(), $this->getFields()),
'data' => array_combine($this->getFields(), $this->getFields()),
'choice_attr' => [],
'attr' => ['class' => ''],
'constraints' => [new Callback([
'callback' => function ($selected, ExecutionContextInterface $context) {
if (0 === count($selected)) {
$context
->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
}
},
])],
])
->add('reportdate_min', ChillDateType::class, [
'label' => 'Date du rapport après le',
'required' => false,
'label_attr' => [
'class' => 'reportdate_range',
],
'attr' => [
'class' => 'reportdate_range',
],
])
->add('reportdate_max', ChillDateType::class, [
'label' => 'Date du rapport avant le',
'required' => false,
'label_attr' => [
'class' => 'report_date_range',
],
'attr' => [
'class' => 'report_date_range',
],
])
;
}
/**
* Return the Export's type. This will inform _on what_ export will apply.
* Most of the type, it will be a string which references an entity.
*
* Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE
*
* @return string
*/
public function getType()
{
return Person::class;
}
/**
* A description, which will be used in the UI to explain what the export does.
* This description will be translated.
*
* @return string
*/
public function getDescription()
{
return 'Crée une liste des personnes et de leur projet professionnel en fonction de différents paramètres.';
}
/**
* The initial query, which will be modified by ModifiersInterface
* (i.e. AggregatorInterface, FilterInterface).
*
* This query should take into account the `$acl` and restrict result only to
* what the user is allowed to see. (Do not show personal data the user
* is not allowed to see).
*
* The returned object should be an instance of QueryBuilder or NativeQuery.
*
* @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )`
* @param array $data the data from the form, if any
*
* @return QueryBuilder|\Doctrine\ORM\NativeQuery the query to execute
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
return $this->entityManager->createQueryBuilder()
->from('ChillPersonBundle:Person', 'person');
}
/**
* Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface)
* are allowed. The modifiers should be an array of types the _modifier_ apply on
* (@see ModifiersInterface::applyOn()).
*
* @return string[]
*/
public function supportsModifiers()
{
return ['projetprofessionnel', 'person'];
}
/**
* Return the required Role to execute the Export.
*/
public function requiredRole(): string
{
return ExportsJobVoter::EXPORT;
}
/**
* Return which formatter type is allowed for this report.
*
* @return string[]
*/
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_LIST];
}
/**
* Return array FIELDS keys only.
*
* @return array
*/
private function getFields()
{
return array_keys(self::FIELDS);
}
/**
* give the list of keys the current export added to the queryBuilder in
* self::initiateQuery.
*
* Example: if your query builder will contains `SELECT count(id) AS count_id ...`,
* this function will return `array('count_id')`.
*
* @param mixed[] $data the data from the export's form (added by self::buildForm)
*
* @return array
*/
public function getQueryKeys($data)
{
$projet_professionnel = self::PPROF;
$fields = [];
foreach ($data['fields'] as $key) {
switch ($key) {
case 'projet_prof__type_contrat__label':
case 'projet_prof__volume_horaire__label':
foreach ($projet_professionnel[$key] as $item) {
$this->translationCompatKey($item, $key);
$fields[] = $item;
}
break;
case 'projet_prof__souhait__code':
case 'projet_prof__type_contrat__note':
case 'projet_prof__volume_horaire__note':
case 'projet_prof__idee':
case 'projet_prof__encoursdeconstruction':
case 'projet_prof__valide__note':
case 'projet_prof__valide__code':
case 'projet_prof__note':
$key = str_replace('__', '.', (string) $key);
// no break
default:
$fields[] = $key;
}
}
return $fields;
}
/**
* Make item compatible with YAML messages ids
* for fields that are splitted in columns (with field key to replace).
*
* AVANT
* key: projet_prof__volume_horaire__label
* item: temps_plein
* APRES
* item: projet_prof.volume_horaire.temps_plein
*
* @param string $item (&) passed by reference
* @param string $key
*/
private function translationCompatKey(&$item, $key)
{
$key = str_replace('label', $item, $key);
$key = str_replace('__', '.', $key);
$item = $key;
}
/**
* Some fields values are arrays that have to be splitted in columns.
* This function split theses fields.
*
* @param array $rows
*
* @return array|\Closure
*/
private function splitArrayToColumns($rows)
{
$projet_professionnel = self::PPROF;
$results = [];
foreach ($rows as $row) {
/**
* @var string $key
*/
$res = [];
foreach ($row as $key => $value) {
switch ($key) {
case 'projet_prof__type_contrat__label':
case 'projet_prof__volume_horaire__label':
foreach ($projet_professionnel[$key] as $item) {
$this->translationCompatKey($item, $key);
if (0 === count($value)) {
$res[$item] = '';
} else {
foreach ($value as $v) {
$this->translationCompatKey($v, $key);
if ($item === $v) {
$res[$item] = 'x';
break;
}
$res[$item] = '';
}
}
}
break;
case 'projet_prof__souhait__code':
case 'projet_prof__type_contrat__note':
case 'projet_prof__volume_horaire__note':
case 'projet_prof__idee':
case 'projet_prof__encoursdeconstruction':
case 'projet_prof__valide__note':
case 'projet_prof__valide__code':
case 'projet_prof__note':
$key = str_replace('__', '.', (string) $key);
// no break
default:
$res[$key] = $value;
}
}
$results[] = $res;
}
return $results;
}
/**
* Return the results of the query builder.
*
* @param QueryBuilder|\Doctrine\ORM\NativeQuery $qb
* @param mixed[] $data the data from the export's form (added by self::buildForm)
*/
public function getResult($qb, $data)
{
$qb->select('person.id');
$ids = $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
$this->personIds = array_map(fn ($e) => $e['id'], $ids);
$personIdsParameters = '?'.\str_repeat(', ?', count($this->personIds) - 1);
$query = \str_replace('%person_ids%', $personIdsParameters, self::QUERY);
$rsm = new Query\ResultSetMapping();
foreach (self::FIELDS as $name => $type) {
if (null !== $data['fields'][$name]) {
$rsm->addScalarResult($name, $name, $type);
}
}
$nq = $this->entityManager->createNativeQuery($query, $rsm);
$idx = 1;
for ($i = 1; $i <= count($this->personIds); ++$i) {
++$idx;
$nq->setParameter($i, $this->personIds[$i - 1]);
}
$nq->setParameter($idx++, $data['reportdate_min'], 'date');
$nq->setParameter($idx, $data['reportdate_max'], 'date');
return $this->splitArrayToColumns(
$nq->getResult()
);
}
/**
* transform the results to viewable and understable string.
*
* The callable will have only one argument: the `value` to translate.
*
* The callable should also be able to return a key `_header`, which
* will contains the header of the column.
*
* The string returned **must** be already translated if necessary,
* **with an exception** for the string returned for `_header`.
*
* Example :
*
* ```
* protected $translator;
*
* public function getLabels($key, array $values, $data)
* {
* return function($value) {
* case $value
* {
* case '_header' :
* return 'my header not translated';
* case true:
* return $this->translator->trans('true');
* case false:
* return $this->translator->trans('false');
* default:
* // this should not happens !
* throw new \LogicException();
* }
* }
* ```
*
* **Note:** Why each string must be translated with an exception for
* the `_header` ? For performance reasons: most of the value will be number
* which do not need to be translated, or value already translated in
* database. But the header must be, in every case, translated.
*
* @param string $key The column key, as added in the query
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
* @param mixed $data The data from the export's form (as defined in `buildForm`
*/
public function getLabels($key, array $values, $data)
{
return match ($key) {
'birthdate' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $value->format('d-m-Y');
},
'countryofbirth' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
return $value['fr'];
},
'projet_prof.valide.code', 'projet_prof.souhait.code' => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
if ('{NULL}' === $value) {
return '';
}
return str_replace(['{', '}'], '', $value);
},
'gender' => function ($value) use ($key) {
$gend_array = ['man' => 'Homme', 'woman' => 'Femme', 'both' => 'Indéterminé'];
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $gend_array[$value];
},
default => function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
if (null === $value || '' === $value) {
return '';
}
return $value;
},
};
}
/**
* Native Query SQL.
*/
public const QUERY = <<<'SQL'
WITH projet_professionnel AS (
SELECT
pp.id,
pp.reportdate,
pp.typecontrat,
pp.typecontratnotes,
pp.volumehoraire,
pp.volumehorairenotes,
pp.idee,
pp.encoursconstruction,
pp.validenotes,
pp.projetprofessionnelnote,
ARRAY_AGG (DISTINCT rms.code) as rms_codes,
ARRAY_AGG (DISTINCT rmv.code) as rmv_codes
FROM chill_job.projet_professionnel AS pp
LEFT OUTER JOIN chill_job.projetprofessionnel_souhait AS pps
ON pp.id = pps.projetprofessionnel_id
LEFT OUTER JOIN chill_job.rome_appellation AS ras
ON pps.appellation_id = ras.id
LEFT OUTER JOIN chill_job.rome_metier AS rms
ON ras.metier_id = rms.id
LEFT OUTER JOIN chill_job.projetprofessionnel_valide AS ppv
ON pp.id = ppv.projetprofessionnel_id
LEFT OUTER JOIN chill_job.rome_appellation AS rav
ON ppv.appellation_id = rav.id
LEFT OUTER JOIN chill_job.rome_metier AS rmv
ON rav.metier_id = rmv.id
GROUP BY pp.id
)
SELECT
p.id,
p.firstname,
p.lastname,
p.gender as gender,
p.birthdate as birthdate,
p.place_of_birth as placeofbirth,
cn.name as countryofbirth,
pp.rms_codes as projet_prof__souhait__code,
pp.typecontrat as projet_prof__type_contrat__label,
pp.typecontratnotes as projet_prof__type_contrat__note,
pp.volumehoraire as projet_prof__volume_horaire__label,
pp.volumehorairenotes as projet_prof__volume_horaire__note,
pp.idee as projet_prof__idee,
pp.encoursconstruction as projet_prof__encoursdeconstruction,
pp.validenotes as projet_prof__valide__note,
pp.rmv_codes as projet_prof__valide__code,
pp.projetprofessionnelnote as projet_prof__note
FROM public.chill_person_person AS p
LEFT JOIN projet_professionnel AS pp
ON p.id = pp.id
LEFT OUTER JOIN public.country AS cn
ON p.countryofbirth_id = cn.id
-- condition 1
WHERE p.id IN (%person_ids%)
-- condition 2
AND (
pp.reportdate
BETWEEN COALESCE(?::date, '1900-01-01')
AND COALESCE(?::date, '2100-01-01')
)
ORDER BY pp.reportdate DESC
SQL;
public function getFormDefaultData(): array
{
return [];
}
}

View File

@@ -0,0 +1,125 @@
<?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\JobBundle\Form;
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\JobBundle\Entity\CSPerson;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\ChillDateType;
class CSPersonDispositifsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('accompagnement', ChoiceType::class, [
'choices' => \array_combine(CSPerson::ACCOMPAGNEMENTS, CSPerson::ACCOMPAGNEMENTS),
'required' => false,
'label' => 'Accompagnement',
'multiple' => true,
'expanded' => true,
'choice_label' => fn ($k) => 'accompagnement.'.$k,
])
->add('accompagnementRQTHDate', ChillDateType::class, [
'label' => "Date d'accompagnement RQTH",
'required' => false,
])
->add('accompagnementComment', TextareaType::class, [
'label' => 'Accompagnement autre: précisions',
'required' => false,
])
->add('poleEmploiId', TextType::class, [
'label' => 'Identifiant pôle emploi',
'required' => false,
])
->add('poleEmploiInscriptionDate', ChillDateType::class, [
'label' => "Date d'inscription Pôle emploi",
'required' => false,
])
->add('cafId', TextType::class, [
'label' => 'Numéro allocataire CAF',
'required' => false,
])
->add('cafInscriptionDate', ChillDateType::class, [
'label' => "Date d'inscription à la CAF",
'required' => false,
])
->add('cERInscriptionDate', ChillDateType::class, [
'label' => 'Date CER',
'required' => false,
])
->add('pPAEInscriptionDate', ChillDateType::class, [
'label' => 'Date PPAE',
'required' => false,
])
->add('nEETEligibilite', ChoiceType::class, [
'label' => 'Éligibilité NEET',
'choices' => \array_combine(CSPerson::NEET_ELIGIBILITY, CSPerson::NEET_ELIGIBILITY),
'choice_label' => fn ($k) => 'neet_eligibility.'.$k,
'multiple' => false,
'expanded' => true,
'required' => false,
])
->add('cERSignataire', TextType::class, [
'label' => 'Signataire CER',
'required' => false,
])
->add('pPAESignataire', TextType::class, [
'label' => 'Signataire PPAE',
'required' => false,
])
->add('nEETCommissionDate', ChillDateType::class, [
'label' => 'Date commission NEET',
'required' => false,
])
->add('fSEMaDemarcheCode', TextType::class, [
'label' => 'Code "Ma démarche FSE"',
'required' => false,
])
->add('prescripteur', PickThirdpartyDynamicType::class, [
'required' => false,
'label' => 'Prescripteur',
])
->add('dispositifsNotes', TextareaType::class, [
'required' => false,
'label' => 'Notes',
])
->add('dateContratIEJ', ChillDateType::class, [
'required' => false,
'label' => ' Date du contrat dengagement IEJ',
])
->add('dateAvenantIEJ', ChillDateType::class, [
'required' => false,
'label' => " Date de l'avenant IEJ",
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => CSPerson::class]);
$resolver
->setDefined('center')
->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class])
;
}
public function getBlockPrefix()
{
return 'job_bundle_csperson';
}
}

View File

@@ -0,0 +1,256 @@
<?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\JobBundle\Form;
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\JobBundle\Entity\CSPerson;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Chill\DocStoreBundle\Form\StoredObjectType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Chill\PersonBundle\Form\Type\Select2MaritalStatusType;
class CSPersonPersonalSituationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// quick and dirty way to handle marital status...
->add('personMaritalStatus', Select2MaritalStatusType::class, ['required' => false, 'label' => 'État civil'])
->add('situationLogement', ChoiceType::class, [
'choices' => \array_combine(
CSPerson::SITUATIONS_LOGEMENTS,
CSPerson::SITUATIONS_LOGEMENTS
),
'choice_label' => fn ($k) => 'situation_logement.'.$k,
'required' => false,
'label' => 'Situation de logement',
'multiple' => false,
'expanded' => true,
])
->add('situationLogementPrecision', TextareaType::class, [
'label' => 'Précisions',
'required' => false,
])
->add('enfantACharge', IntegerType::class, [
'label' => 'Enfants à charge',
'required' => false,
])
->add('niveauMaitriseLangue', ChoiceType::class, [
'choices' => \array_combine(
CSPerson::NIVEAU_MAITRISE_LANGUE,
CSPerson::NIVEAU_MAITRISE_LANGUE
),
'choice_label' => fn ($k) => 'niveau_maitrise_langue.'.$k,
'multiple' => true,
'required' => false,
'expanded' => true,
'label' => 'Maitrise de la langue française',
])
->add('vehiculePersonnel', ChoiceType::class, [
'choices' => [
'Oui' => true,
'Non' => false,
],
'required' => false,
'multiple' => false,
])
->add('permisConduire', ChoiceType::class, [
'choices' => [
\array_combine(CSPerson::PERMIS_CONDUIRE, CSPerson::PERMIS_CONDUIRE),
],
'label' => 'Permis de conduire',
'required' => false,
'multiple' => true,
'expanded' => true,
'choice_label' => fn ($k) => 'permis_conduire.'.$k,
])
->add('situationProfessionnelle', ChoiceType::class, [
'choices' => \array_combine(CSPerson::SITUATION_PROFESSIONNELLE, CSPerson::SITUATION_PROFESSIONNELLE),
'required' => false,
'multiple' => false,
'expanded' => true,
'choice_label' => fn ($k) => 'situation_professionnelle.'.$k,
])
->add('dateFinDernierEmploi', ChillDateType::class, [
'label' => 'Date de la fin du dernier emploi',
'required' => false,
])
->add('typeContrat', ChoiceType::class, [
'choices' => \array_combine(CSPerson::TYPE_CONTRAT, CSPerson::TYPE_CONTRAT),
'label' => 'Type de contrat',
'required' => false,
'multiple' => true,
'expanded' => true,
'choice_label' => fn ($k) => 'type_contrat.'.$k,
])
->add('typeContratAide', TextType::class, [
'label' => 'Type de contrat aidé',
'required' => false,
])
->add('ressources', ChoiceType::class, [
'choices' => \array_combine(CSPerson::RESSOURCES, CSPerson::RESSOURCES),
'choice_label' => fn ($k) => 'ressource.'.$k,
'required' => false,
'multiple' => true,
'expanded' => true,
])
->add('ressourcesComment', TextareaType::class, [
'label' => 'Information autre ressource',
'required' => false,
])
->add('ressourceDate1Versement', ChillDateType::class, [
'label' => "Date du premier versement (si bénéficiaire d'une aide)",
'required' => false,
])
->add('cPFMontant', MoneyType::class, [
'label' => 'Montant CPF',
'required' => false,
])
->add('acompteDIF', MoneyType::class, [
'label' => 'Compte DIF',
'required' => false,
])
->add('handicapIs', ChoiceType::class, [
'label' => 'Handicap',
'required' => false,
'choices' => [
'Oui' => true,
'Non' => false,
],
'multiple' => false,
'expanded' => true,
])
->add('handicapNotes', TextareaType::class, [
'label' => 'Type de handicap',
'required' => false,
])
->add('handicapRecommandation', ChoiceType::class, [
'label' => 'Recommandation',
'required' => false,
'multiple' => false,
'expanded' => true,
'choices' => \array_combine(CSPerson::HANDICAP_RECOMMANDATIONS, CSPerson::HANDICAP_RECOMMANDATIONS),
'choice_label' => fn ($k) => 'handicap_recommandation.'.$k,
])
->add('handicapAccompagnement', PickThirdpartyDynamicType::class, [
'required' => false,
'multiple' => false,
])
->add('mobiliteMoyenDeTransport', ChoiceType::class, [
'required' => false,
'multiple' => true,
'expanded' => true,
'label' => 'Moyens de transports accessibles',
'choices' => \array_combine(
CSPerson::MOBILITE_MOYEN_TRANSPORT,
CSPerson::MOBILITE_MOYEN_TRANSPORT
),
'choice_label' => fn ($k) => 'moyen_transport.'.$k,
])
->add('mobiliteNotes', TextareaType::class, [
'required' => false,
'label' => 'Notes concernant la mobilité',
])
->add('documentCV', StoredObjectType::class, [
'label' => 'CV',
'required' => false,
'error_bubbling' => false,
])
->add('documentAgrementIAE', StoredObjectType::class, [
'label' => 'Document Agrément IAE',
'required' => false,
'error_bubbling' => false,
])
->add('documentRQTH', StoredObjectType::class, [
'label' => 'Document RQTH',
'required' => false,
'error_bubbling' => false,
])
->add('documentAttestationNEET', StoredObjectType::class, [
'label' => 'Attestation NEET',
'required' => false,
'error_bubbling' => false,
])
->add('documentCI', StoredObjectType::class, [
'label' => 'Carte d\'identité',
'required' => false,
'error_bubbling' => false,
])
->add('documentTitreSejour', StoredObjectType::class, [
'label' => 'Titre de séjour',
'required' => false,
'error_bubbling' => false,
])
->add('documentAttestationFiscale', StoredObjectType::class, [
'label' => 'Attestation fiscale',
'required' => false,
'error_bubbling' => false,
])
->add('documentPermis', StoredObjectType::class, [
'label' => 'Permis',
'required' => false,
'error_bubbling' => false,
])
->add('documentAttestationCAAF', StoredObjectType::class, [
'label' => 'Attestation CAF',
'required' => false,
'error_bubbling' => false,
])
->add('documentContraTravail', StoredObjectType::class, [
'label' => 'Contrat de travail',
'required' => false,
'error_bubbling' => false,
])
->add('documentAttestationFormation', StoredObjectType::class, [
'label' => 'Attestation formation',
'required' => false,
'error_bubbling' => false,
])
->add('documentQuittanceLoyer', StoredObjectType::class, [
'label' => 'Quittance de loyer',
'required' => false,
'error_bubbling' => false,
])
->add('documentFactureElectricite', StoredObjectType::class, [
'label' => 'Facture d\'électricité',
'required' => false,
'error_bubbling' => false,
])
->add('documentAttestationSecuriteSociale', StoredObjectType::class, [
'label' => 'Attestation de sécurité sociale',
'required' => false,
'error_bubbling' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => CSPerson::class]);
$resolver->setRequired('center')
->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class])
;
}
public function getBlockPrefix()
{
return 'job_bundle_csperson';
}
}

View File

@@ -0,0 +1,70 @@
<?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\JobBundle\Form\CV;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Chill\JobBundle\Entity\CV\Experience;
class ExperienceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('poste', TextType::class, [
'required' => true,
'label' => 'Poste',
'label_attr' => [
'class' => 'required ',
],
])
->add('structure', TextType::class, [
'required' => false,
'label' => 'Nom de la structure',
])
->add('startDate', ChillDateType::class, [
'required' => false,
'label' => 'Date de début',
])
->add('endDate', ChillDateType::class, [
'required' => false,
'label' => 'Date de fin',
])
->add('contratType', ChoiceType::class, [
'required' => false,
'expanded' => true,
'multiple' => false,
'choices' => \array_combine(Experience::CONTRAT_TYPE, Experience::CONTRAT_TYPE),
'choice_label' => fn ($k) => 'xp_contrat_type.'.$k,
])
->add('notes', TextareaType::class, [
'label' => 'Notes',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Experience::class]);
}
public function getBlockPrefix()
{
return 'job_bundle_cv_experience';
}
}

View File

@@ -0,0 +1,75 @@
<?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\JobBundle\Form\CV;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\JobBundle\Entity\CV\Formation as F;
class FormationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, [
'required' => true,
'label' => 'Nom de la formation',
'label_attr' => [
'class' => 'required ',
],
])
->add('organisme', TextType::class, [
'label' => 'Organisme',
'required' => false,
])
->add('startDate', ChillDateType::class, [
'required' => false,
'label' => 'Date de début',
])
->add('endDate', ChillDateType::class, [
'required' => false,
'label' => 'Date de fin',
])
->add('diplomaObtained', ChoiceType::class, [
'label' => 'Diplôme obtenu ?',
'required' => false,
'multiple' => false,
'expanded' => true,
'choices' => \array_combine(F::DIPLOMA_OBTAINED, F::DIPLOMA_OBTAINED),
'choice_label' => fn ($k) => 'diploma_obtained.'.$k,
])
->add('diplomaReconnue', ChoiceType::class, [
'label' => 'Diplôme reconnu en France ?',
'required' => false,
'multiple' => false,
'expanded' => true,
'choices' => \array_combine(F::DIPLOMA_RECONNU, F::DIPLOMA_RECONNU),
'choice_label' => fn ($k) => 'diploma_reconnu.'.$k,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => F::class]);
}
public function getBlockPrefix()
{
return 'job_bundle_cv_formation';
}
}

View File

@@ -0,0 +1,91 @@
<?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\JobBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Chill\JobBundle\Entity\CV;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\JobBundle\Form\CV\FormationType;
use Chill\JobBundle\Form\CV\ExperienceType;
use Chill\MainBundle\Form\Type\Select2LanguageType;
class CVType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reportDate', ChillDateType::class, [
'label' => 'Date de rédaction du CV',
])
->add('formationLevel', ChoiceType::class, [
'label' => 'Niveau de formation',
'required' => true,
'multiple' => false,
'expanded' => true,
'choices' => \array_combine(CV::FORMATION_LEVEL, CV::FORMATION_LEVEL),
'choice_label' => fn ($k) => 'formation_level.'.$k,
])
->add('formationType', ChoiceType::class, [
'label' => 'Type de formation',
'required' => false,
'multiple' => false,
'expanded' => true,
'choices' => \array_combine(CV::FORMATION_TYPE, CV::FORMATION_TYPE),
'choice_label' => fn ($k) => 'formation_type.'.$k,
])
->add('spokenLanguages', Select2LanguageType::class, [
'required' => false,
'multiple' => true,
])
->add('notes', TextareaType::class, [
'label' => 'Note',
'required' => false,
])
->add('formations', ChillCollectionType::class, [
'label' => 'Formations',
'entry_type' => FormationType::class,
'allow_add' => true,
'allow_delete' => true,
'button_add_label' => 'Ajouter une formation',
'button_remove_label' => 'Retirer cette formation',
'required' => false,
'by_reference' => false,
'block_name' => 'formation_list',
])
->add('experiences', ChillCollectionType::class, [
'label' => 'Expériences',
'entry_type' => ExperienceType::class,
'allow_add' => true,
'allow_delete' => true,
'button_add_label' => 'Ajouter une expérience',
'button_remove_label' => 'Retirer cette expérience',
'required' => false,
'by_reference' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => CV::class]);
}
public function getBlockPrefix()
{
return 'job_bundle_cv';
}
}

View File

@@ -0,0 +1,155 @@
<?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\JobBundle\Form\ChoiceLoader;
use Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation;
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
use Chill\JobBundle\Entity\Rome\Appellation;
use Doctrine\ORM\EntityManagerInterface;
use Chill\JobBundle\Entity\Rome\Metier;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Lazy load third parties.
*/
class RomeAppellationChoiceLoader implements ChoiceLoaderInterface
{
/**
* @var Appellation[]
*/
protected $lazyLoadedAppellations = [];
/**
* @var EntityManagerInterface
*/
protected $em;
/**
* @var \Chill\JobBundle\Repository\Rome\AppellationRepository
*/
protected $appellationRepository;
/**
* @var PartenaireRomeAppellation;
*/
protected $apiAppellation;
/**
* @var ValidatorInterface
*/
protected $validator;
/**
* @var array<string, array{0: Appellation, 1: Metier}>
*/
private $toBeCreated = [];
public function __construct(
EntityManagerInterface $em,
PartenaireRomeAppellation $apiAppellation,
ValidatorInterface $validator
) {
$this->em = $em;
$this->apiAppellation = $apiAppellation;
$this->appellationRepository = $em->getRepository(Appellation::class);
$this->validator = $validator;
}
public function loadChoiceList($value = null): ChoiceListInterface
{
return new ArrayChoiceList($this->lazyLoadedAppellations, $value);
}
public function loadChoicesForValues($values, $value = null)
{
$choices = [];
$code = '';
foreach ($values as $v) {
if (null === $v || '' === $v) {
continue;
}
// start with "original-" ? then we load from api
if (str_starts_with($v, 'original-')) {
$code = \substr($v, \strlen('original-'));
$appellation = $this->appellationRepository->findOneBy(['code' => $code]);
if ($appellation) {
$metier = $appellation->getMetier();
}
if (null === $appellation) {
if (array_key_exists($v, $this->toBeCreated)) {
[$appellation, $metier] = $this->toBeCreated[$v];
}
}
} else {
$id = $v;
$appellation = $this->appellationRepository->find($id);
$metier = $appellation->getMetier();
}
if (null === $appellation && '' !== $code) {
$def = $this->apiAppellation->getAppellation($code);
$metier ??= $this->em->getRepository(Metier::class)
->findOneBy(['code' => $def['metier']['code']])
?? (new Metier())
->setCode($def['metier']['code'])
->setLibelle($def['metier']['libelle']);
$appellation = new Appellation();
$appellation
->setCode($def['code'])
->setLibelle($def['libelle'])
->setMetier($metier)
;
$errorsAppellation = $this->validator->validate($appellation);
$errorsMetier = $this->validator->validate($metier);
if (0 === $errorsAppellation->count() && 0 === $errorsMetier->count()) {
$this->toBeCreated[$v] = [$appellation, $metier];
$this->em->persist($appellation);
}
}
if ($this->em->contains($metier) and $this->em->contains($appellation)) {
$choices[] = $appellation;
}
}
return $choices;
}
public function loadValuesForChoices(array $choices, $value = null)
{
$values = [];
foreach ($choices as $choice) {
if (null === $choice) {
$values[] = null;
continue;
}
$id = \call_user_func($value, $choice);
$this->lazyLoadedAppellations[$id] = $choice;
}
return $this->loadChoiceList($value)->getValuesForChoices($choices);
}
}

View File

@@ -0,0 +1,66 @@
<?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\JobBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\JobBundle\Entity\Frein;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
class FreinType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reportDate', ChillDateType::class, [
'label' => 'Date du rapport',
])
->add('freinsPerso', ChoiceType::class, [
'label' => 'Freins identifiés liés à la situation personnelle',
'choices' => \array_combine(Frein::FREINS_PERSO, Frein::FREINS_PERSO),
'choice_label' => fn ($k) => 'freins_perso.'.$k,
'required' => false,
'expanded' => true,
'multiple' => true,
])
->add('freinsEmploi', ChoiceType::class, [
'label' => 'Freins identifiés liés à la situation professionnelle',
'choices' => \array_combine(Frein::FREINS_EMPLOI, Frein::FREINS_EMPLOI),
'choice_label' => fn ($k) => 'freins_emploi.'.$k,
'required' => false,
'expanded' => true,
'multiple' => true,
])
->add('notesPerso', TextareaType::class, [
'label' => 'Notes concernant la situation personnelle',
'required' => false,
])
->add('notesEmploi', TextareaType::class, [
'label' => 'Notes concernant l\'accès à l\'emploi',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Frein::class]);
}
public function getBlockPrefix()
{
return 'job_bundle_frein';
}
}

View File

@@ -0,0 +1,197 @@
<?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\JobBundle\Form;
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
use Chill\MainBundle\Form\Type\PickAddressType;
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Chill\MainBundle\Form\Type\DateIntervalType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\JobBundle\Entity\Immersion;
class ImmersionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ('immersion' === $options['step']) {
$builder
->add('entreprise', PickThirdpartyDynamicType::class, [
'label' => "Identité de l'entreprise",
'required' => true,
'multiple' => false,
])
->add('domaineActivite', TextType::class, [
'label' => "Domaine d'activité",
'required' => true,
])
->add('tuteurName', TextType::class, [
'label' => 'Nom du tuteur',
'required' => true,
])
->add('tuteurFonction', TextType::class, [
'label' => 'Fonction du tuteur',
'required' => true,
])
->add('tuteurPhoneNumber', ChillPhoneNumberType::class, [
'label' => 'Téléphone du tuteur',
'required' => true,
])
->add('structureAccName', TextType::class, [
'label' => 'Nom de la structure',
'required' => false,
])
->add('structureAccPhonenumber', ChillPhoneNumberType::class, [
'label' => 'Téléphone de la structure',
'required' => false,
])
->add('structureAccEmail', EmailType::class, [
'label' => 'Email de la structure',
'required' => false,
])
->add('structureAccAddress', PickAddressType::class, [
'label' => 'Addresse de la structure d\'accompagnement',
'required' => false,
])
->add('posteTitle', TextType::class, [
'label' => 'Intitulé du poste',
'required' => true,
])
->add('posteLieu', TextType::class, [
'label' => "Lieu d'exercice",
'required' => true,
])
->add('debutDate', ChillDateType::class, [
'label' => "Date de début de l'immersion",
'required' => true,
])
->add('duration', DateIntervalType::class, [
'unit_choices' => [
'Weeks' => 'W',
'Months' => 'M',
'Days' => 'D',
],
'label' => "Durée de l'immersion",
'required' => true,
])
->add('horaire', TextareaType::class, [
'label' => 'Horaire du stagiaire',
'required' => true,
])
->add('objectifs', ChoiceType::class, [
'label' => 'Objectifs',
'required' => false,
'multiple' => true,
'expanded' => true,
'choices' => \array_combine(Immersion::OBJECTIFS, Immersion::OBJECTIFS),
'choice_label' => fn ($k) => 'immersion_objectif.'.$k,
])
->add('objectifsAutre', TextareaType::class, [
'label' => 'Précision sur les objectifs',
'required' => false,
])
->add('noteImmersion', TextareaType::class, [
'label' => 'Note',
'required' => false,
])
;
} elseif ('bilan' === $options['step']) {
$builder
->add('savoirEtre', ChoiceType::class, [
'label' => 'Savoir-être du jeune',
'required' => false,
'multiple' => true,
'expanded' => true,
'choices' => \array_combine(Immersion::SAVOIR_ETRE, Immersion::SAVOIR_ETRE),
'choice_label' => fn ($k) => 'immersion_savoir_etre.'.$k,
])
->add('savoirEtreNote', TextareaType::class, [
'label' => 'Note',
'required' => false,
])
->add('principalesActivites', TextareaType::class, [
'label' => 'Principales activités',
'required' => false,
])
->add('competencesAcquises', TextareaType::class, [
'label' => 'Compétences acquises',
'required' => false,
])
->add('competencesADevelopper', TextareaType::class, [
'label' => 'Compétences à développer',
'required' => false,
])
->add('noteBilan', TextareaType::class, [
'label' => 'Notes sur le bilan',
'required' => false,
])
;
foreach ([
['ponctualiteSalarie', Immersion::PONCTUALITE_SALARIE, 'Ponctualité du salarié'],
['assiduite', Immersion::ASSIDUITE, 'Assiduité'],
['interetActivite', Immersion::YES_NO_NSP, 'La personne sintéresse à lensemble des activités et membres de lentreprise'],
['integreRegle', Immersion::INTEGRE_REGLE, 'La personne a intégré les règles (les principes) de lentreprise'],
['espritInitiative', Immersion::YES_NO_NSP, 'La personne fait preuve desprit dinitiative'],
['organisation', Immersion::YES_NO_NSP, 'La personne a fait preuve dorganisation'],
['capaciteTravailEquipe', Immersion::YES_NO_NSP, 'Sa capacité à travailler en équipe'],
['styleVestimentaire', Immersion::YES_NO_NSP, 'Style vestimentaire adapté'],
['langageProf', Immersion::YES_NO_NSP, 'Langage professionnel'],
['appliqueConsigne', Immersion::YES_NO_NSP, 'Applique les consignes'],
['respectHierarchie', Immersion::YES_NO_NSP, 'Respecte les niveaux hiérarchiques'],
] as [$name, $choices, $label]) {
$builder
->add($name, ChoiceType::class, [
'label' => $label,
'multiple' => false,
'required' => false,
'expanded' => true,
'choices' => $choices,
'choice_label' => function ($el) use ($choices, $name) {
if (Immersion::YES_NO_NSP === $choices) {
return 'immersion_nsp.'.$el;
}
return 'immersion_'.$name.'.'.$el;
},
])
->add($name.'Note', TextareaType::class, [
'label' => 'Notes',
'required' => false,
]);
}
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Immersion::class, 'step' => 'immersion']);
$resolver
->setAllowedValues('step', ['immersion', 'bilan'])
->setRequired('center')
->setAllowedTypes('center', \Chill\MainBundle\Entity\Center::class)
;
}
public function getBlockPrefix()
{
return 'job_bundle_immersion';
}
}

View File

@@ -0,0 +1,108 @@
<?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\JobBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\JobBundle\Entity\ProjetProfessionnel;
use Chill\JobBundle\Form\Type\PickRomeAppellationType;
class ProjetProfessionnelType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('souhait', PickRomeAppellationType::class, [
'label' => 'Souhait',
'multiple' => true,
'required' => false,
])
->add('domaineActiviteSouhait', TextareaType::class, [
'label' => "Domaine d'activité souhaité",
'required' => false,
])
->add('reportDate', ChillDateType::class, [
'label' => 'Date',
'required' => true,
])
->add('typeContrat', ChoiceType::class, [
'label' => 'Type de contrat recherché',
'multiple' => true,
'expanded' => true,
'choices' => \array_combine(
ProjetProfessionnel::TYPE_CONTRAT,
ProjetProfessionnel::TYPE_CONTRAT
),
'choice_label' => fn ($k) => 'projet_prof.type_contrat.'.$k,
])
->add('typeContratNotes', TextareaType::class, [
'label' => 'Notes concernant le contrat recherché',
'required' => false,
])
->add('volumeHoraire', ChoiceType::class, [
'label' => 'Volume horaire',
'multiple' => true,
'expanded' => true,
'required' => true,
'choices' => \array_combine(
ProjetProfessionnel::VOLUME_HORAIRES,
ProjetProfessionnel::VOLUME_HORAIRES
),
'choice_label' => fn ($k) => 'projet_prof.volume_horaire.'.$k,
])
->add('volumeHoraireNotes', TextareaType::class, [
'label' => 'Notes concernant le volume horaire',
'required' => false,
])
->add('idee', TextareaType::class, [
'label' => 'Idée',
'required' => false,
])
->add('enCoursConstruction', TextareaType::class, [
'label' => 'En cours de construction',
'required' => false,
])
->add('valide', PickRomeAppellationType::class, [
'label' => 'Validé',
'multiple' => true,
'by_reference' => false,
'required' => false,
])
->add('domaineActiviteValide', TextareaType::class, [
'label' => "Domaine d'activité validé",
'required' => false,
])
->add('valideNotes', TextareaType::class, [
'label' => 'Validé (notes)',
'required' => false,
])
->add('projetProfessionnelNote', TextareaType::class, [
'label' => 'Notes concernant le projet professionnel',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => ProjetProfessionnel::class]);
}
public function getBlockPrefix()
{
return 'job_bundle_projetprofessionnel';
}
}

View File

@@ -0,0 +1,116 @@
<?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\JobBundle\Form\Type;
use Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormBuilderInterface;
use Chill\JobBundle\Entity\Rome\Appellation;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\OptionsResolver\Options;
use Chill\JobBundle\Form\ChoiceLoader\RomeAppellationChoiceLoader;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Allow to grab an appellation.
*/
class PickRomeAppellationType extends AbstractType
{
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* @var UrlGeneratorInterface
*/
protected $urlGenerator;
// /**
// *
// * @var \Chill\JobBundle\Form\DataTransformer\RomeAppellationTransformer
// */
// protected $romeAppellationTransformer;
/**
* @var EntityManagerInterface
*/
protected $em;
/**
* @var PartenaireRomeAppellation
*/
protected $apiPartenaire;
/**
* @var ValidatorInterface
*/
protected $validator;
/**
* PickRomeAppellationType constructor.
*/
public function __construct(
TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator,
EntityManagerInterface $em,
PartenaireRomeAppellation $apiPartenaire,
ValidatorInterface $validator
) {
$this->translator = $translator;
$this->urlGenerator = $urlGenerator;
$this->em = $em;
$this->apiPartenaire = $apiPartenaire;
$this->validator = $validator;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ->addModelTransformer($this->romeAppellationTransformer)
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('class', Appellation::class)
->setDefault('choice_label', fn (Appellation $a) => $a->getLibelle())
->setDefault('placeholder', 'Choisir une appellation')
->setDefault('attr', ['class' => 'select2 '])
->setDefault('choice_loader', fn (Options $o) => new RomeAppellationChoiceLoader(
$this->em,
$this->apiPartenaire,
$this->validator
))
;
}
public function getParent()
{
return EntityType::class;
}
public function buildView(\Symfony\Component\Form\FormView $view, \Symfony\Component\Form\FormInterface $form, array $options)
{
$view->vars['attr']['data-rome-appellation-picker'] = true;
$view->vars['attr']['data-select-interactive-loading'] = true;
$view->vars['attr']['data-search-url'] = $this->urlGenerator
->generate('chill_france_travail_api_appellation_search', ['_format' => 'json']);
$view->vars['attr']['data-placeholder'] = 'Choisir une appellation';
$view->vars['attr']['data-no-results-label'] = $this->translator->trans('select2.no_results');
$view->vars['attr']['data-error-load-label'] = $this->translator->trans('select2.error_loading');
$view->vars['attr']['data-searching-label'] = $this->translator->trans('select2.searching');
}
}

View File

@@ -0,0 +1,72 @@
<?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\JobBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Chill\JobBundle\Security\Authorization\JobVoter;
class MenuBuilder implements LocalMenuBuilderInterface
{
/**
* @var AuthorizationCheckerInterface
*/
protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var \Chill\PersonBundle\Entity\Person $person */
$person = $parameters['person'];
if ($this->authorizationChecker->isGranted(JobVoter::REPORT_NEW, $person)) {
$menu->addChild('Situation personnelle', [
'route' => 'chill_crud_job_personal_situation_view',
'routeParameters' => [
'person' => $person->getId(),
],
])
->setExtras([
'order' => 50,
]);
$menu->addChild('Dispositifs', [
'route' => 'chill_crud_job_dispositifs_view',
'routeParameters' => [
'person' => $person->getId(),
],
])
->setExtras([
'order' => 51,
]);
}
$menu->addChild('Emploi', [
'route' => 'chill_job_report_index',
'routeParameters' => [
'person' => $person->getId(),
],
])
->setExtras([
'order' => 52,
]);
}
public static function getMenuIds(): array
{
return ['person'];
}
}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository;
/**
* CSPersonRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class CSPersonRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository\CV;
/**
* ExperienceRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ExperienceRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository\CV;
/**
* FormationRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class FormationRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository;
/**
* CVRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class CVRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository;
/**
* FreinRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class FreinRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository;
/**
* ImmersionRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ImmersionRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository;
/**
* ProjetProfessionnelRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ProjetProfessionnelRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository\Rome;
/**
* AppellationRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class AppellationRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,20 @@
<?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\JobBundle\Repository\Rome;
/**
* MetierRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class MetierRepository extends \Doctrine\ORM\EntityRepository {}

View File

@@ -0,0 +1,3 @@
chill_job_controllers:
resource: "@ChillJobBundle/Controller"
type: annotation

View File

@@ -0,0 +1,12 @@
imports:
- './services/3party_type.yml'
- './services/menu.yml'
- './services/security.yml'
- './services/controller.yml'
- './services/form.yml'
- './services/export.yml'
services:
# cs_connectes_sp.example:
# class: Chill\JobBundle\Example
# arguments: ["@service_id", "plain_value", "%parameter%"]

View File

@@ -0,0 +1,9 @@
services:
Chill\JobBundle\ThirdParty\PrescripteurType:
tags:
- { name: chill_3party.provider }
Chill\JobBundle\ThirdParty\EntrepriseType:
tags:
- { name: chill_3party.provider }

View File

@@ -0,0 +1,8 @@
services:
_defaults:
autowire: true
autoconfigure: true
Chill\JobBundle\Controller\:
resource: '../../../Controller'
tags: ['controller.service_arguments']

View File

@@ -0,0 +1,20 @@
services:
_defaults:
autowire: true
autoconfigure: true
Chill\JobBundle\Export\AddCSPersonToPersonListHelper:
tags:
- { name: chill_person.list_person_customizer }
Chill\JobBundle\Export\ListCV:
tags:
- { name: chill.export, alias: list_CV }
Chill\JobBundle\Export\ListFrein:
tags:
- { name: chill.export, alias: list_Frein }
Chill\JobBundle\Export\ListProjetProfessionnel:
tags:
- { name: chill.export, alias: list_ProjetProfessionnel }

View File

@@ -0,0 +1,8 @@
services:
Chill\JobBundle\Form\Type\PickRomeAppellationType:
autowire: true
tags:
- { name: form.type }
Chill\JobBundle\Form\DataTransformer\RomeAppellationTransformer:
autowire: true

View File

@@ -0,0 +1,6 @@
services:
Chill\JobBundle\Menu\MenuBuilder:
arguments:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
tags:
- { name: 'chill.menu_builder' }

View File

@@ -0,0 +1,13 @@
services:
Chill\JobBundle\Security\Authorization\JobVoter:
autowire: true
autoconfigure: true
tags:
- { name: security.voter }
Chill\JobBundle\Security\Authorization\ExportsJobVoter:
autowire: true
autoconfigure: true
tags:
- { name: security.voter }

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1 @@
require('./footer_bandeau.jpg');

View File

@@ -0,0 +1,43 @@
import { ShowHide } from 'ShowHide/show_hide.js';
// listen to adding of formation and register a show hide
var make_show_hide = function(entry) {
let
obtained = entry.querySelector('[data-diploma-obtained]'),
reconnue = entry.querySelector('[data-diploma-reconnue]')
;
var a = new ShowHide({
load_event: null,
froms: [ obtained ],
container: [ reconnue ],
test: function(froms, event) {
for (let f of froms.values()) {
for (let input of f.querySelectorAll('input').values()) {
if (input.value === 'non-fr') {
return input.checked;
}
}
}
return false;
}
});
};
window.addEventListener('collection-add-entry', function(e) {
if (e.detail.collection.dataset.collectionName === 'formations') {
make_show_hide(e.detail.entry);
}
});
// starting the formation on load
window.addEventListener('load', function(_e) {
let
formations = document.querySelectorAll('[data-formation-entry]')
;
for (let f of formations.values()) {
make_show_hide(f);
}
});

View File

@@ -0,0 +1,72 @@
import { ShowHide } from 'ShowHide/show_hide.js';
var
div_accompagnement = document.getElementById("form_accompagnement"),
div_accompagnement_rqth = document.getElementById("form_accompagnement_rqth"),
div_accompagnement_comment = document.getElementById("form_accompagnement_comment"),
div_caf_id = document.getElementById("cafId"),
div_caf_inscription_date = document.getElementById("cafInscriptionDate"),
div_neet_eligibilite = document.getElementById("neetEligibilite"),
div_neet_commission_date = document.getElementById("neetCommissionDate")
;
// faire apparaitre / disparaitre RQTH si RQTH coché
new ShowHide({
"froms": [div_accompagnement],
"test": function(froms, event) {
for (let el of froms.values()) {
for (let input of el.querySelectorAll('input').values()) {
if (input.value === 'rqth') {
return input.checked;
}
}
}
},
"container": [div_accompagnement_rqth]
});
// faire apparaitre / disparaitre commetnaire si coché
new ShowHide({
"froms": [div_accompagnement],
"test": function(froms, event) {
for (let el of froms.values()) {
for (let input of el.querySelectorAll('input').values()) {
if (input.value === 'autre') {
return input.checked;
}
}
}
return false;
},
"container": [div_accompagnement_comment]
});
// faire apparaitre cafInscriptionDate seulement si cafID est rempli
new ShowHide({
froms: [ div_caf_id ],
test: function(froms, event) {
for (let el of froms.values()) {
return el.querySelector("input").value !== "";
}
},
container: [ div_caf_inscription_date ],
event_name: 'input'
});
// faire apparaitre date de commission neet seulement si eligible
new ShowHide({
froms: [ div_neet_eligibilite ],
test: function(froms, event) {
for (let el of froms.values()) {
for (let input of el.querySelectorAll('input').values()) {
if (input.value === "oui") {
return input.checked;
}
}
}
return false;
},
container: [ div_neet_commission_date ]
});

View File

@@ -0,0 +1,20 @@
import { ShowHide } from 'ShowHide/show_hide.js';
var
div_objectifs = document.getElementById("objectifs"),
div_objectifs_autre = document.getElementById("objectifsAutre")
;
new ShowHide({
froms: [div_objectifs],
container: [div_objectifs_autre],
test: function(froms, event) {
for (let el of froms.values()) {
for (let input of el.querySelectorAll('input').values()) {
if (input.value === 'autre') {
return input.checked;
}
}
}
}
});

View File

@@ -0,0 +1,103 @@
import { ShowHide } from 'ShowHide/show_hide.js';
var
ressources = document.getElementById("ressources"),
ressources_comment = document.getElementById("ressourcesComment"),
handicap_is = document.getElementById('handicap_is'),
handicap_if = document.getElementById('handicap_if'),
situation_prof = document.getElementById('situation_prof'),
type_contrat = document.getElementById('type_contrat'),
type_contrat_aide = document.getElementById('type_contrat_aide'),
situation_logement = document.getElementById('situation_logement'),
situation_logement_precision = document.getElementById('situation_logement_precision')
;
new ShowHide({
froms: [ressources],
container: [ressources_comment],
test: function(froms) {
for (let f of froms.values()) {
for (let input of f.querySelectorAll('input').values()) {
if (input.value === 'autre') {
return input.checked;
}
}
}
}
});
new ShowHide({
froms: [handicap_is],
container: [handicap_if],
test: function(froms) {
for (let f of froms.values()) {
for (let input of f.querySelectorAll('input').values()) {
if (input.value === '1') {
return input.checked;
}
}
}
return false;
}
});
var show_hide_contrat_aide = new ShowHide({
froms: [type_contrat],
container: [type_contrat_aide],
test: function(froms) {
for (let f of froms.values()) {
for (let input of f.querySelectorAll('input').values()) {
if (input.value === 'contrat_aide') {
return input.checked;
}
}
}
return false;
}
});
new ShowHide({
id: 'situation_prof_type_contrat',
froms: [situation_prof],
container: [type_contrat],
test: function(froms) {
for (let f of froms.values()) {
for (let input of f.querySelectorAll('input').values()) {
if (input.value === 'en_activite') {
return input.checked;
}
}
}
return false;
}
});
window.addEventListener('show-hide-hide', function (e) {
if (e.detail.id = 'situation_prof_type_contrat') {
show_hide_contrat_aide.forceHide();
}
});
window.addEventListener('show-hide-show', function (e) {
if (e.detail.id = 'situation_prof_type_contrat') {
show_hide_contrat_aide.forceCompute();
}
});
new ShowHide({
froms: [situation_logement],
container: [situation_logement_precision],
test: function(froms) {
for (let f of froms.values()) {
for (let input of f.querySelectorAll('input')) {
if (input.value === 'heberge_chez_tiers') {
return input.checked;
}
}
}
return false;
}
});

View File

@@ -0,0 +1,19 @@
footer.footer {
padding: 0;
background-color: white;
border-top: 1px solid grey;
div.sponsors {
p {
padding-bottom: 10px;
color: #000;
font-size: 16px;
}
background-color: white;
padding: 2em 0;
img {
display: block;
margin: auto;
}
}
}

View File

@@ -0,0 +1 @@
require('./csconnectes.scss');

View File

@@ -0,0 +1,298 @@
situation_logement:
proprietaire: Propriétaire
locataire: Locataire
heberge_chez_tiers: Hébergé chez un tiers
heberge_chez_parents: Hébergé chez un parent
hebergement_en_foyer: Hébergé en foyer
sans_domicile: Sans domicile
niveau_maitrise_langue:
lu: Lu
ecrit: Écrit
parle: Parlé
aucun: Aucun
permis_conduire:
a: Permis A
b: Permis B
c: Permis C
d: Permis D
e: Permis E
en_cours: En cours
pas_de_permis: Pas de permis
caces: CACES
label: "Permis de conduire"
situation_professionnelle:
sans_emploi: Sans emploi
en_activite: En activité
etudiant: Étudiant
etudiant_descolarise: Étudiant déscolarisé
label: "Situation professionnelle"
type_contrat:
cdd: CDD
cdi: CDI
contrat_interim: Contrat intérim
contrat_aide: Contrat aidé
cdd_insertion: CDD insertion
contrat_extra: Contrat extra
service_civique: Service civique
label: "Type de contrat"
ressource:
salaires: Salaire(s)
ARE: ARE
are: ARE
ASS: ASS
ass: ASS
RSA: RSA
rsa: RSA
AAH: AAH
aah: AAH
autre: Autre
label: "Ressource"
accompagnement:
plie: PLIE
pole_emploi: Pôle emploi
referent_RSA: Référent RSA
mission_locale: Mission locale
rqth: RQTH
autre: Autre
label: "Accompagnement"
freins_perso:
situation_administrative: Situation administrative
situation_personnelle_et_familiale: Situation personnelle et familiale
comportement: Comportement
etat_de_sante: État de santé
precarite_situation_materielle: Précarité de la situation matérielle
condition_ou_absence_logement: Condition ou absence de logement
autres: Autres
freins_emploi:
garde_d_enfants: Garde d'enfants
sante: Santé
famille: Famille
finances: Finances
maitrise_de_la_langue: Maitrise de la langue
autres: Autres
neet_eligibility:
oui: Oui
non: Non
en_attente: En attente
label: "Éligibilité NEET"
handicap_recommandation:
travail_esat: Travail en ESAT
milieu_ordinaire: Milieu ordinaire
entreprise_adaptee: Entreprise adaptée
moyen_transport:
transport_commun: Transport en commun
scooter: Scooter
velo: Vélo
voiture: Voiture
autre: Autre
label: "Moyen de transport"
formation_level:
sans_diplome: Sans diplôme
BEP_CAP: BEP CAP
BAC: BAC
BAC+2: BAC +2
BAC+3: BAC +3
BAC+4: BAC +4
BAC+5: BAC +5
BAC+8: BAC +8
formation_type:
formation_initiale: Formation initiale
formation_continue: Formation continue
diploma_obtained:
fr: En France
non-fr: À l'étranger
aucun: Aucun
diploma_reconnu:
oui: Oui
non: Non
nsp: Ne sait pas
xp_contrat_type:
cddi: CDDI
cdd-6mois: CDD -6mois
cdd+6mois: CDD +6mois
interim: Intérim
apprentissage: Apprentissage
contrat_prof: Contrat professionnel
cui: CUI
cae: CAE
cdi: CDI
stage: Stage
volontariat: Volontariat
benevolat: Bénévolat
autres: Autres
immersion_objectif:
'decouvrir_metier': "Découvrir un métier ou un secteur d'activité"
'confirmer_projet_prof': "Confirmer un projet professionnel"
'acquerir_experience': "Acquérir une expérience professionnelle"
'acquerir_competences': "Acquérir de nouvelles compétences"
'initier_demarche_recrutement': "Initier une démarche de recrutement"
'autre': "Autre"
immersion_savoir_etre:
'assiduite': "Assiduité"
'ponctualite': "Ponctualité"
'respect_consigne_securite': "Respect des consignes de sécurité"
'relation_hierarchie': "Relation avec la hiérarchie"
'capacite_adaptation': "Capacité d'adaptation"
'motivation_travail': "Motivation au travail"
immersion_ponctualiteSalarie:
un: Un retard
aucun: Aucun retard
plusieurs: Plusieurs retards
immersion_assiduite:
aucun: Aucune absence
un: Une absence
plusieurs: Plusieurs absences
immersion_integreRegle:
1_temps: Au bout d'un certain temps
rapidement: Rapidement
pas_encore: Ne les a pas encore intégrées
immersion_nsp:
oui: Oui
non: Non
nsp: Ne sait pas
projet_prof:
type_contrat:
cdd: "CDD"
cdi: "CDI"
contrat_insertion: "Contrat d'insertion"
interim: "Intérim"
indifferent: "Indifférent"
label: "Type de contrat recherché"
apprentissage: Contrat d'apprentissage
personnalisation: Personnalisation
creation_entreprise: Création d'entreprise
note: "Notes contrat recherché"
volume_horaire:
temps_plein: "Temps plein"
temps_partiel: "Temps partiel"
label: "Volume horaire"
note: "Notes volume horaire"
idee: "Idées"
encoursdeconstruction: "En cours de construction"
valide:
note: "Notes validés"
code: "Codes validés"
note: "Notes"
souhait:
code: "Codes souhaits"
chill_3party:
key_label:
prescripteur: Prescripteur
entreprise: Entreprise
crud:
csfrein:
title_new: Nouveau rapport "frein" pour %person%
title_view: Rapport 'Frein' pour %person%
title_edit: Modifier un rapport "frein"
title_delete: Supprimer un Frein
button_delete: Supprimer
confirm_message_delete: Supprimer le %as_string% ?
cscv:
title_new: Nouveau CV pour %person%
title_view: CV pour %person%
title_edit: Modifier un CV
title_delete: Supprimer un CV
button_delete: Supprimer
confirm_message_delete: Supprimer le %as_string% ?
no_date: Aucune date indiquée
no_end_date: date de fin inconnue
no_start_date: date de début inconnue
immersion:
title_new: Nouvelle immersion pour %person%
title_view: Immersion pour %person%
title_edit: Modifier immersion
title_delete: Supprimer immersion
button_delete: Supprimer
confirm_message_delete: Supprimer le %as_string% ?
projet_prof:
title_new: Nouveau projet professionnel pour %person%
title_view: Projet professionnel pour %person%
title_edit: Modifier un projet professionnel
title_delete: Supprimer le projet professionnel
button_delete: Supprimer
confirm_message_delete: Supprimer le %as_string% ?
#
# Exports
#
placeofbirth: 'Lieu de naissance'
countryofbirth: 'Pays de naissance'
formationlevel: 'Niveau de formation'
reportdate: 'Date du rapport'
notesperso: 'Notes situation personnelle'
notesemploi: "Notes accès à lemploi"
prescripteur:
name: "Prescripteur"
email: "Email prescripteur"
phone: "Téléphone prescripteur"
recentopeningdate: "Date récente douverture du dossier"
recentclosingdate: "Date récente de fermeture du dossier"
closingmotive: "Motif de fermeture"
situation_familiale: "Situation familiale"
enfantacharge: "Enfants à charge"
poleemploiid: "Identifiant pôle emploi"
cafid: "Numéro allocataire CAF"
cafinscriptiondate: "Date de linscription CAF"
cerinscriptiondate: "Date de linscription CER"
contratiejdate: "Date de lavenant du contrat"
ppaeinscriptiondate: "Date de linscription PPAE"
ppaesignataire: "Signataire PPAE"
cersignataire: "Signataire CER"
neetcommissiondate: "Date de commission NEET"
fsemademarchecode: "Code démarche FSE"
findernieremploidate: "Date de fin dernier emploi"
CHILL_JOB_REPORT_NEW: Création et modification des rapports emploi
CHILL_JOB_REPORT_DELETE: Suppression des rapports emploi
CHILL_JOB_REPORT_CV: Création et modification des rapports emploi (CV uniquement)
CHILL_JOB_EXPORTS: Exports emploi
JobBundle: Emploi
export:
list:
cs_person:
ressources:
salaires: 'Ressources: salaires'
ARE: 'Ressources: ARE'
ASS: 'Ressources: ASS'
RSA: 'Ressources: RSA'
AAH: 'Ressources: AAH'
autre: 'Ressources: autre'
moyen_transport:
transport_commun: 'Moyen transport: transport commun'
scooter: 'Moyen transport: scooter'
velo: 'Moyen transport: vélo'
voiture: 'Moyen transport: voiture'
autre: 'Moyen transport: autre'
accompagnements:
plie: 'Accompagnement: plie'
pole_emploi: 'Accompagnement: pôle emploi'
referent_RSA: 'Accompagnement: '
mission_locale: 'Accompagnement: '
rqth: 'Accompagnement: '
autre: 'Accompagnement: '
permis_conduire:
a: 'Permis de conduire: A'
b: 'Permis de conduire: B'
c: 'Permis de conduire: C'
d: 'Permis de conduire: D'
e: 'Permis de conduire: E'
caces: 'Permis de conduire: caces'
en_cours: 'Permis de conduire: en cours'
pas_de_permis: 'Pas de permis de conduire'
type_contrat:
cdd: 'Type de contrat: cdd'
cdi: 'Type de contrat: cdi'
contrat_interim: 'Type de contrat: interim'
contrat_aide: 'Type de contrat: aide'
cdd_insertion: 'Type de contrat: cdd insertion'
contrat_extra: 'Type de contrat: contrat extra'
service_civique: 'Type de contrat: service civique'
neet_eligibility: 'NEET eligibilité'
situation_professionelle: 'Situation professionelle'

View File

@@ -0,0 +1,96 @@
{% extends '@ChillPerson/CRUD/edit.html.twig' %}
{% block css %}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block title 'Dispositifs de ' ~ entity.person.firstName ~ ' ' ~ entity.person.lastName %}
{% block content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block crud_content_header %}
<h1>Dispositifs</h1>
{% endblock %}
{# surcharge le block "retour" par un lien vers la page vue #}
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_crud_job_dispositifs_view', { 'person': entity.person.id}) }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_view %}
{# no view acceptable #}
{% endblock %}
{% block content_form_actions_save_and_close %}
{# save and close does not makes sens #}
{% endblock %}
{% block crud_content_form_rows %}
<h2>Accompagnement</h2>
<div id="form_accompagnement">
{{ form_row(form.accompagnement) }}
</div>
<div id="form_accompagnement_rqth">
{{ form_row(form.accompagnementRQTHDate) }}
</div>
<div id="form_accompagnement_comment">
{{ form_row(form.accompagnementComment) }}
</div>
{{ form_row(form.prescripteur) }}
{{ form_row(form.dispositifsNotes) }}
<h2>Pôle emploi</h2>
{{ form_row(form.poleEmploiId) }}
{{ form_row(form.poleEmploiInscriptionDate) }}
<h2>CAF</h2>
<div id="cafId">
{{ form_row(form.cafId) }}
</div>
<div id="cafInscriptionDate">
{{ form_row(form.cafInscriptionDate) }}
</div>
<h2>Autres informations</h2>
{{ form_row(form.cERInscriptionDate) }}
{{ form_row(form.cERSignataire) }}
{{ form_row(form.pPAEInscriptionDate) }}
{{ form_row(form.pPAESignataire) }}
<div id="neetEligibilite">
{{ form_row(form.nEETEligibilite) }}
</div>
<div id="neetCommissionDate">
{{ form_row(form.nEETCommissionDate) }}
</div>
{{ form_row(form.fSEMaDemarcheCode) }}
{{ form_row(form.dateContratIEJ) }}
{{ form_row(form.dateAvenantIEJ) }}
{% endblock %}
{% endembed %}
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
<script type="text/javascript" src="{{ asset('build/dispositifs_edit.js') }}"></script>
<script type="text/javascript">
</script>
{% endblock js %}

View File

@@ -0,0 +1,128 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set person = entity.getPerson() %}
{% set activeRouteKey = '' %}
{% set accompagnements = constant('Chill\\JobBundle\\Entity\\CSPerson::ACCOMPAGNEMENTS') %}
{% import '@ChillDocStore/Macro/macro.html.twig' as doc %}
{% block title 'Dispositifs d\'accompagnement de %name%'|trans( { '%name%': person.firstName ~ ' ' ~ person.lastName } ) %}
{% block content %}
<h1>{{ 'Dispositifs d\'accompagnement de %name%'|trans( { '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}</h1>
<h2>Accompagnement</h2>
<dl class="chill_view_data">
<dt>Accompagnements</dt>
{% if entity.accompagnement is null or entity.accompagnement|length == 0 %}
<dd>{{ null|chill_print_or_message }}</dd>
{% else %}
<dd>
<ul>
{% for e in accompagnements %}
{% if e in entity.accompagnement %}
{% if e == 'autre' %}
<li>Autre: <br/>{{ entity.accompagnementComment|chill_print_or_message(null, 'blockquote') }}</li>
{% elseif e == 'rqth' %}
<li>{{ ('accompagnement.' ~ e)|trans }} - <strong>Date de l'accompagnement:</strong> {{ entity.accompagnementRQTHDate|chill_print_or_message }}</li>
{% else %}
<li>{{ ('accompagnement.' ~ e)|trans }}</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
</dd>
{% endif %}
<dt>Prescripteur</dt>
{% if entity.prescripteur is not null %}
<dd>{{ entity.prescripteur|chill_entity_render_box({'with_valid_from': false}) }}</dd>
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
<dt>Notes</dt>
<dd>{{ entity.dispositifsNotes|chill_print_or_message("Aucune note", 'blockquote') }}</dd>
</dl>
<h2>Pôle emploi</h2>
<dl class="chill_view_data">
<dt>Identifiant pôle emploi</dt>
<dd>{{ entity.poleEmploiId|chill_print_or_message }}</dd>
<dt>Date d'inscription pôle emploi</dt>
<dd>{{ entity.poleEmploiInscriptionDate|chill_print_or_message }}</dd>
</dl>
<h2>CAF</h2>
<dl class="chill_view_data">
<dt>Identifiant CAF</dt>
<dd>{{ entity.cafId|chill_print_or_message }}</dd>
<dt>Date d'inscription CAF</dt>
<dd>{{ entity.cafInscriptionDate|chill_print_or_message }}</dd>
</dl>
<h2>Autres informations</h2>
<dl class="chill_view_data">
{% for item in [
['cERInscriptionDate', 'Date CER'],
['cERSignataire', 'Signataire CER'],
['pPAEInscriptionDate', 'Date PPAE'],
['pPAESignataire', 'Signataire PPAE'],
] %}
<dt>{{ item[1] }}</dt>
<dd>{{ attribute(entity, item[0])|chill_print_or_message }}</dd>
{% endfor %}
<dt>Éligibilite NEET</dt>
<dd>
{% if entity.nEETEligibilite is null %}
{{ null|chill_print_or_message }}
{% elseif entity.nEETEligibilite == 'oui' %}
Oui <strong>Date de commission :</strong> {{ entity.nEETCommissionDate|chill_print_or_message }}
{% elseif entity.nEETEligibilite == 'non' %}
Non
{% else %}
{{ ('neet_eligibility.' ~ entity.nEETEligibilite)|trans }}
{% endif %}
</dd>
<dt>Code "Ma démarche FSE"</dt>
<dd>{{ entity.fSEMaDemarcheCode|chill_print_or_message }}</dd>
{% if entity.dateContratIEJ != null or entity.dateAvenantIEJ != null %}
<dt>IEJ</dt>
<dd>
{% if entity.dateContratIEJ != null %}
<p>Date du contrat IEJ&nbsp;: {{ entity.dateContratIEJ|format_date('short') }}</p>
{% endif %}
{% if entity.dateAvenantIEJ != null %}
<p>Date de l'avenant IEJ&nbsp;: {{ entity.dateAvenantIEJ|format_date('short') }}</p>
{% endif %}
</dd>
{% endif %}
</dl>
<ul class="record_actions sticky-form-buttons">
<li>
<a class="btn btn-update" href="{{ path('chill_crud_job_dispositifs_edit', { 'id': entity.person.id }) }}">Modifier</a>
</li>
</ul>
{% endblock content %}
{% block css %}
<link rel="stylesheet" href="{{ asset('build/thirdparty_styles.css') }}"/>
{% endblock %}

View File

@@ -0,0 +1,126 @@
{% extends '@ChillPerson/CRUD/edit.html.twig' %}
{% block title 'Situation personnelle de ' ~ entity.person.firstName ~ ' ' ~ entity.person.lastName %}
{% block content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block crud_content_header %}
<h1>Situation personnelle</h1>
{% endblock %}
{# surcharge le block "retour" par un lien vers la page vue #}
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_crud_job_personal_situation_view', { 'person': entity.person.id}) }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_view %}
{# no view acceptable #}
{% endblock %}
{% block content_form_actions_save_and_close %}
{# save and close does not makes sens #}
{% endblock %}
{% block crud_content_form_rows %}
<h2>Logement</h2>
<div id="situation_logement">
{{ form_row(form.situationLogement) }}
</div>
<div id="situation_logement_precision">
{{ form_row(form.situationLogementPrecision) }}
</div>
<h2>Situation familiale</h2>
{{ form_row(form.enfantACharge) }}
{{ form_row(form.personMaritalStatus) }}
<h2>Maitrise de la langue</h2>
{{ form_row(form.niveauMaitriseLangue) }}
<h2>Mobilité</h2>
{{ form_row(form.mobiliteMoyenDeTransport) }}
{{ form_row(form.vehiculePersonnel) }}
{{ form_row(form.permisConduire) }}
{{ form_row(form.mobiliteNotes) }}
<h2>Situation professionnelle et économique</h2>
<div id="situation_prof">
{{ form_row(form.situationProfessionnelle) }}
</div>
{{ form_row(form.dateFinDernierEmploi) }}
<div id="type_contrat">
{{ form_row(form.typeContrat) }}
</div>
<div id="type_contrat_aide">
{{ form_row(form.typeContratAide) }}
</div>
<div id="ressources">
{{ form_row(form.ressources) }}
</div>
<div id="ressourcesComment">
{{ form_row(form.ressourcesComment) }}
</div>
{{ form_row(form.ressourceDate1Versement) }}
{{ form_row(form.cPFMontant) }}
{{ form_row(form.acompteDIF) }}
<h2>Situation de handicap</h2>
<div id="handicap_is">
{{ form_row(form.handicapIs) }}
</div>
<div id="handicap_if">
{{ form_row(form.handicapNotes) }}
{{ form_row(form.handicapRecommandation) }}
{{ form_row(form.handicapAccompagnement) }}
</div>
<h2>Documents</h2>
{{ form_row(form.documentCV) }}
{{ form_row(form.documentAgrementIAE) }}
{{ form_row(form.documentRQTH) }}
{{ form_row(form.documentAttestationNEET) }}
{{ form_row(form.documentCI) }}
{{ form_row(form.documentTitreSejour) }}
{{ form_row(form.documentAttestationFiscale) }}
{{ form_row(form.documentPermis) }}
{{ form_row(form.documentAttestationCAAF) }}
{{ form_row(form.documentContraTravail) }}
{{ form_row(form.documentAttestationFormation) }}
{{ form_row(form.documentQuittanceLoyer) }}
{{ form_row(form.documentFactureElectricite) }}
{{ form_row(form.documentAttestationSecuriteSociale) }}
{% endblock %}
{% endembed %}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock css %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
<script type="text/javascript" src="{{ asset('build/personal_situation_edit.js') }}"></script>
{% endblock js %}

View File

@@ -0,0 +1,282 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set person = entity.getPerson() %}
{% set activeRouteKey = '' %}
{% set niveaux_maitrise_langue = constant('Chill\\JobBundle\\Entity\\CSPerson::NIVEAU_MAITRISE_LANGUE') %}
{% set permis_conduire = constant('Chill\\JobBundle\\Entity\\CSPerson::PERMIS_CONDUIRE') %}
{% set types_contrat = constant('Chill\\JobBundle\\Entity\\CSPerson::TYPE_CONTRAT') %}
{% set ressources = constant('Chill\\JobBundle\\Entity\\CSPerson::RESSOURCES') %}
{% import '@ChillDocStore/Macro/macro.html.twig' as doc %}
{% block title 'Situation personnelle de %name%'|trans( { '%name%': person.firstName ~ ' ' ~ person.lastName } ) %}
{% block content %}
<h1>{{ 'Situation personnelle de %name%'|trans( { '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}</h1>
<h2>Logement</h2>
<dl class="chill_view_data">
<dt>Situation de logement</dt>
{% if entity.situationLogement is not null %}
<dd>{{ ('situation_logement.' ~ entity.situationLogement)|trans }}</dd>
{% else %}
<dd>{{ null|chill_print_or_message("Aucune information") }}</dd>
{% endif %}
</dl>
<h2>Situation familiale</h2>
<dl class="chill_view_data">
<dt>Enfants à charge</dt>
{% if entity.enfantACharge is not null %}
<dd>
{% if entity.enfantACharge == 0 %}Aucun enfant{% elseif entity.enfantACharge == 1 %}Un enfant{% else %}{{ entity.enfantACharge }} enfants{% endif %} à charge</dd>
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
<dt>{{'Marital status'|trans}}&nbsp;:</dt>
<dd>
{% if entity.person.maritalStatus is not null %}
{{ entity.person.maritalStatus.name|localize_translatable_string }}
{% else %}
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
{% endif %}
</dd>
</dl>
<h2>Maitrise de la langue</h2>
<dl class="chill_view_data">
<dt>Niveau de maitrise de la langue française</dt>
{% if entity.niveauMaitriseLangue is null or entity.niveauMaitriseLangue|length == 0 %}
<dd>{{ null|chill_print_or_message }}</dd>
{% else %}
<dd>
<ul>
{% for niveau in niveaux_maitrise_langue %}
{% if niveau in entity.niveauMaitriseLangue %}
<li>{{ ('niveau_maitrise_langue.' ~ niveau)|trans }}</li>
{% endif %}
{% endfor %}
</ul>
</dd>
{% endif %}
</dl>
<h2>Mobilité</h2>
<dl class="chill_view_data">
<dt>Moyens de transports accessibles</dt>
<dd>
{% if entity.mobiliteMoyenDeTransport is null or entity.mobiliteMoyenDeTransport|length == 0 %}
{{ null|chill_print_or_message("Aucun moyen de transport renseigné") }}
{% else %}
<ul>
{% for e in entity.mobiliteMoyenDeTransport %}
<li>{{ ('moyen_transport.' ~ e)|trans }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
<dt>Véhicule Personnel</dt>
{% if entity.vehiculePersonnel is null %}
<dd>{{ null|chill_print_or_message }}</dd>
{% elseif entity.vehiculePersonnel == true %}
<dd>A un véhicule personnel</dd>
{% else %}
<dd>N'a pas de véhicule personnel</dd>
{% endif %}
<dt>Permis de conduire</dt>
{% if entity.permisConduire is null or entity.permisConduire|length == 0 %}
<dd>{{ null|chill_print_or_message }}</dd>
{% else %}
<dd>
<ul>
{% for e in permis_conduire %}
{% if e in entity.permisConduire %}
<li>{{ ('permis_conduire.' ~ e)|trans }}</li>
{% endif %}
{% endfor %}
</ul>
</dd>
{% endif %}
<dt>Notes concernant la mobilité</dt>
<dd>
{{ entity.mobiliteNotes|chill_print_or_message("Aucune note", 'blockquote') }}
</dd>
</dl>
<h2>Situation professionnelle et économique</h2>
<dl class="chill_view_data">
<dt>Situation professionnelle</dt>
{% if entity.situationProfessionnelle is not null %}
<dd>{{ ('situation_professionnelle.' ~ entity.situationProfessionnelle)|trans }}</dd>
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
<dt>Date de fin du dernier emploi</dt>
{% if entity.dateFinDernierEmploi is not null %}
<dd>{{ entity.dateFinDernierEmploi|format_date('short') }}
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
{% if entity.situationProfessionnelle == 'en_activite' %}
<dt>Type de contrat</dt>
{% if entity.typeContrat is null or entity.typeContrat|length == 0 %}
<dd>{{ null|chill_print_or_message }}</dd>
{% else %}
<dd>
<ul>
{% for e in types_contrat %}
{% if e in entity.typeContrat %}
<li>{{ ('type_contrat.' ~ e)|trans }}</li>
{% endif %}
{% endfor %}
</ul>
</dd>
{% endif %}
{% endif %}
<dt>Ressources</dt>
{% if entity.ressources is null or entity.ressources|length == 0 %}
<dd>{{ null|chill_print_or_message }}</dd>
{% else %}
<dd>
<ul>
{% for e in ressources %}
{% if e in entity.ressources %}
{% if e == 'autre' %}
<li>Autre: {{ entity.ressourcesComment|chill_print_or_message }}</li>
{% else %}
<li>{{ ('ressource.' ~ e)|trans }}</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
</dd>
{% endif %}
<dt>Date du premier versement</dt>
{% if entity.ressourceDate1Versement is not null %}
<dd>{{ entity.ressourceDate1Versement|format_date('short') }}
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
<dt>Montant CPF</dt>
{% if entity.cPFMontant is not null %}
<dd>{{ entity.cPFMontant|format_currency('EUR') }}</dd>
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
<dt>Montant acompte DIF</dt>
{% if entity.acompteDIF is not null %}
<dd>{{ entity.acompteDIF|format_currency('EUR') }}</dd>
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
</dl>
<h2>Handicap</h2>
<dl class="chill_view_data">
<dt>Handicap ?</dt>
<dd>
{% if entity.handicapIs is null %}
{{ null|chill_print_or_message }}
{% elseif entity.handicapIs %}
Oui<br/>
<br/>
<strong>Type de handicap</strong>&nbsp;: {{ entity.handicapNotes|chill_print_or_message("Aucune précision", 'blockquote') }}
{% else %}
Non
{% endif %}
</dd>
{% if entity.handicapIs %}
<dt>Recommandation</dt>
<dd>
{% if entity.handicapRecommandation is null %}
{{ null|chill_print_or_message("Aucune recommandation renseignée") }}
{% else %}
{{ ('handicap_recommandation.' ~ entity.handicapRecommandation)|trans }}
{% endif %}
</dd>
<dt>Accompagnement</dt>
{% if entity.handicapAccompagnement is not null %}
<dd>{{ entity.handicapAccompagnement.name }}</dd>
{% else %}
<dd>{{ null|chill_print_or_message }}</dd>
{% endif %}
{% endif %}
</dl>
<h2>Documents</h2>
<dl class="chill_view_data">
{% for r in [
['documentCV', 'CV'],
['documentAgrementIAE', 'Document Agrément AIE'],
['documentRQTH', 'Document RQTH'],
['documentAttestationNEET', 'Attestation NEET'],
['documentCI', "Carte d'identité"],
['documentTitreSejour', 'Titre de séjour'],
['documentAttestationFiscale', 'Attestation fiscale'],
['documentPermis', 'Permis'],
['documentAttestationCAAF', 'Attestation CAAF'],
['documentContraTravail', 'Contrat de travail'],
['documentAttestationFormation', 'Attestation formation'],
['documentQuittanceLoyer', 'Quittance de loyer'],
['documentFactureElectricite', "Facture d'électricité"],
['documentAttestationSecuriteSociale', "Attestation sécurité sociale"],
] %}
<dt>{{ r[1] }}</dt>
{% set document = attribute(entity, r[0]) %}
{% if document is null %}
<dd>{{ null|chill_print_or_message("Aucun document") }}</dd>
{% else %}
<dd>{{ doc.download_button(document, r[1] ~ " de " ~ person.firstName ~ " " ~ person.lastName) }}</dd>
{% endif %}
{% endfor %}
</dl>
<ul class="record_actions sticky-form-buttons">
<li><a class="btn btn-update" href="{{ path('chill_crud_job_personal_situation_edit', { 'id': entity.person.id }) }}">Modifier</a></li>
</ul>
{% endblock %}
{% block css %}
{{ parent() }}
<link rel="stylesheet" type="text/css" href="{{ asset('build/async_upload.css') }}" />
{% endblock css %}
{% block js %}
{{ parent() }}
<script type="text/javascript" src="{{ asset('build/async_upload.js') }}"></script>
{% endblock js %}

View File

@@ -0,0 +1,61 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set person = entity.person %}
{% set activeRouteKey = '' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock title %}
{% form_theme form _self %}
{% block job_bundle_cv_formation_widget %}
<div data-formation-entry>
{{ form_row(form.title) }}
{{ form_row(form.organisme) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
<div data-diploma-obtained>
{{ form_row(form.diplomaObtained) }}
</div>
<div data-diploma-reconnue>
{{ form_row(form.diplomaReconnue) }}
</div>
</div>
{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block crud_content_form_rows %}
{{ form_row(form.reportDate) }}
{{ form_row(form.formationLevel) }}
{{ form_row(form.formationType) }}
{{ form_row(form.spokenLanguages) }}
<h2>Formations</h2>
{{ form_widget(form.formations) }}
<h2>Expériences</h2>
{{ form_widget(form.experiences) }}
<h2>Notes</h2>
{{ form_widget(form.notes) }}
{% endblock crud_content_form_rows %}
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_job_report_index', {'person': entity.person.id}) }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% endembed %}
{% endblock %}
{% block css %}
<script type="text/javascript" src="{{ asset('build/cs_cv.js') }}"></script>
{% endblock css %}

View File

@@ -0,0 +1,61 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set person = entity.person %}
{% set activeRouteKey = '' %}
{% block title %}
{% embed('@ChillPerson/CRUD/_new_title.html.twig') %}{% endembed %}
{% endblock %}
{% form_theme form _self %}
{% block job_bundle_cv_formation_widget %}
<div data-formation-entry>
{{ form_row(form.title) }}
{{ form_row(form.organisme) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
<div data-diploma-obtained>
{{ form_row(form.diplomaObtained) }}
</div>
<div data-diploma-reconnue>
{{ form_row(form.diplomaReconnue) }}
</div>
</div>
{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block crud_content_header %}
<h1>{{ ('crud.'~crud_name~'.title_new')|trans({'%person%': person|chill_entity_render_string }) }}</h1>
{% endblock crud_content_header %}
{% block crud_content_form_rows %}
{{ form_row(form.reportDate) }}
{{ form_row(form.formationLevel) }}
{{ form_row(form.formationType) }}
{{ form_row(form.spokenLanguages) }}
<h2>Formations</h2>
{{ form_widget(form.formations) }}
<h2>Expériences</h2>
{{ form_widget(form.experiences) }}
<h2>Notes</h2>
{{ form_widget(form.notes) }}
{% endblock crud_content_form_rows %}
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_job_report_index', {'person': entity.person.id}) }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% endembed %}
{% endblock %}
{% block css %}
<script type="text/javascript" src="{{ asset('build/cs_cv.js') }}"></script>
{% endblock css %}

View File

@@ -0,0 +1,144 @@
{% extends '@ChillPerson/CRUD/view.html.twig' %}
{% block content %}
{% embed '@ChillPerson/CRUD/_view_content.html.twig' %}
{% block crud_content_header %}
<h1>{{ ('crud.' ~ crud_name ~ '.title_view')|trans({'%person%': person|chill_entity_render_string }) }}</h1>
{% endblock crud_content_header %}
{% block crud_content_view_details %}
<dl class="chill_view_data">
<dt>Date du rapport</dt>
<dd>{{ entity.reportDate|format_date('short') }}</dd>
<h2>Compétences</h2>
<dt>Langues parlées</dt>
<dd>
{% if entity.spokenLanguages is null or entity.spokenLanguages|length == 0 %}
{{ null|chill_print_or_message }}
{% else %}
{% for lang in entity.spokenLanguages %}
{{ lang.name|localize_translatable_string }}{% if not loop.last %},{% endif %}
{% endfor %}
{% endif %}
</dd>
<h2>Formation</h2>
<dt>Niveau de formation</dt>
<dd>
{{ (entity.formationLevel is null ? null : ('formation_level.' ~ entity.formationLevel))|chill_print_or_message("Aucune information") }}
</dd>
<dt>Type de formation</dt>
<dd>
{{ (entity.formationType is null ? null : ('formation_type.' ~ entity.formationType))|chill_print_or_message("Aucune information") }}
</dd>
</dl>
<h3>Formations suivies</h3>
{% if entity.formations|length > 0 %}
{% for f in entity.formations %}
<div class="flex-table">
<div class="job__cv-view__formations__formation">
<h4>{{ f.title }}{% if f.organisme is not empty %} <span style="font-size: 85%;">auprès de <span style="font-style: italic;">{{ f.organisme }}</span></span>{% endif %}</h4>
<dl class="chill_view_data">
<dt>Dates de formation</dt>
<dd>
{% if f.startDate is null and f.endDate is null %}
{{ null|chill_print_or_message("Aucune date indiquée") }}
{% elseif f.startDate is null %}
Jusqu'au {{ f.endDate|format_date('short') }} <span class="chill-no-data-statement">(date de début inconnue)</span>
{% elseif f.endDate is null %}
Depuis le {{ f.startDate|format_date('short') }} <span class="chill-no-data-statement">(date de fin inconnue)</span>
{% else %}
Du {{ f.startDate|format_date('short') }} au {{ f.endDate|format_date('short') }}
{% endif %}
</dd>
<dt>Diplôme</dt>
<dd>
<p>Diplôme obtenu: {{ (f.diplomaObtained is null ? null : ('diploma_obtained.' ~ f.diplomaObtained))|chill_print_or_message("Aucune information") }}</p>
<p>Diplôme reconnu en France: {{ (f.diplomaReconnue is null ? null : ('diploma_reconnu.' ~ f.diplomaReconnue))|chill_print_or_message("Aucune information") }}</p>
</dd>
</dl>
</div>
</div>
{% endfor %}
{% else %}
<span class="chill-no-data-statement">{{ 'No education'|trans }}</span>
{% endif %}
<h3>Expériences</h3>
{% if entity.formations|length > 0 %}
{% for f in entity.experiences %}
<div class="flex-table">
<div class="job__cv-view__experiences_experience">
<h4>{{ f.poste }} {% if f.structure is not empty %}<span style="font-size: 85%;">auprès de <span style=" font-style: italic;">{{ f.structure }}</span></span>{% endif %}</h4>
<dl class="chill_view_data">
<dt>Dates de l'expérience</dt>
<dd>
{% if f.startDate is null and f.endDate is null %}
{{ null|chill_print_or_message("Aucune date indiquée") }}
{% elseif f.startDate is null %}
Jusqu'au {{ f.endDate|format_date('short') }} <span class="chill-no-data-statement">(date de début inconnue)</span>
{% elseif f.endDate is null %}
Depuis le {{ f.startDate|format_date('short') }} <span class="chill-no-data-statement">(date de fin inconnue)</span>
{% else %}
Du {{ f.startDate|format_date('short') }} au {{ f.endDate|format_date('short') }}
{% endif %}
</dd>
<dt>Type de contrat</dt>
<dd>
{{ (f.contratType is null ? null : ('xp_contrat_type.'~f.contratType))|chill_print_or_message }}
</dd>
{% if f.notes is not empty %}
<dt>Notes</dt>
<dd>
{{ f.notes|chill_print_or_message(null, 'blockquote') }}
</dd>
{% endif %}
</dl>
</div>
</div>
{% endfor %}
{% else %}
<p class="chill-no-data-statement">Aucune formation renseignée</p>
{% endif %}
<h3>Note</h3>
{{ entity.notes|chill_print_or_message("Aucune note", 'blockquote') }}
{% endblock crud_content_view_details %}
{% block content_view_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_job_report_index', { 'person': entity.person.id }) }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% endembed %}
{% endblock %}
{% block css %}
<style>
div.job__cv-view__experiences > div {
padding: 0 0.5em 0.5em 0.5em;
}
div.job__cv-view__experiences > div:nth-child(2n+1) {
background-color: var(--chill-llight-gray);
}
div.job__cv-view__experiences > div:nth-child(2n) {
background-color: var(--chill-beige);
}
</style>
{% endblock %}

View File

@@ -0,0 +1,20 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set person = entity.person %}
{% set activeRouteKey = '' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock title %}
{% block content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_job_report_index', {'person': entity.person.id}) }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% endembed %}
{% endblock %}

Some files were not shown because too many files have changed in this diff Show More