Compare commits

..

121 Commits

Author SHA1 Message Date
f8fa96d836 Fix download report URL in ChillMainBundle export
An extra "?" was erroneously appended to the download report URL in ChillMainBundle's export feature. This update removes the extraneous character to ensure the function works as expected with the correct URL format.
2024-06-24 14:23:47 +02:00
d28cec3786 Update dependencies and bootstrap configuration
Updated the versions of PHPUnit and Symfony's PHPUnit-Bridge in composer.json to more recent, stable versions. The bootstrap.php code has been modified to now load the regular .env file instead of the .env.test file, the change is made to enable the application fetch the actual environment variables during execution.
2024-06-24 12:12:32 +02:00
7cd36cd483 Remove minimum length assertions in ThirdParty entity
The code changes eliminate the minimum length assertions for 'acronym' and 'nameCompany' in the ThirdParty entity. This modification increases flexibility, accommodating acronyms and company names of any length.
2024-06-24 11:33:54 +02:00
d3d98cdec2 Update method parameter type in ExportController
The parameter type for the 'rebuildRawData' function in the ExportController class has been changed to accept null values. This change is introduced to handle cases where a null key might be passed, preventing potential errors in the application.
2024-06-24 11:33:54 +02:00
49dd7f94fa Fix CS and upgrade issues after mergin master branch 2024-06-24 10:56:02 +02:00
916724c0c5 Merge branch 'master' into upgrade-sf5 2024-06-24 10:46:21 +02:00
nobohan
102d0dad94 DOC: add jwt key generation in the sf5 installationdoc - format doc 2024-06-24 09:17:16 +02:00
nobohan
8d225dd68c DOC: add jwt key generation in the sf5 installationdoc - format doc 2024-06-24 09:16:29 +02:00
nobohan
61d0005be8 DOC: add jwt key generation in the sf5 installationdoc 2024-06-24 09:14:58 +02:00
47f4cfddbb Prepare for 2.21.0 2024-06-18 10:16:39 +02:00
e95f9e9846 Merge branch '282-add-dates-job-filter' into 'master'
Add dates ranges to job and scope filter and aggregator (accompanying course's exports)

Closes #282

See merge request Chill-Projet/chill-bundles!699
2024-06-18 07:54:49 +00:00
1f4bef754d Refactor callback functions to arrow functions
The callback functions used in the addViewTransformer method in FilterType.php and AggregatorType.php were replaced with shorter arrow functions. This change was made to increase code readability and encourage consistency throughout the codebase.
2024-06-18 09:35:57 +02:00
19e34d5dc0 PHP CS Fixer updated (3.57.2 -> v3.59.3) 2024-06-17 17:28:29 +02:00
fab00f679c Add date range to UserJobAggregator
This update includes adding start_date and end_date to UserJobAggregator. This addition allows the selection of a date range in the export feature. Accompanying this change are associated translations and tests.
2024-06-17 17:16:02 +02:00
791b3776c5 Add date range filter to referrer scope aggregator
A date range filter was added to the 'ReferrerScopeAggregator' class. This new feature allows users to filter courses by their referrer's scope based on a specified date range. In addition, relevant unit tests and translations were updated to support this new functionality.
2024-06-17 17:15:53 +02:00
6bd38f1a58 Refactor assertions in AbstractAggregatorTest
The conditional checks in the AbstractAggregatorTest have been simplified. Instead of a complex inline condition with multiple checks, the test now uses straightforward assertions. This makes the code cleaner and easier to understand.
2024-06-17 15:31:33 +02:00
68d21c9267 Update ReferrerAggregator to specify a date range as parameter
The ReferrerAggregator in ChillPersonBundle has been updated to include start and end dates, replacing the previous single computation date. This provides greater flexibility in setting the timeframe for referrer data. The messages.fr.yml file has also been updated to reflect these changes. Relevant tests have been updated to match the new functionality.
2024-06-17 15:22:28 +02:00
e7ca89e0c1 Rename DataTransformerFilterInterface to DataTransformerInterface
The DataTransformerFilterInterface has been renamed to DataTransformerInterface to reflect expanded functionality. Now, this interface can be implemented not only by @see{FilterInterface}, but also by @see{AggregatorInterface}. This change allows transforming existing data in saved exports and replacing it with some default values, or new default values.
2024-06-17 15:20:54 +02:00
fc8bc33ba9 Add startDate and endDate on UserScopeFilter 2024-06-17 14:31:12 +02:00
cbd9489810 Add startDate and endDate on UserJobFilter 2024-06-17 14:10:32 +02:00
90b615c5b2 Add data transformation interface for filters
Introduced a new DataTransformerFilterInterface that allows transforming filter's form data before it is processed. Updated the FilterType file to add a view transformer if the filter implements this new interface. This new transformation process caters to transforming existing data in saved exports and replacing it with default values.
2024-06-14 14:38:10 +02:00
5ca222b501 Merge branch '122-improve-list-rendez-vous' into 'master'
Update calendar list display for the the next calendar in search results

Closes #122

See merge request Chill-Projet/chill-bundles!700
2024-06-13 16:12:57 +00:00
3e4495dd6e Refactor AccompanyingPeriod::getNextCalendarForPerson to enhance performance 2024-06-13 18:07:19 +02:00
bca0d04201 Update calendar list display for the the next calendar in search results
The calendar list display in ChillPersonBundle has been revamped, including a new view and style modifications. This update enables the display of calendars as a list for easy navigation with an added authorization check. Also, a new SCSS file named "calendar-list.scss" has been created and imported to enhance the UI/UX design.
2024-06-13 18:07:19 +02:00
f66ac50571 Merge branch '616_rapid-action' into 'master'
Flash menu rapid action in search results

See merge request Chill-Projet/chill-bundles!441
2024-06-13 10:32:30 +00:00
b454774836 add changie [ci-skip] 2024-06-13 12:21:19 +02:00
008f344e49 Update calendar and activity voters in security checks
This commit adjusts the conditions in CalendarVoter and ActivityVoter security checks. Now it takes into account both STEP_DRAFT and STEP_CLOSED statuses in determining permissions. This enhancement ensures tighter control over specific actions in these two scenarios, enhancing the overall application security.
2024-06-13 12:17:14 +02:00
90bfd87ec6 Implement security checks for menu options
The changes in this commit add security checks before displaying menu options for creating new objects on Accompanying Period.
2024-06-13 12:08:24 +02:00
cc0030c1cd Fix adding quick menus to list_with_period.html.twig
- update twig namespaces
- move twig file within Resources
2024-06-13 12:07:34 +02:00
d60ba3ecb2 Merge remote-tracking branch 'origin/master' into 616_rapid-action 2024-06-12 16:45:43 +02:00
cd5001ac74 Merge branch 'issue178_affichage_metiers' into 'master'
Display users and jobs at the date that they executed some task

See merge request Chill-Projet/chill-bundles!641
2024-06-12 14:41:40 +00:00
98f47ac512 fixes for normalising accompanying periods in docgen context 2024-06-12 16:35:53 +02:00
31b541d12f Update AccompanyingPeriodWorkNormalizer and related classes
Updated the AccompanyingPeriodWorkNormalizer, its test, and the related entity class. Now, the normalizer includes additional checks for different formats and conditions, and cleans the context accordingly before processing. AccompanyingPeriodWorkDocGenNormalizerTest now extends from a new abstract base class. Changes are made in AccompanyingPeriodWork entity for datetime handling and serialization.
2024-06-12 11:47:13 +02:00
72045ce082 Add DocGenNormalizerTestAbstract class
A new class, DocGenNormalizerTestAbstract, was added to the ChillDocGeneratorBundle. This abstract class tests the normalization of null values and ensures they comply with expected formats and behaviors. It implements key methods that allow for providing non-null objects, expectation setting, and normalization.
2024-06-12 11:46:49 +02:00
0bfb3de465 fix cs 2024-06-11 16:58:33 +02:00
9ec4c77fb7 systematically at a parameter 'at_date' when displaying createdBy in twig template
The rendering of the 'createdBy' entity has been updated across various .twig files to include the 'at_date' property. This makes the date an entity was created more explicit, providing clearer information to the user.
2024-06-11 16:55:15 +02:00
77c53972c8 Add DateTimeImmutable support in UserNormalizer
This commit introduces the use of DateTimeImmutable in the UserNormalizer class to ensure immutability of datetime objects. A check is also added to convert DateTime instances to DateTimeImmutable when normalizing data. This enhances the safety and predictability of datetimes used in the application.
2024-06-11 16:33:54 +02:00
350d991a85 Update AccompanyingPeriod normalization with UserHistory
The AccompanyingPeriod normalization now includes 'createdBy' and 'ref' fields from the UserHistory. AccompanyingPeriodDocGenNormalizer has been modified adding UserHistory retrieval and subsequently normalization. A new method was also added to the AccompanyingPeriod entity to retrieve the current UserHistory.
2024-06-11 16:33:37 +02:00
0ce9cdd07a Add label to main user selection in Calendar App
A new attribute `label` has been added to the `pick-entity` component in the Chill Calendar Bundle's Vue.js App. This label, set as 'Utilisateur principal', enhances user interaction and clarity in the main user selection process.
2024-06-11 09:39:51 +02:00
1993fac1c4 Update button rendering in AddPersons.vue
This commit modifies the button rendering in AddPersons.vue component to ensure that it doesn't crash if 'buttonTitle' is undefined. It does so by providing an empty string as a fallback in case 'buttonTitle' is unavailable, improving the component's stability.
2024-06-11 09:39:32 +02:00
83883567a2 Upgrade node dependencies and add necessary fixes 2024-06-11 09:38:56 +02:00
29d57934a1 Update workflow rendering with date context
Code updates have been made in multiple files to ensure that when entities are rendered, it includes the appropriate context relating to the date. This adjustment has been primarily made in template files where the `chill_entity_render_box` function is used. These changes help to provide users with more accurate information regarding the state of an entity at a specific time.
2024-06-10 17:19:34 +02:00
f43d79c940 Add notification date to entity render strings
The notification date has been added to the render strings of entities involved in the notifications, specifically for the sender, addressees, and normalizer. This is done by passing it as a parameter to the 'chill_entity_render_string' function and the 'normalize' function in NotificationNormalizer. This will help provide more context regarding the time of the events in the notification.
2024-06-10 17:08:30 +02:00
be730679c8 Update rendering of user information in AccompanyingCourse/Comment: show user at the comment's date 2024-06-10 15:23:12 +02:00
f62f1891d8 Fix displaying calendar: reproduce same getAtDate method as Activity 2024-06-07 13:07:25 +02:00
ebb856fe85 fix rendering of accompanying course commen with at_date 2024-06-07 13:06:46 +02:00
61877e0157 Refactor UserRenderTest and remove unused methods
The UserRenderTest class has been refactored significantly. Redundant methods related to the booting kernel of Symfony have been removed. The approach of mocking objects has been changed, swapping from traditional mocking to prophecy mocking.
2024-06-07 13:06:11 +02:00
4c3f082163 Merge remote-tracking branch 'origin/master' into issue178_affichage_metiers 2024-06-07 12:03:30 +02:00
35109133f6 Release 2.20.1 2024-06-05 17:08:57 +02:00
a220dad83b Do not pass StoredObjectCreated on Convert and Edit buttons 2024-06-05 17:08:30 +02:00
9eb571549b Prepare for release 2.20.0 2024-06-05 16:21:11 +02:00
db8257d230 Merge branch '170-export-action-referrer' into 'master'
Resolve "Dans la liste des évaluations et la liste des actions, il n'y a pas le nom des référents de l'action"

Closes #170

See merge request Chill-Projet/chill-bundles!695
2024-06-05 14:08:05 +00:00
bce93efe83 Resolve "Dans la liste des évaluations et la liste des actions, il n'y a pas le nom des référents de l'action" 2024-06-05 14:08:05 +00:00
06401af801 Merge branch '145-permettre-de-visualiser-les-documents-dans-libreoffice-en-utilisant-webdav' into 'master'
Add history to storedObject, instead of creating new stored object instances

Closes #145

See merge request Chill-Projet/chill-bundles!698
2024-06-04 20:37:36 +00:00
ea1d4c48f2 Add history support to StoredObject entity
This commit adds a history saving feature to the StoredObject entity, which allows saving versions of the object's changes over time. This is achieved by implementing a saveHistory method that captures data attributes like filename, IV, key information, and type. The corresponding Automated tests were also created. Furthermore, adjustments were made to the StoredObject test to align with the new feature.
2024-06-04 22:31:50 +02:00
nobohan
33cba27dd4 Translations: Added translations for choices of durations (> 5 hours) 2024-06-04 21:24:58 +02:00
a7ec7c9f37 fix pipeline for branch affichage metiers 2024-05-07 16:32:12 +02:00
c9e13be736 pipeline fixes for phpstan, cs-fixer, rector 2024-04-16 20:16:45 +02:00
b9b342fe44 Set isActive property for userjob 2024-04-16 20:09:00 +02:00
31f29f0bc5 Resolve merge conflicts 2024-04-16 12:43:07 +02:00
0bc9fff825 test still failing with error saying column phonenumber of relation users does not exist 2024-04-16 12:01:40 +02:00
25f93e8a89 fix typing 2024-04-16 12:01:40 +02:00
4e0d8e4def fix userNormalizerTest by adding clock in the construct of UserNormalizer 2024-04-16 12:01:40 +02:00
1ecc825945 Correct 2 phpstan errors, condition is always true and wrong typing 2024-04-16 12:01:40 +02:00
addc623add php style fixer 2024-04-16 12:01:37 +02:00
1b96deb4ee try to fix userRenderTest: mock not working 2024-04-16 11:55:54 +02:00
f510acd170 add back the annotation to edit accompanying period work for referrers 2024-04-16 11:55:54 +02:00
835409cb94 work on userRenderTest 2024-04-16 11:55:54 +02:00
2121b3ef28 Add at_date to userRender for rendering the text 2024-04-16 11:55:54 +02:00
6c9101c167 Adapt the rendering of user in accompanyingPeriodWork list and item templates 2024-04-16 11:55:54 +02:00
b46883fe36 Implement clockInterface in renderString method 2024-04-16 11:55:54 +02:00
8d58805abd work on user render test 2024-04-16 11:55:54 +02:00
c3a799cb7d work on test logic 2024-04-16 11:55:54 +02:00
bc683b28d6 update normalizers to take into account referrerHistory logic for accompanying period work 2024-04-16 11:55:50 +02:00
d91b1a70bf work on userRender test 2024-04-16 11:52:58 +02:00
853014d8d2 remove attempt to adjust accompanyingperiod work for display of user job and service at specific date 2024-04-16 11:52:58 +02:00
ad6154a1e4 Implement 'at date' for concerned groups in activity 2024-04-16 11:52:58 +02:00
50c04382ef Adjust view template for aside activity 2024-04-16 11:52:58 +02:00
d62e9ce269 Implement 'at date' for display of service and user job in accompanying period work entities (for twig templates) -> vue component still to fix 2024-04-16 11:52:58 +02:00
2149ef1cb4 Implement 'at date' for display of service and user job in aside activities entities 2024-04-16 11:52:58 +02:00
d15fbadd27 Implement 'at date' for display of service and user job in calendar entities 2024-04-16 11:52:58 +02:00
fbbf421d8b Handle DateTime type for activity while DateTimeImmutable is expected 2024-04-16 11:52:58 +02:00
fe695f1a14 Implement 'at date' in user render component for activities 2024-04-16 11:52:58 +02:00
d0ec6f9819 Improve naming for 'at date' in user render component 2024-04-16 11:52:54 +02:00
0b739fda34 test still failing with error saying column phonenumber of relation users does not exist 2024-02-12 18:56:05 +01:00
9b8e143855 fix typing 2024-02-12 18:55:00 +01:00
a533ab77ed fix userNormalizerTest by adding clock in the construct of UserNormalizer 2024-02-12 18:44:32 +01:00
087032881b Correct 2 phpstan errors, condition is always true and wrong typing 2024-02-12 14:50:26 +01:00
82667a1c0f php style fixer 2024-02-12 14:37:54 +01:00
db6408926b try to fix userRenderTest: mock not working 2024-02-12 14:36:41 +01:00
f5c7ab6ef0 add back the annotation to edit accompanying period work for referrers 2024-02-12 09:02:48 +01:00
a13ada2937 work on userRenderTest 2024-02-07 07:19:26 +01:00
3be8a39a1a Add at_date to userRender for rendering the text 2024-01-30 17:03:24 +01:00
d7eb1e01da Adapt the rendering of user in accompanyingPeriodWork list and item templates 2024-01-30 17:01:45 +01:00
bd62202d22 Implement clockInterface in renderString method 2024-01-30 16:31:29 +01:00
0e3de2ec8a work on user render test 2024-01-29 15:07:27 +01:00
aa2a398f9e work on test logic 2024-01-24 19:31:04 +01:00
33187448a0 update normalizers to take into account referrerHistory logic for accompanying period work 2024-01-24 19:30:50 +01:00
a4482ad28b work on userRender test 2024-01-23 18:13:33 +01:00
8ed5a023e8 remove attempt to adjust accompanyingperiod work for display of user job and service at specific date 2024-01-17 17:27:54 +01:00
653ac1d62b Implement 'at date' for concerned groups in activity 2024-01-08 16:51:06 +01:00
499009ac43 Adjust view template for aside activity 2024-01-08 16:38:50 +01:00
192b161e78 Implement 'at date' for display of service and user job in accompanying period work entities (for twig templates) -> vue component still to fix 2024-01-08 16:38:07 +01:00
1b1f355123 Implement 'at date' for display of service and user job in aside activities entities 2024-01-08 16:37:25 +01:00
39a863448c Implement 'at date' for display of service and user job in calendar entities 2024-01-08 12:35:41 +01:00
0c1a4a5f59 Handle DateTime type for activity while DateTimeImmutable is expected 2024-01-08 12:35:09 +01:00
6f358ee1a9 Implement 'at date' in user render component for activities 2024-01-08 11:25:33 +01:00
0f36b9349b Improve naming for 'at date' in user render component 2024-01-08 11:25:13 +01:00
d18cc29acf Revert "UX: [address details] improve button integration"
This reverts commit 89fb87f71f.
2023-07-12 17:45:06 +02:00
4220d1a2d3 Revert "UX: [vue][onTheFly] improve residential address position in modale"
This reverts commit 62d6106801.
2023-07-12 17:44:47 +02:00
1ae27152c2 Merge branch 'master' into 616_rapid-action 2023-07-12 15:38:51 +02:00
b946f8c10a Merge branch 'master' into 616_rapid-action 2023-05-24 19:56:24 +02:00
62d6106801 UX: [vue][onTheFly] improve residential address position in modale 2023-05-24 19:55:17 +02:00
89fb87f71f UX: [address details] improve button integration 2023-05-24 19:54:13 +02:00
1337360690 Fixed [search page] quickMenu: improve position and design, manage duplicate buttons 2023-05-24 18:25:35 +02:00
9324c33caf Merge branch 'master' into 616_rapid-action 2023-05-24 11:21:34 +02:00
c2dd9ef676 wip 2022-07-12 09:37:16 +02:00
a42d7231d9 not display flash menu if menu is empty 2022-07-11 17:23:34 +02:00
38deaf6f36 remove outdated deprecated message 2022-07-11 17:11:27 +02:00
04fc5b6614 flash menu rapid action built with chill_menu() 2022-07-11 17:11:21 +02:00
384b2be577 flash menu rapid action in search results: bootstrap dropdown integration 2022-07-11 12:35:00 +02:00
263 changed files with 1590 additions and 12979 deletions

View File

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

21
.changes/v2.20.0.md Normal file
View File

@@ -0,0 +1,21 @@
## v2.20.0 - 2024-06-05
### Fixed
* ([#170](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/170)) Display agents traitants instead of accompanying period referrer in export list social actions.
* Added translations for choices of durations (> 5 hours)
### Feature
* ([#145](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/145)) Allow to open documents in LibreOffice locally (need configuration within security);
This endpoint should be added to make the endpoint works properly:
```yaml
security:
firewalls:
dav:
pattern: ^/dav
provider: chain_provider
stateless: true
guard:
authenticators:
- Chill\DocStoreBundle\Security\Guard\JWTOnDavUrlAuthenticator
```

3
.changes/v2.20.1.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.20.1 - 2024-06-05
### Fixed
* Do not allow StoredObjectCreated for edit and convert buttons

31
.changes/v2.21.0.md Normal file
View File

@@ -0,0 +1,31 @@
## v2.21.0 - 2024-06-18
### Feature
* Add flash menu buttons in search results, to open directly a new calendar, or a new activity in an accompanying period
* ([#122](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/122)) Improve the list of calendar in the search results: make all calendar clicable, and display a list of calendars
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] add start date and end date on filters "filter course by referrer job" and "filter course by referrer scope"
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] the aggregator "Group by referrer" now accept a date range.
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] add date range on "group course by referrer's scope"
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] add date range on "group course by referrer's jobs"
* ([#168](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/168) In the UX, display user job and service at the time when he performs an action:
now, the job and service is shown:
* at the activity's date,
* at the appointment's date,
* when the user is marked as referrer for an accompanying period work,
* when the user apply a transition in a workflow,
* when the user updates or creates "something" ("created/updated by ... at ..."),
* or when he wrote a comment,
*
### Traduction francophone
* Ajout d'un menu "flash" dans les résultats de recherche, pour créer un rendez-vous ou un échange dans un parcours depuis les résultats de recherche;
* Améliore la liste des rendez-vous dans les résultats de recherche: les rendez-vous sont cliquables;
* [exports] Ajout d'intervalles de dates pour des filtres et regroupements des parcours par référent, métier du référent, service du référent;
* Affiche le métier et le service des utilisateurs à la date à laquelle il a exécuté une action. Le métier et le service est affiché:
* à la date d'un échange,
* au jour d'un rendez-vous,
* quand l'utilisateur est devenu référent d'un parcours d'accompagnement,
* quand il a appliqué une transition sur un workflow,
* quand il a mise à jour ou créé une fiche, dans les mentions "créé / mise à jour par ..., le ...",
* quand il a mis à jour un commentaire,
*

View File

@@ -6,6 +6,64 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.21.0 - 2024-06-18
### Feature
* Add flash menu buttons in search results, to open directly a new calendar, or a new activity in an accompanying period
* ([#122](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/122)) Improve the list of calendar in the search results: make all calendar clicable, and display a list of calendars
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] add start date and end date on filters "filter course by referrer job" and "filter course by referrer scope"
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] the aggregator "Group by referrer" now accept a date range.
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] add date range on "group course by referrer's scope"
* ([#282](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/282)) [export] add date range on "group course by referrer's jobs"
* ([#168](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/168) In the UX, display user job and service at the time when he performs an action:
now, the job and service is shown:
* at the activity's date,
* at the appointment's date,
* when the user is marked as referrer for an accompanying period work,
* when the user apply a transition in a workflow,
* when the user updates or creates "something" ("created/updated by ... at ..."),
* or when he wrote a comment,
*
### Traduction francophone
* Ajout d'un menu "flash" dans les résultats de recherche, pour créer un rendez-vous ou un échange dans un parcours depuis les résultats de recherche;
* Améliore la liste des rendez-vous dans les résultats de recherche: les rendez-vous sont cliquables;
* [exports] Ajout d'intervalles de dates pour des filtres et regroupements des parcours par référent, métier du référent, service du référent;
* Affiche le métier et le service des utilisateurs à la date à laquelle il a exécuté une action. Le métier et le service est affiché:
* à la date d'un échange,
* au jour d'un rendez-vous,
* quand l'utilisateur est devenu référent d'un parcours d'accompagnement,
* quand il a appliqué une transition sur un workflow,
* quand il a mise à jour ou créé une fiche, dans les mentions "créé / mise à jour par ..., le ...",
* quand il a mis à jour un commentaire,
*
## v2.20.1 - 2024-06-05
### Fixed
* Do not allow StoredObjectCreated for edit and convert buttons
## v2.20.0 - 2024-06-05
### Fixed
* ([#170](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/170)) Display agents traitants instead of accompanying period referrer in export list social actions.
* Added translations for choices of durations (> 5 hours)
### Feature
* ([#145](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/145)) Allow to open documents in LibreOffice locally (need configuration within security);
This endpoint should be added to make the endpoint works properly:
```yaml
security:
firewalls:
dav:
pattern: ^/dav
provider: chain_provider
stateless: true
guard:
authenticators:
- Chill\DocStoreBundle\Security\Guard\JWTOnDavUrlAuthenticator
```
## v2.19.0 - 2024-05-14
### Feature
* ([#197](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/197)) Make the script which subscribe to microsoft calendars changes more tolerant to errors or missing configuration on the microsoft side

View File

@@ -92,12 +92,12 @@
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": ">= 7.5",
"phpunit/phpunit": "^10.5.24",
"rector/rector": "^1.1.0",
"symfony/debug-bundle": "^5.4",
"symfony/dotenv": "^5.4",
"symfony/maker-bundle": "^1.20",
"symfony/phpunit-bridge": "^5.4",
"symfony/phpunit-bridge": "^7.1",
"symfony/runtime": "^5.4",
"symfony/stopwatch": "^5.4",
"symfony/var-dumper": "^5.4"
@@ -115,8 +115,6 @@
"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(): ?string
public function addRole()
{
// we do not need any new role for this filter, so we return null
return null;

View File

@@ -95,7 +95,7 @@ custom developments. But most of the time, this should be fine.
You have to configure some local variables, which are described in the :code:`.env` file. The secrets should not be stored
in this :code:`.env` file, but instead using the `secrets management tool <https://symfony.com/doc/current/configuration/secrets.html>`_
or in the :code:`.env.local` file, which should not be commited to the git repository.
or in the :code:`.env.local` file, which should not be committed to the git repository.
You do not need to set variables for the smtp server, redis server and relatorio server, as they are generated automatically
by the symfony server, from the docker compose services.
@@ -114,6 +114,12 @@ you can either:
- add the generated password to the secrets manager (**note**: you must add the generated hashed password to the secrets env,
not the password in clear text).
- set up the jwt authentication bundle
Some environment variables are available for the JWT authentication bundle in the :code:`.env` file. You must also run the command
:code:`symfony console lexik:jwt:generate-keypair` to generate some keys that will be stored in the paths set up in the :code:`JWT_SECRET_KEY`
and the :code:`JWT_PUBLIC_KEY` env variables. This is only required for using the stored documents in Chill.
Prepare migrations and other tools
**********************************
@@ -179,7 +185,7 @@ Install fixtures
This will generate user accounts, centers, and some basic configuration.
The accounts created are: :code:`center a_social`, :code:`center b_social`, :code:`center a_direction`, ... The full list is
visibile in the "users" table: :code:`docker compose exec database psql -U app -c "SELECT username FROM users"`.
visible in the "users" table: :code:`docker compose exec database psql -U app -c "SELECT username FROM users"`.
The password is always :code:`password`.

View File

@@ -27,7 +27,7 @@
"popper.js": "^1.16.1",
"postcss-loader": "^7.0.2",
"raw-loader": "^4.0.2",
"sass-loader": "^14.0.0",
"sass-loader": "^13.0.0",
"select2": "^4.0.13",
"select2-bootstrap-theme": "0.1.0-beta.10",
"style-loader": "^3.3.1",
@@ -46,9 +46,11 @@
"@fullcalendar/vue3": "^6.1.4",
"@popperjs/core": "^2.9.2",
"@types/leaflet": "^1.9.3",
"@types/dompurify": "^3.0.5",
"dropzone": "^5.7.6",
"es6-promise": "^4.2.8",
"leaflet": "^1.7.1",
"marked": "^12.0.2",
"masonry-layout": "^4.2.2",
"mime": "^4.0.0",
"swagger-ui": "^4.15.5",
@@ -56,7 +58,7 @@
"vue": "^3.2.37",
"vue-i18n": "^9.1.6",
"vue-multiselect": "3.0.0-alpha.2",
"vue-toast-notification": "^3.1.2",
"vue-toast-notification": "^2.0",
"vuex": "^4.0.0"
},
"browserslist": [

View File

@@ -1,29 +1,34 @@
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: "#^Property Chill\\\\CustomFieldsBundle\\\\Entity\\\\CustomField\\:\\:\\$required \\(false\\) does not accept bool\\.$#"
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php
path: src/Bundle/ChillPersonBundle/Form/PersonType.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/DocumentAccompanyingCourseController.php
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.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\\.$#"
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\\.$#"
count: 2
path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php
path: src/Bundle/ChillMainBundle/Repository/NotificationRepository.php
-
message: "#^Foreach overwrites \\$key with its key variable\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php
-
message: "#^Variable \\$participation might not be defined\\.$#"
@@ -35,106 +40,6 @@ 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
@@ -160,31 +65,11 @@ 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,9 +28,6 @@ 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);
@@ -39,8 +36,12 @@ return static function (RectorConfig $rectorConfig): void {
//define sets of rules
$rectorConfig->sets([
\Rector\Set\ValueObject\LevelSetList::UP_TO_PHP_82,
\Rector\Symfony\Set\SymfonyLevelSetList::UP_TO_SYMFONY_54,
\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\Doctrine\Set\DoctrineSetList::DOCTRINE_CODE_QUALITY,
\Rector\Doctrine\Set\DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
]);

View File

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

View File

@@ -0,0 +1,49 @@
<?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\ActivityBundle\Menu;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Security;
final readonly class AccompanyingCourseQuickMenuBuilder implements LocalMenuBuilderInterface
{
public function __construct(private Security $security) {}
public static function getMenuIds(): array
{
return ['accompanying_course_quick_menu'];
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingCourse */
$accompanyingCourse = $parameters['accompanying-course'];
if ($this->security->isGranted(ActivityVoter::CREATE, $accompanyingCourse)) {
$menu
->addChild('Create a new activity in accompanying course', [
'route' => 'chill_activity_activity_new',
'routeParameters' => [
// 'activityType_id' => '',
'accompanying_period_id' => $accompanyingCourse->getId(),
],
])
->setExtras([
'order' => 10,
'icon' => 'plus',
])
;
}
}
}

View File

@@ -68,7 +68,7 @@
<div class="wl-col title"><h3>{{ 'Referrer'|trans }}</h3></div>
<div class="wl-col list">
<p class="wl-item">
<span class="badge-user">{{ activity.user|chill_entity_render_box }}</span>
<span class="badge-user">{{ activity.user|chill_entity_render_box({'at_date': activity.date}) }}</span>
</p>
</div>
</div>

View File

@@ -87,7 +87,8 @@
<li>
{% if bloc.type == 'user' %}
<span class="badge-user">
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false }) }}
hello
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false, 'at_date': entity.date }) }}
</span>
{% else %}
{{ _self.insert_onthefly(bloc.type, item) }}
@@ -114,7 +115,7 @@
<li>
{% if bloc.type == 'user' %}
<span class="badge-user">
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false }) }}
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false, 'at_date': entity.date }) }}
</span>
{% else %}
{{ _self.insert_onthefly(bloc.type, item) }}
@@ -142,7 +143,7 @@
<span class="wl-item">
{% if bloc.type == 'user' %}
<span class="badge-user">
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false }) }}
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false, 'at_date': entity.date }) }}
{%- if context == 'calendar_accompanyingCourse' or context == 'calendar_person' %}
{% set invite = entity.inviteForUser(item) %}
{% if invite is not null %}

View File

@@ -41,7 +41,7 @@
{% if activity.user and t.userVisible %}
<li>
<span class="item-key">{{ 'Referrer'|trans ~ ': ' }}</span>
<span class="badge-user">{{ activity.user|chill_entity_render_box }}</span>
<span class="badge-user">{{ activity.user|chill_entity_render_box({'at_date': activity.date}) }}</span>
</li>
{% endif %}

View File

@@ -37,7 +37,7 @@
{%- if entity.user is not null %}
<dt class="inline">{{ 'Referrer'|trans|capitalize }}</dt>
<dd>
<span class="badge-user">{{ entity.user|chill_entity_render_box }}</span>
<span class="badge-user">{{ entity.user|chill_entity_render_box({'at_date': entity.date}) }}</span>
</dd>
{% endif %}

View File

@@ -145,7 +145,7 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
throw new \RuntimeException('Could not determine context of activity.');
}
} elseif ($subject instanceof AccompanyingPeriod) {
if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep()) {
if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep() || AccompanyingPeriod::STEP_DRAFT === $subject->getStep()) {
if (\in_array($attribute, [self::UPDATE, self::CREATE, self::DELETE], true)) {
return false;
}

View File

@@ -60,7 +60,7 @@ final class TranslatableActivityTypeTest extends KernelTestCase
$this->assertInstanceOf(
ActivityType::class,
$form->getData()['type'],
'The data is an instance of Chill\\ActivityBundle\\Entity\\ActivityType'
'The data is an instance of Chill\ActivityBundle\Entity\ActivityType'
);
$this->assertEquals($type->getId(), $form->getData()['type']->getId());

View File

@@ -77,6 +77,18 @@ Choose a type: Choisir un type
4 hours: 4 heures
4 hours 30: 4 heures 30
5 hours: 5 heures
5 hours 30: 5 heure 30
6 hours: 6 heures
6 hours 30: 6 heure 30
7 hours: 7 heures
7 hours 30: 7 heure 30
8 hours: 8 heures
8 hours 30: 8 heure 30
9 hours: 9 heures
9 hours 30: 9 heure 30
10 hours: 10 heures
11 hours: 11 heures
12 hours: 12 heures
Concerned groups: Parties concernées par l'échange
Persons in accompanying course: Usagers du parcours
Third persons: Tiers non-pro.
@@ -210,6 +222,7 @@ Documents label: Libellé du champ Documents
# activity type category admin
ActivityTypeCategory list: Liste des catégories des types d'échange
Create a new activity type category: Créer une nouvelle catégorie de type d'échange
Create a new activity in accompanying course: Créer un échange dans le parcours
# activity delete
Remove activity: Supprimer un échange

View File

@@ -49,13 +49,13 @@
<li>
<span>
<abbr class="referrer" title={{ 'Created by'|trans }}>{{ 'By'|trans }}:</abbr>
<b>{{ entity.createdBy|chill_entity_render_box }}</b>
<b>{{ entity.createdBy|chill_entity_render_box({'at_date': entity.date}) }}</b>
</span>
</li>
<li>
<span>
<abbr class="referrer" title={{ 'Created for'|trans }}>{{ 'For'|trans }}:</abbr>
<b>{{ entity.agent|chill_entity_render_box }}</b>
<b>{{ entity.agent|chill_entity_render_box({'at_date': entity.date}) }}</b>
</span>
</li>

View File

@@ -18,11 +18,11 @@
<dd>{{ entity.type|chill_entity_render_box }}</dd>
<dt class="inline">{{ 'Created by'|trans }}</dt>
<dd>{{ entity.createdBy }}</dd>
<dd>{{ entity.createdBy|chill_entity_render_box({'at_date': entity.date}) }}</dd>
<dt class="inline">{{ 'Created for'|trans }}</dt>
<dd>{{ entity.agent }}</dd>
<dd>{{ entity.agent|chill_entity_render_box({'at_date': entity.date}) }}</dd>
<dt class="inline">{{ 'Asideactivity location'|trans }}</dt>
{%- if entity.location.name is defined -%}
<dd>{{ entity.location.name }}</dd>

View File

@@ -72,21 +72,21 @@ days: jours
1 hour 30: 1 heure 30
1 hour 45: 1 heure 45
2 hours: 2 heures
2 hours 30: 2 heure 30
2 hours 30: 2 heures 30
3 hours: 3 heures
3 hours 30: 3 heure 30
3 hours 30: 3 heures 30
4 hours: 4 heures
4 hours 30: 4 heure 30
4 hours 30: 4 heures 30
5 hours: 5 heures
5 hours 30: 5 heure 30
5 hours 30: 5 heures 30
6 hours: 6 heures
6 hours 30: 6 heure 30
6 hours 30: 6 heures 30
7 hours: 7 heures
7 hours 30: 7 heure 30
7 hours 30: 7 heures 30
8 hours: 8 heures
8 hours 30: 8 heure 30
8 hours 30: 8 heures 30
9 hours: 9 heures
9 hours 30: 9 heure 30
9 hours 30: 9 heures 30
10 hours: 10 heures
1/2 day: 1/2 jour
1 day: 1 jour

View File

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

View File

@@ -440,6 +440,16 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
return $this->startDate;
}
/**
* get the date of the calendar.
*
* Useful for showing the date of the calendar event, required by twig in some places.
*/
public function getDate(): ?\DateTimeImmutable
{
return $this->getStartDate();
}
public function getStatus(): ?string
{
return $this->status;

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Menu;
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Security;
final readonly class AccompanyingCourseQuickMenuBuilder implements LocalMenuBuilderInterface
{
public function __construct(private Security $security) {}
public static function getMenuIds(): array
{
return ['accompanying_course_quick_menu'];
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingCourse */
$accompanyingCourse = $parameters['accompanying-course'];
if ($this->security->isGranted(CalendarVoter::CREATE, $accompanyingCourse)) {
$menu
->addChild('Create a new calendar in accompanying course', [
'route' => 'chill_calendar_calendar_new',
'routeParameters' => [
'accompanying_period_id' => $accompanyingCourse->getId(),
],
])
->setExtras([
'order' => 20,
'icon' => 'plus',
])
;
}
}
}

View File

@@ -37,12 +37,12 @@ class RemoteEventConverter
* valid when the remote string contains also a timezone, like in
* lastModifiedDate.
*/
final public const REMOTE_DATETIMEZONE_FORMAT = 'Y-m-d\\TH:i:s.u?P';
final public const REMOTE_DATETIMEZONE_FORMAT = 'Y-m-d\TH:i:s.u?P';
/**
* Same as above, but sometimes the date is expressed with only 6 milliseconds.
*/
final public const REMOTE_DATETIMEZONE_FORMAT_ALT = 'Y-m-d\\TH:i:s.uP';
final public const REMOTE_DATETIMEZONE_FORMAT_ALT = 'Y-m-d\TH:i:s.uP';
private const REMOTE_DATE_FORMAT = 'Y-m-d\TH:i:s.u0';

View File

@@ -1 +1,2 @@
import './scss/badge.scss';
import './scss/calendar-list.scss';

View File

@@ -0,0 +1,26 @@
ul.calendar-list {
list-style-type: none;
padding: 0;
& > li {
display: inline-block;
}
& > li:nth-child(n+2) {
margin-left: 0.25rem;
}
}
div.calendar-list {
ul.calendar-list {
display: inline-block;
}
& > a.calendar-list__global {
display: inline-block;;
padding: 0.2rem;
min-width: 2rem;
border: 1px solid var(--bs-chill-blue);
border-radius: 0.25rem;
text-align: center;
}
}

View File

@@ -55,7 +55,7 @@
<div class="item-col">
<ul class="list-content">
{% if calendar.mainUser is not empty %}
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box }}</span>
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span>
{% endif %}
</ul>
</div>
@@ -132,7 +132,7 @@
<li class="cancel">
<span class="createdBy">
{{ 'Created by'|trans }}
<b>{{ calendar.activity.createdBy|chill_entity_render_string }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
<b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
</span>
</li>
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}

View File

@@ -89,7 +89,7 @@ class CalendarVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
switch ($attribute) {
case self::SEE:
case self::CREATE:
if (AccompanyingPeriod::STEP_DRAFT === $subject->getStep()) {
if (AccompanyingPeriod::STEP_DRAFT === $subject->getStep() || AccompanyingPeriod::STEP_CLOSED === $subject->getStep()) {
return false;
}

View File

@@ -26,6 +26,7 @@ The calendar item has been successfully removed.: Le rendez-vous a été supprim
From the day: Du
to the day: au
Transform to activity: Transformer en échange
Create a new calendar in accompanying course: Créer un rendez-vous dans le parcours
Will send SMS: Un SMS de rappel sera envoyé
Will not send SMS: Aucun SMS de rappel ne sera envoyé
SMS already sent: Un SMS a été envoyé

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,65 @@
<?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\DocGeneratorBundle\Test;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
/**
* @template T of object
*/
abstract class DocGenNormalizerTestAbstract extends KernelTestCase
{
public function testNullValueHasSameKeysAsNull(): void
{
$normalizedObject = $this->getNormalizer()->normalize($this->provideNotNullObject(), 'docgen', [
AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => $this->provideDocGenExpectClass(),
]);
$nullNormalizedObject = $this->getNormalizer()->normalize(null, 'docgen', [
AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => $this->provideDocGenExpectClass(),
]);
self::assertEqualsCanonicalizing(array_keys($normalizedObject), array_keys($nullNormalizedObject));
self::assertArrayHasKey('isNull', $nullNormalizedObject, 'each object must have an "isNull" key');
self::assertTrue($nullNormalizedObject['isNull'], 'isNull key must be true for null objects');
self::assertFalse($normalizedObject['isNull'], 'isNull key must be false for null objects');
foreach ($normalizedObject as $key => $value) {
if (in_array($key, ['isNull', 'type'])) {
continue;
}
if (is_array($value)) {
if (array_is_list($value)) {
self::assertEquals([], $nullNormalizedObject[$key], "list must be serialized as an empty array, in {$key}");
} else {
self::assertEqualsCanonicalizing(array_keys($value), array_keys($nullNormalizedObject[$key]), "sub-object must have the same keys, in {$key}");
}
} elseif (is_string($value)) {
self::assertEquals('', $nullNormalizedObject[$key], 'strings must be ');
}
}
}
/**
* @return T
*/
abstract public function provideNotNullObject(): object;
/**
* @return class-string<T>
*/
abstract public function provideDocGenExpectClass(): string;
abstract public function getNormalizer(): NormalizerInterface;
}

View File

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

View File

@@ -86,7 +86,7 @@ class DocumentCategory
return $this;
}
public function setDocumentClass(?string $documentClass): self
public function setDocumentClass($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 $person): self
public function setPerson($person): self
{
$this->person = $person;
return $this;
}
public function setScope(?Scope $scope): self
public function setScope($scope): self
{
$this->scope = $scope;

View File

@@ -313,4 +313,19 @@ class StoredObject implements Document, TrackCreationInterface
return $this;
}
public function saveHistory(): void
{
if ('' === $this->getFilename()) {
return;
}
$this->datas['history'][] = [
'filename' => $this->getFilename(),
'iv' => $this->getIv(),
'key_infos' => $this->getKeyInfos(),
'type' => $this->getType(),
'before' => (new \DateTimeImmutable('now'))->getTimestamp(),
];
}
}

View File

@@ -57,8 +57,8 @@ class StoredObjectDataMapper implements DataMapperInterface
/** @var StoredObject $viewData */
if ($viewData->getFilename() !== $forms['stored_object']->getData()['filename']) {
// we do not want to erase the previous object
$viewData = new StoredObject();
// we want to keep the previous history
$viewData->saveHistory();
}
$viewData->setFilename($forms['stored_object']->getData()['filename']);

View File

@@ -4,13 +4,13 @@
Actions
</button>
<ul class="dropdown-menu">
<li v-if="props.canEdit && is_extension_editable(props.storedObject.type)">
<li v-if="props.canEdit && is_extension_editable(props.storedObject.type) && props.storedObject.status !== 'stored_object_created'">
<wopi-edit-button :stored-object="props.storedObject" :classes="{'dropdown-item': true}" :execute-before-leave="props.executeBeforeLeave"></wopi-edit-button>
</li>
<li v-if="props.canEdit && is_extension_editable(props.storedObject.type) && props.davLink !== undefined && props.davLinkExpiration !== undefined">
<desktop-edit-button :classes="{'dropdown-item': true}" :edit-link="props.davLink" :expiration-link="props.davLinkExpiration"></desktop-edit-button>
</li>
<li v-if="props.storedObject.type != 'application/pdf' && is_extension_viewable(props.storedObject.type) && props.canConvertPdf">
<li v-if="props.storedObject.type != 'application/pdf' && is_extension_viewable(props.storedObject.type) && props.canConvertPdf && props.storedObject.status !== 'stored_object_created'">
<convert-button :stored-object="props.storedObject" :filename="filename" :classes="{'dropdown-item': true}"></convert-button>
</li>
<li v-if="props.canDownload">

View File

@@ -13,7 +13,7 @@ import {reactive} from "vue";
import {StoredObject, StoredObjectCreated} from "../../types";
interface ConvertButtonConfig {
storedObject: StoredObject|StoredObjectCreated,
storedObject: StoredObject,
classes: { [key: string]: boolean},
filename?: string,
};

View File

@@ -11,7 +11,7 @@ import {build_wopi_editor_link} from "./helpers";
import {StoredObject, StoredObjectCreated, WopiEditButtonExecutableBeforeLeaveFunction} from "../../types";
interface WopiEditButtonConfig {
storedObject: StoredObject|StoredObjectCreated,
storedObject: StoredObject,
returnPath?: string,
classes: {[k: string] : boolean},
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction,

View File

@@ -0,0 +1,53 @@
<?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\DocStoreBundle\Tests\Entity;
use Chill\DocStoreBundle\Entity\StoredObject;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* @internal
*
* @coversNothing
*/
class StoredObjectTest extends KernelTestCase
{
public function testSaveHistory(): void
{
$storedObject = new StoredObject();
$storedObject
->setFilename('test_0')
->setIv([2, 4, 6, 8])
->setKeyInfos(['key' => ['data0' => 'data0']])
->setType('text/html');
$storedObject->saveHistory();
$storedObject
->setFilename('test_1')
->setIv([8, 10, 12])
->setKeyInfos(['key' => ['data1' => 'data1']])
->setType('text/text');
$storedObject->saveHistory();
self::assertEquals('test_0', $storedObject->getDatas()['history'][0]['filename']);
self::assertEquals([2, 4, 6, 8], $storedObject->getDatas()['history'][0]['iv']);
self::assertEquals(['key' => ['data0' => 'data0']], $storedObject->getDatas()['history'][0]['key_infos']);
self::assertEquals('text/html', $storedObject->getDatas()['history'][0]['type']);
self::assertEquals('test_1', $storedObject->getDatas()['history'][1]['filename']);
self::assertEquals([8, 10, 12], $storedObject->getDatas()['history'][1]['iv']);
self::assertEquals(['key' => ['data1' => 'data1']], $storedObject->getDatas()['history'][1]['key_infos']);
self::assertEquals('text/text', $storedObject->getDatas()['history'][1]['type']);
}
}

View File

@@ -56,14 +56,14 @@ class StoredObjectTypeTest extends TypeTestCase
{"filename":"abcdef","iv":[10, 15, 20, 30],"keyInfos":[],"type":"text/html","status":"object_store_created"}
JSON];
$model = new StoredObject();
$originalObjectId = spl_object_id($model);
$originalObjectId = spl_object_hash($model);
$form = $this->factory->create(StoredObjectType::class, $model, ['has_title' => true]);
$form->submit($formData);
$this->assertTrue($form->isSynchronized());
$model = $form->getData();
$this->assertNotEquals($originalObjectId, spl_object_hash($model));
$this->assertEquals($originalObjectId, spl_object_hash($model));
$this->assertEquals('abcdef', $model->getFilename());
$this->assertEquals([10, 15, 20, 30], $model->getIv());
$this->assertEquals('text/html', $model->getType());

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,84 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,106 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,100 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\FranceTravailApiBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillFranceTravailApiBundle extends Bundle {}

View File

@@ -1,56 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

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

View File

@@ -1,16 +0,0 @@
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

@@ -1,93 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\JobBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillJobBundle extends Bundle {}

View File

@@ -1,123 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,150 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,73 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,62 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,80 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,57 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,196 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,303 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,205 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,214 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,192 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,407 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,107 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,100 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,188 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,395 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,497 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,586 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,125 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,256 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,70 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,75 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,91 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,155 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,197 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,108 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,116 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,72 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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

@@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\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 {}

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