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

This commit is contained in:
Julien Fastré 2024-11-13 22:44:29 +01:00
commit 903a87c589
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
86 changed files with 1444 additions and 446 deletions

View File

@ -1,6 +0,0 @@
kind: Fixed
body: Show only the current referrer in the page "show" for an accompanying period
workf
time: 2024-09-16T15:18:43.017401122+02:00
custom:
Issue: "308"

6
.changes/v3.1.1.md Normal file
View File

@ -0,0 +1,6 @@
## v3.1.1 - 2024-10-01
### Fixed
* ([#308](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/308)) Show only the current referrer in the page "show" for an accompanying period workf
* ([#309](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/309)) Correctly compute the grouping by referrer aggregator
* Fixed typing of custom field long choice and custom field group

3
.changes/v3.2.0.md Normal file
View File

@ -0,0 +1,3 @@
## v3.2.0 - 2024-10-30
### Feature
* Introduce a gender entity

4
.changes/v3.2.1.md Normal file
View File

@ -0,0 +1,4 @@
## v3.2.1 - 2024-10-31
### Fixed
* Add the possibility of unknown to the gender entity
* Fix the fusion of person doubles by excluding accompanyingPeriod work entities to be deleted. They are moved instead.

3
.changes/v3.2.2.md Normal file
View File

@ -0,0 +1,3 @@
## v3.2.2 - 2024-10-31
### Fixed
* Fix gender translation for unknown

4
.changes/v3.2.3.md Normal file
View File

@ -0,0 +1,4 @@
## v3.2.3 - 2024-11-05
### Fixed
* ([#315](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/315)) Fix display of accompanying period work referrers. Only current referrers should be displayed.
Fix color of Chill footer

3
.changes/v3.2.4.md Normal file
View File

@ -0,0 +1,3 @@
## v3.2.4 - 2024-11-06
### Fixed
* Fix compilation of chill assets

View File

@ -6,22 +6,57 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v3.2.4 - 2024-11-06
### Fixed
* Fix compilation of chill assets
## v3.2.3 - 2024-11-05
### Fixed
* ([#315](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/315)) Fix display of accompanying period work referrers. Only current referrers should be displayed.
Fix color of Chill footer
## v3.2.2 - 2024-10-31
### Fixed
* Fix gender translation for unknown
## v3.2.1 - 2024-10-31
### Fixed
* Add the possibility of unknown to the gender entity
* Fix the fusion of person doubles by excluding accompanyingPeriod work entities to be deleted. They are moved instead.
## v3.2.0 - 2024-10-30
### Feature
* Introduce a gender entity
## v3.1.1 - 2024-10-01
### Fixed
* ([#308](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/308)) Show only the current referrer in the page "show" for an accompanying period workf
* ([#309](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/309)) Correctly compute the grouping by referrer aggregator
* Fixed typing of custom field long choice and custom field group
## v3.1.0 - 2024-08-30
### Feature
* Add export aggregator to aggregate activities by household + filter persons that are not part of an accompanyingperiod during a certain timeframe.
* Add export aggregator to aggregate activities by household + filter persons that are not part of an accompanyingperiod during a certain timeframe.
## v3.0.0 - 2024-08-26
### Fixed
* Fix delete action for accompanying periods in draft state
* Fix connection to azure when making an calendar event in chill
* CollectionType js fixes for remove button and adding multiple entries
* Fix delete action for accompanying periods in draft state
* Fix connection to azure when making an calendar event in chill
* CollectionType js fixes for remove button and adding multiple entries
## v2.24.0 - 2024-09-11
### Feature
* ([#306](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/306)) When a document is converted or downloaded in the browser, this document is removed from the browser memory after 45s. Future click on the button re-download the document.
* ([#306](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/306)) When a document is converted or downloaded in the browser, this document is removed from the browser memory after 45s. Future click on the button re-download the document.
## v2.23.0 - 2024-07-19 & 2024-07-23
## v2.23.0 - 2024-07-23 & 2024-07-19
### Feature
* ([#221](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/221)) [DX] move async-upload-bundle features into chill-bundles
* Add job bundle (module emploi)
* Upgrade import of address list to the last version of compiled addresses of belgian-best-address
* Upgrade CKEditor and refactor configuration with use of typescript
* ([#123](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/123)) Add a button to duplicate calendar ranges from a week to another one
* [admin] filter users by active / inactive in the admin user's list
* ([#273](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/273)) Add the possibility to mark all notifications as read
@ -31,6 +66,8 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
* Do not update the "createdAt" column when importing postal code which does not change
* Display filename on file upload within the UI interface
### Fixed
* Fix resolving of centers for an household, which will fix in turn the access control
* Resolved type hinting error in activity list export
* ([#271](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/271)) Take into account the acp closing date in the acp works date filter
### Traduction française des principaux changements
@ -43,25 +80,15 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
- Agrandit l'icône du type de fichier dans l'interface de dépôt de fichier;
- correction: tient compte de la date de fermeture du parcours dans les filtres sur les actions d'accompagnement.
* ([#221](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/221)) [DX] move async-upload-bundle features into chill-bundles
* Add job bundle (module emploi)
* Upgrade import of address list to the last version of compiled addresses of belgian-best-address
* Upgrade CKEditor and refactor configuration with use of typescript
### Fixed
* Fix resolving of centers for an household, which will fix in turn the access control
* Resolved type hinting error in activity list export
## v2.22.2 - 2024-07-03
### Fixed
* Remove scope required for event participation stats
* Remove scope required for event participation stats
## v2.22.1 - 2024-07-01
### Fixed
* Remove debug word
* Remove debug word
### DX
* Add a command for reading official address DB from Luxembourg and update chill addresses
* Add a command for reading official address DB from Luxembourg and update chill addresses
## v2.22.0 - 2024-06-25
### Feature
@ -104,7 +131,7 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.20.1 - 2024-06-05
### Fixed
* Do not allow StoredObjectCreated for edit and convert buttons
* Do not allow StoredObjectCreated for edit and convert buttons
## v2.20.0 - 2024-06-05
### Fixed
@ -151,96 +178,96 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.18.2 - 2024-04-12
### Fixed
* ([#250](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/250)) Postal codes import : fix the source URL and the keys to handle each record
* ([#250](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/250)) Postal codes import : fix the source URL and the keys to handle each record
## v2.18.1 - 2024-03-26
### Fixed
* Fix layout issue in document generation for admin (minor)
* Fix layout issue in document generation for admin (minor)
## v2.18.0 - 2024-03-26
### Feature
* ([#268](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/268)) Improve admin UX to configure document templates for document generation
* ([#268](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/268)) Improve admin UX to configure document templates for document generation
### Fixed
* ([#267](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/267)) Fix the join between job and user in the user list (admin): show only the current user job
* ([#267](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/267)) Fix the join between job and user in the user list (admin): show only the current user job
## v2.17.0 - 2024-03-19
### Feature
* ([#237](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/237)) New export filter for social actions with an evaluation created between two dates
* ([#258](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/258)) In the list of accompangying period, add the list of person's centers and the duration of the course
* ([#238](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/238)) Allow to customize list person with new fields
* ([#237](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/237)) New export filter for social actions with an evaluation created between two dates
* ([#258](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/258)) In the list of accompangying period, add the list of person's centers and the duration of the course
* ([#238](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/238)) Allow to customize list person with new fields
* ([#159](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/159)) Admin can publish news on the homepage
### Fixed
* ([#264](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/264)) Fix languages: load the languages in all availables languages configured for Chill
* ([#259](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/259)) Keep a consistent behaviour between the filtering of activities within the document generation (model "accompanying period with activities"), and the same filter in the list of activities for an accompanying period
* ([#264](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/264)) Fix languages: load the languages in all availables languages configured for Chill
* ([#259](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/259)) Keep a consistent behaviour between the filtering of activities within the document generation (model "accompanying period with activities"), and the same filter in the list of activities for an accompanying period
## v2.16.3 - 2024-02-26
### Fixed
* ([#236](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/236)) Fix translation of user job -> 'service' must be 'métier'
* ([#236](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/236)) Fix translation of user job -> 'service' must be 'métier'
### UX
* ([#232](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/232)) Order user jobs and services alphabetically in export filters
* ([#232](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/232)) Order user jobs and services alphabetically in export filters
## v2.16.2 - 2024-02-21
### Fixed
* Check for null values in closing motive of parcours d'accompagnement for correct rendering of template
* Check for null values in closing motive of parcours d'accompagnement for correct rendering of template
## v2.16.1 - 2024-02-09
### Fixed
* Force bootstrap version to avoid error in builds with newer version
* Force bootstrap version to avoid error in builds with newer version
## v2.16.0 - 2024-02-08
### Feature
* ([#231](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/231)) Create new filter for persons having a participation in an accompanying period during a certain time span
* ([#241](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/241)) [Export][List of accompanyign period] Add two columns: the list of persons participating to the period, and their ids
* ([#244](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/244)) Add capability to generate export about change of steps of accompanying period, and generate exports for this
* ([#253](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/253)) Export: group accompanying period by person participating
* ([#243](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/243)) Export: add filter for courses not linked to a reference address
* ([#229](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/229)) Allow to group activities linked with accompanying period by reason
* ([#115](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/115)) Prevent social work to be saved when another user edited conccurently the social work
* Modernize the event bundle, with some new fields and multiple improvements
* ([#231](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/231)) Create new filter for persons having a participation in an accompanying period during a certain time span
* ([#241](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/241)) [Export][List of accompanyign period] Add two columns: the list of persons participating to the period, and their ids
* ([#244](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/244)) Add capability to generate export about change of steps of accompanying period, and generate exports for this
* ([#253](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/253)) Export: group accompanying period by person participating
* ([#243](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/243)) Export: add filter for courses not linked to a reference address
* ([#229](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/229)) Allow to group activities linked with accompanying period by reason
* ([#115](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/115)) Prevent social work to be saved when another user edited conccurently the social work
* Modernize the event bundle, with some new fields and multiple improvements
### Fixed
* ([#220](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/220)) Fix error in logs about wrong typing of eventArgs in onEditNotificationComment method
* ([#256](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/256)) Fix the conditions upon which social actions should be optional or required in relation to social issues within the activity creation form
* ([#220](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/220)) Fix error in logs about wrong typing of eventArgs in onEditNotificationComment method
* ([#256](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/256)) Fix the conditions upon which social actions should be optional or required in relation to social issues within the activity creation form
### UX
* ([#260](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/260)) Order list of centers alphabetically in dropdown 'user' section admin.
* ([#260](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/260)) Order list of centers alphabetically in dropdown 'user' section admin.
## v2.15.2 - 2024-01-11
### Fixed
* Fix the id_seq used when creating a new accompanying period participation during fusion of two person files
* Fix the id_seq used when creating a new accompanying period participation during fusion of two person files
### DX
* Set placeholder to False for expanded EntityType form fields where required is set to False.
* Set placeholder to False for expanded EntityType form fields where required is set to False.
## v2.15.1 - 2023-12-20
### Fixed
* Fix the household export query to exclude accompanying periods that are in draft state.
* Fix the household export query to exclude accompanying periods that are in draft state.
### DX
* ([#167](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/167)) Fixed readthedocs compilation by updating readthedocs config file and requirements for Sphinx
* ([#167](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/167)) Fixed readthedocs compilation by updating readthedocs config file and requirements for Sphinx
## v2.15.0 - 2023-12-11
### Feature
* ([#191](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/191)) Add export "number of household associate with an exchange"
* ([#235](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/235)) Export: add dates on the filter "filter course by activity type"
* ([#191](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/191)) Add export "number of household associate with an exchange"
* ([#235](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/235)) Export: add dates on the filter "filter course by activity type"
### Fixed
* ([#214](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/214)) Fix error when posting an empty comment on an accompanying period.
* ([#233](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/233)) Fix "filter evaluation by evaluation type" (and add select2 to the list of evaluation types to pick)
* ([#214](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/214)) Fix error when posting an empty comment on an accompanying period.
* ([#233](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/233)) Fix "filter evaluation by evaluation type" (and add select2 to the list of evaluation types to pick)
* ([#234](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/234)) Fix "filter aside activity by date"
* ([#228](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/228)) Fix export of activity for people created before the introduction of the createdAt column on person (during v1)
* ([#246](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/246)) Do not show activities, evaluations and social work when associated to a confidential accompanying period, except for the users which are allowed to see them
* ([#228](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/228)) Fix export of activity for people created before the introduction of the createdAt column on person (during v1)
* ([#246](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/246)) Do not show activities, evaluations and social work when associated to a confidential accompanying period, except for the users which are allowed to see them
## v2.14.1 - 2023-11-29
### Fixed
* Export: fix list person with custom fields
* ([#100](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/100)) Add a paginator to budget elements (resource and charge types) in the admin
* Fix error in ListEvaluation when "handling agents" are alone
* Export: fix list person with custom fields
* ([#100](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/100)) Add a paginator to budget elements (resource and charge types) in the admin
* Fix error in ListEvaluation when "handling agents" are alone
## v2.14.0 - 2023-11-24
### Feature
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
### Fixed
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
* Fix various errors in custom fields administration
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
* Fix various errors in custom fields administration
## v2.13.0 - 2023-11-21
### Feature
@ -254,7 +281,7 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.12.1 - 2023-11-16
### Fixed
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"
## v2.12.0 - 2023-11-15
### Feature
@ -285,36 +312,36 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.11.0 - 2023-11-07
### Feature
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
### Fixed
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
* Fix "group activity by creator job" aggregator
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
* Fix "group activity by creator job" aggregator
## v2.10.6 - 2023-11-07
### Fixed
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix aggregator by geographical unit on person: avoid inconsistencies
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix aggregator by geographical unit on person: avoid inconsistencies
## v2.10.5 - 2023-11-05
### Fixed
* ([#183](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/183)) Fix "problem during download" on some filters, which used a wrong data type
* ([#184](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/184)) Fix filter "activity by date"
* ([#183](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/183)) Fix "problem during download" on some filters, which used a wrong data type
* ([#184](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/184)) Fix filter "activity by date"
## v2.10.4 - 2023-10-26
### Fixed
* Fix null value constraint errors when merging relationships in doubles
* Fix null value constraint errors when merging relationships in doubles
## v2.10.3 - 2023-10-26
### Fixed
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Replace old method of getting translator with injection of translatorInterface
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Replace old method of getting translator with injection of translatorInterface
## v2.10.2 - 2023-10-26
### Fixed
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
## v2.10.1 - 2023-10-24
### Fixed
* Fix export controller when generating an export without any data in session
* Fix export controller when generating an export without any data in session
## v2.10.0 - 2023-10-24
### Feature
@ -339,11 +366,11 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.9.2 - 2023-10-17
### Fixed
* Fix possible null values in string's entities
* Fix possible null values in string's entities
## v2.9.1 - 2023-10-17
### Fixed
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
## v2.9.0 - 2023-10-17
### Feature
@ -391,57 +418,57 @@ But if you do not need this any more, you must ensure that the configuration key
## v2.7.0 - 2023-09-27
### Feature
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
### Fixed
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
## v2.6.3 - 2023-09-19
### Fixed
* Remove id property from document
mappedsuperclass
* Remove id property from document
mappedsuperclass
## v2.6.2 - 2023-09-18
### Fixed
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
## v2.6.1 - 2023-09-14
### Fixed
* Filter out active centers in exports, which uses a different PickCenterType.
* Filter out active centers in exports, which uses a different PickCenterType.
## v2.6.0 - 2023-09-14
### Feature
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Adapt Aside Activity exports: display location, filter by location, group by location
* Use the CRUD controller for center entity + add the isActive property to be able to mask instances of Center that are no longer in use.
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Adapt Aside Activity exports: display location, filter by location, group by location
* Use the CRUD controller for center entity + add the isActive property to be able to mask instances of Center that are no longer in use.
### Fixed
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) reinstate the fusion of duplicate persons
* Missing translation in Work Actions exports
* Reimplement the mission type filter on tasks, only for instances that have a config parameter indicating true for this.
* ([#135](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/135)) Corrects a typing error in 2 filters, which caused an
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) reinstate the fusion of duplicate persons
* Missing translation in Work Actions exports
* Reimplement the mission type filter on tasks, only for instances that have a config parameter indicating true for this.
* ([#135](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/135)) Corrects a typing error in 2 filters, which caused an
error when trying to reedit a saved export
* ([#136](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/136)) [household] when moving a person to a sharing position to a not-sharing position on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.
* ([#136](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/136)) [household] when moving a person to a sharing position to a not-sharing position on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.
* Add missing translation for comment field placeholder in repositionning household editor.
* Do not send an email to creator twice when adding a comment to a notification
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) Fix gestion doublon functionality to work with chill bundles v2
* Do not send an email to creator twice when adding a comment to a notification
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) Fix gestion doublon functionality to work with chill bundles v2
### UX
* Uniformize badge-person in household banner (background, size)
## v2.5.3 - 2023-07-20
### Fixed
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
## v2.5.2 - 2023-07-15
### Fixed
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
## v2.5.1 - 2023-07-14
### Fixed
* [collate addresses] block collating addresses to another address reference where the address reference is already the best match
* [collate addresses] block collating addresses to another address reference where the address reference is already the best match
## v2.5.0 - 2023-07-14
### Feature

View File

@ -59,7 +59,8 @@
"vue-i18n": "^9.1.6",
"vue-multiselect": "3.0.0-alpha.2",
"vue-toast-notification": "^3.1.2",
"vuex": "^4.0.0"
"vuex": "^4.0.0",
"bootstrap-icons": "^1.11.3"
},
"browserslist": [
"Firefox ESR"

View File

@ -16,7 +16,7 @@ use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Symfony\Component\Security\Core\Security;
class ActivityStoredObjectVoter extends AbstractStoredObjectVoter
@ -24,7 +24,7 @@ class ActivityStoredObjectVoter extends AbstractStoredObjectVoter
public function __construct(
private readonly ActivityRepository $repository,
Security $security,
WorkflowStoredObjectPermissionHelper $workflowDocumentService,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
) {
parent::__construct($security, $workflowDocumentService);
}

View File

@ -42,8 +42,8 @@ class CustomFieldLongChoice extends AbstractCustomField
$translatableStringHelper = $this->translatableStringHelper;
$builder->add($customField->getSlug(), Select2ChoiceType::class, [
'choices' => $entries,
'choice_label' => static fn (Option $option) => $translatableStringHelper->localize($option->getText()),
'choice_value' => static fn (Option $key): ?int => null === $key ? null : $key->getId(),
'choice_label' => static fn (?Option $option) => $translatableStringHelper->localize($option->getText()),
'choice_value' => static fn (?Option $key): ?int => $key?->getId(),
'multiple' => false,
'expanded' => false,
'required' => $customField->isRequired(),

View File

@ -46,11 +46,8 @@ class CustomFieldsGroup
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
/**
* @var array
*/
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
private $name;
private array|string $name;
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
private array $options = [];
@ -181,7 +178,7 @@ class CustomFieldsGroup
*
* @return CustomFieldsGroup
*/
public function setName($name)
public function setName(array|string $name)
{
$this->name = $name;

View File

@ -15,7 +15,7 @@ use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoterInterface;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;
@ -34,7 +34,7 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
public function __construct(
private readonly Security $security,
private readonly ?WorkflowStoredObjectPermissionHelper $workflowDocumentService = null,
private readonly ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null,
) {}
public function supports(StoredObjectRoleEnum $attribute, StoredObject $subject): bool
@ -49,6 +49,11 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
// Retrieve the related accompanying course document
$entity = $this->getRepository()->findAssociatedEntityToStoredObject($subject);
if ($this->workflowDocumentService->isAllowedByWorkflow($entity)) {
// read and write permissions are granted by workflow
return true;
}
// Determine the attribute to pass to AccompanyingCourseDocumentVoter
$voterAttribute = $this->attributeToRole($attribute);

View File

@ -16,7 +16,7 @@ use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Symfony\Component\Security\Core\Security;
final class AccompanyingCourseDocumentStoredObjectVoter extends AbstractStoredObjectVoter
@ -24,7 +24,7 @@ final class AccompanyingCourseDocumentStoredObjectVoter extends AbstractStoredOb
public function __construct(
private readonly AccompanyingCourseDocumentRepository $repository,
Security $security,
WorkflowStoredObjectPermissionHelper $workflowDocumentService,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
) {
parent::__construct($security, $workflowDocumentService);
}

View File

@ -16,7 +16,7 @@ use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Repository\PersonDocumentRepository;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Symfony\Component\Security\Core\Security;
class PersonDocumentStoredObjectVoter extends AbstractStoredObjectVoter
@ -24,7 +24,7 @@ class PersonDocumentStoredObjectVoter extends AbstractStoredObjectVoter
public function __construct(
private readonly PersonDocumentRepository $repository,
Security $security,
WorkflowStoredObjectPermissionHelper $workflowDocumentService,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
) {
parent::__construct($security, $workflowDocumentService);
}

View File

@ -15,7 +15,7 @@ use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Chill\MainBundle\Entity\User;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@ -30,16 +30,16 @@ class AbstractStoredObjectVoterTest extends TestCase
{
private AssociatedEntityToStoredObjectInterface $repository;
private Security $security;
private WorkflowStoredObjectPermissionHelper $workflowDocumentService;
private WorkflowRelatedEntityPermissionHelper $workflowDocumentService;
protected function setUp(): void
{
$this->repository = $this->createMock(AssociatedEntityToStoredObjectInterface::class);
$this->security = $this->createMock(Security::class);
$this->workflowDocumentService = $this->createMock(WorkflowStoredObjectPermissionHelper::class);
$this->workflowDocumentService = $this->createMock(WorkflowRelatedEntityPermissionHelper::class);
}
private function buildStoredObjectVoter(bool $canBeAssociatedWithWorkflow, AssociatedEntityToStoredObjectInterface $repository, Security $security, ?WorkflowStoredObjectPermissionHelper $workflowDocumentService = null): AbstractStoredObjectVoter
private function buildStoredObjectVoter(bool $canBeAssociatedWithWorkflow, AssociatedEntityToStoredObjectInterface $repository, Security $security, ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null): AbstractStoredObjectVoter
{
// Anonymous class extending the abstract class
return new class ($canBeAssociatedWithWorkflow, $repository, $security, $workflowDocumentService) extends AbstractStoredObjectVoter {
@ -47,7 +47,7 @@ class AbstractStoredObjectVoterTest extends TestCase
private readonly bool $canBeAssociatedWithWorkflow,
private readonly AssociatedEntityToStoredObjectInterface $repository,
Security $security,
?WorkflowStoredObjectPermissionHelper $workflowDocumentService = null,
?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null,
) {
parent::__construct($security, $workflowDocumentService);
}
@ -99,6 +99,25 @@ class AbstractStoredObjectVoterTest extends TestCase
$this->workflowDocumentService->method('notBlockedByWorkflow')->willReturn($workflowAllowed);
}
public function testIsAllowedByWorkflow(): void
{
[$user, $token, $subject, $entity] = $this->setupMockObjects();
$workflowRelatedEntityPermissionHelper = $this->createMock(WorkflowRelatedEntityPermissionHelper::class);
$workflowRelatedEntityPermissionHelper->method('isAllowedByWorkflow')->withAnyParameters()->willReturn(true);
$associatedObjectRepository = $this->createMock(AssociatedEntityToStoredObjectInterface::class);
$associatedObjectRepository->method('findAssociatedEntityToStoredObject')->willReturn($entity);
$voter = $this->buildStoredObjectVoter(
true,
$associatedObjectRepository,
$this->createMock(Security::class),
$workflowRelatedEntityPermissionHelper
);
self::assertTrue($voter->voteOnAttribute(StoredObjectRoleEnum::EDIT, $subject, $token));
}
public function testSupportsOnAttribute(): void
{
[$user, $token, $subject, $entity] = $this->setupMockObjects();

View File

@ -14,7 +14,7 @@ namespace Chill\EventBundle\Security\Authorization;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Chill\EventBundle\Entity\Event;
use Chill\EventBundle\Repository\EventRepository;
use Chill\EventBundle\Security\EventVoter;
@ -25,7 +25,7 @@ class EventStoredObjectVoter extends AbstractStoredObjectVoter
public function __construct(
private readonly EventRepository $repository,
Security $security,
WorkflowStoredObjectPermissionHelper $workflowDocumentService,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
) {
parent::__construct($security, $workflowDocumentService);
}

View File

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

View File

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

View File

@ -5,8 +5,7 @@ module.exports = function(encore, chillEntries)
personal_situation_edit_file = __dirname + '/Resources/public/module/personal_situation/index.js',
cv_edit_file = __dirname + '/Resources/public/module/cv_edit/index.js',
immersion_edit_file = __dirname + '/Resources/public/module/immersion_edit/index.js',
images = __dirname + '/Resources/public/images/index.js',
sass_styles = __dirname + '/Resources/public/sass/index.js'
images = __dirname + '/Resources/public/images/index.js'
;
encore.addEntry('dispositifs_edit', dispositif_edit_file);
@ -15,6 +14,4 @@ module.exports = function(encore, chillEntries)
encore.addEntry('images', images);
encore.addEntry('cs_cv', cv_edit_file);
chillEntries.push(sass_styles);
};

View File

@ -0,0 +1,32 @@
<?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\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class GenderApiController extends ApiController
{
protected function customizeQuery(string $action, Request $request, $query): void
{
$query
->andWhere(
$query->expr()->eq('e.active', "'TRUE'")
);
}
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{
return $query->addOrderBy('e.order', 'ASC');
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class GenderController extends CRUDController
{
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$query->addOrderBy('e.order', 'ASC');
return parent::orderQuery($action, $query, $request, $paginator);
}
}

View File

@ -0,0 +1,63 @@
<?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\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class LoadGenders extends AbstractFixture implements OrderedFixtureInterface
{
private array $genders = [
[
'label' => ['en' => 'man', 'fr' => 'homme'],
'genderTranslation' => GenderEnum::MALE,
'icon' => GenderIconEnum::MALE,
],
[
'label' => ['en' => 'woman', 'fr' => 'femme'],
'genderTranslation' => GenderEnum::FEMALE,
'icon' => GenderIconEnum::FEMALE,
],
[
'label' => ['en' => 'neutral', 'fr' => 'neutre'],
'genderTranslation' => GenderEnum::NEUTRAL,
'icon' => GenderIconEnum::NEUTRAL,
],
];
public function getOrder()
{
return 100;
}
public function load(ObjectManager $manager)
{
echo "loading genders... \n";
foreach ($this->genders as $g) {
echo $g['label']['fr'].' ';
$new_g = new Gender();
$new_g->setGenderTranslation($g['genderTranslation']);
$new_g->setLabel($g['label']);
$new_g->setIcon($g['icon']);
$this->addReference('g_'.$g['genderTranslation']->value, $new_g);
$manager->persist($new_g);
}
$manager->flush();
}
}

View File

@ -17,6 +17,8 @@ use Chill\MainBundle\Controller\CivilityApiController;
use Chill\MainBundle\Controller\CivilityController;
use Chill\MainBundle\Controller\CountryApiController;
use Chill\MainBundle\Controller\CountryController;
use Chill\MainBundle\Controller\GenderApiController;
use Chill\MainBundle\Controller\GenderController;
use Chill\MainBundle\Controller\GeographicalUnitApiController;
use Chill\MainBundle\Controller\LanguageController;
use Chill\MainBundle\Controller\LocationController;
@ -54,6 +56,7 @@ use Chill\MainBundle\Doctrine\Type\PointType;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GeographicalUnitLayer;
use Chill\MainBundle\Entity\Language;
use Chill\MainBundle\Entity\Location;
@ -66,6 +69,7 @@ use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\CenterType;
use Chill\MainBundle\Form\CivilityType;
use Chill\MainBundle\Form\CountryType;
use Chill\MainBundle\Form\GenderType;
use Chill\MainBundle\Form\LanguageType;
use Chill\MainBundle\Form\LocationFormType;
use Chill\MainBundle\Form\LocationTypeType;
@ -511,6 +515,28 @@ class ChillMainExtension extends Extension implements
],
],
],
[
'class' => Gender::class,
'name' => 'main_gender',
'base_path' => '/admin/main/gender',
'base_role' => 'ROLE_ADMIN',
'form_class' => GenderType::class,
'controller' => GenderController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Gender/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Gender/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Gender/edit.html.twig',
],
],
],
[
'class' => Language::class,
'name' => 'main_language',
@ -814,6 +840,21 @@ class ChillMainExtension extends Extension implements
],
],
],
[
'class' => Gender::class,
'name' => 'gender',
'base_path' => '/api/1.0/main/gender',
'base_role' => 'ROLE_USER',
'controller' => GenderApiController::class,
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
],
],
],
],
[
'class' => GeographicalUnitLayer::class,
'controller' => GeographicalUnitApiController::class,

View File

@ -0,0 +1,104 @@
<?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\MainBundle\Entity;
use Chill\MainBundle\Repository\GenderRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
#[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['chill_main_gender' => Gender::class])]
#[ORM\Entity(repositoryClass: GenderRepository::class)]
#[ORM\Table(name: 'chill_main_gender')]
class Gender
{
#[Serializer\Groups(['read'])]
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
private ?int $id = null;
#[Serializer\Groups(['read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
private array $label = [];
#[Serializer\Groups(['read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
private bool $active = true;
#[Assert\NotNull(message: 'You must choose a gender translation')]
#[Serializer\Groups(['read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, enumType: GenderEnum::class)]
private GenderEnum $genderTranslation;
#[Serializer\Groups(['read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, enumType: GenderIconEnum::class)]
private GenderIconEnum $icon;
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::FLOAT, name: 'ordering', nullable: true, options: ['default' => '0.0'])]
private float $order = 0;
public function getId(): int
{
return $this->id;
}
public function getLabel(): array
{
return $this->label;
}
public function setLabel(array $label): void
{
$this->label = $label;
}
public function isActive(): bool
{
return $this->active;
}
public function setActive(bool $active): void
{
$this->active = $active;
}
public function getGenderTranslation(): GenderEnum
{
return $this->genderTranslation;
}
public function setGenderTranslation(GenderEnum $genderTranslation): void
{
$this->genderTranslation = $genderTranslation;
}
public function getIcon(): GenderIconEnum
{
return $this->icon;
}
public function setIcon(GenderIconEnum $icon): void
{
$this->icon = $icon;
}
public function getOrder(): float
{
return $this->order;
}
public function setOrder(float $order): void
{
$this->order = $order;
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
enum GenderEnum: string
{
case MALE = 'man';
case FEMALE = 'woman';
case NEUTRAL = 'neutral';
case UNKNOWN = 'unknown';
}

View File

@ -0,0 +1,22 @@
<?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\MainBundle\Entity;
enum GenderIconEnum: string
{
case MALE = 'bi bi-gender-male';
case FEMALE = 'bi bi-gender-female';
case NEUTRAL = 'bi bi-gender-neuter';
case AMBIGUOUS = 'bi bi-gender-ambiguous';
case TRANS = 'bi bi-gender-trans';
case UNKNOWN = 'bi bi-question';
}

View File

@ -0,0 +1,64 @@
<?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\MainBundle\Form;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EnumType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class GenderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('label', TranslatableStringFormType::class, [
'required' => true,
])
->add('icon', EnumType::class, [
'class' => GenderIconEnum::class,
'choices' => GenderIconEnum::cases(),
'expanded' => true,
'multiple' => false,
'mapped' => true,
'choice_label' => fn (GenderIconEnum $enum) => '<i class="'.strtolower($enum->value).'"></i>',
'choice_value' => fn (?GenderIconEnum $enum) => null !== $enum ? $enum->value : null,
'label' => 'gender.admin.Select Gender Icon',
'label_html' => true,
])
->add('genderTranslation', EnumType::class, [
'class' => GenderEnum::class,
'choice_label' => fn (GenderEnum $enum) => $enum->value,
'label' => 'gender.admin.Select Gender Translation',
])
->add('active', ChoiceType::class, [
'choices' => [
'Active' => true,
'Inactive' => false,
],
])
->add('order', NumberType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Gender::class,
]);
}
}

View File

@ -0,0 +1,47 @@
<?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\MainBundle\Repository;
use Chill\MainBundle\Entity\Gender;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Gender>
*/
class GenderRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Gender::class);
}
public function findByActiveOrdered(): array
{
return $this->createQueryBuilder('g')
->select('g')
->where('g.active = True')
->orderBy('g.order', 'ASC')
->getQuery()
->getResult();
}
public function findByGenderTranslation($gender): array
{
return $this->createQueryBuilder('g')
->select('g')
->where('g.genderTranslation = :gender')
->setParameter('gender', $gender)
->getQuery()
->getResult();
}
}

View File

@ -10,6 +10,7 @@ import Modal from 'bootstrap/js/dist/modal';
import Collapse from 'bootstrap/js/src/collapse';
import Carousel from 'bootstrap/js/src/carousel';
import Popover from 'bootstrap/js/src/popover';
import 'bootstrap-icons/font/bootstrap-icons.css';
//
// Carousel: ACHeaderSlider is a small slider used in banner of AccompanyingCourse Section
@ -59,4 +60,4 @@ const popoverList = triggerList.map(function (el) {
return new Popover(el, {
html: true,
});
});
});

View File

@ -0,0 +1,11 @@
<template>
<i :class="gender.icon"></i>
</template>
<script setup>
const props = defineProps({
gender: Object
})
</script>

View File

@ -38,7 +38,9 @@ const messages = {
person: "Usager",
birthday: {
man: "Né le",
woman: "Née le"
woman: "Née le",
neutral: "Né·e le",
unknown: "Né·e le",
},
deathdate: "Date de décès",
household_without_address: "Le ménage de l'usager est sans adresse",

View File

@ -0,0 +1,75 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% form_theme form _self %}
{% block _gender_icon_widget %}
{% for child in form %}
<div class="form-check">
<input
type="radio"
id="{{ child.vars.id }}"
name="{{ child.vars.full_name }}"
value="{{ child.vars.value }}"
{% if child.vars.checked %}checked="checked"{% endif %}
/>
<label for="{{ child.vars.id }}">{{ child.vars.label|raw }}</label>
</div>
{% endfor %}
{% endblock %}
{% block admin_content %}
{% set formId = crudMainFormId|default('crud_main_form') %}
{% block crud_content_header %}
<h1 class="mb-5">{{ ('crud.'~crud_name~'.title_edit')|trans }}</h1>
{% endblock crud_content_header %}
{% block crud_content_form %}
{{ form_start(form, { 'attr' : { 'id': formId } }) }}
{{ form_row(form.label) }}
{{ form_row(form.genderTranslation) }}
{{ form_row(form.icon) }}
{{ form_row(form.active) }}
{{ form_row(form.order) }}
{{ form_end(form) }}
{% block crud_content_after_form %}{% endblock %}
{% block crud_content_form_actions %}
<ul class="record_actions sticky-form-buttons">
{% block content_form_actions_back %}
<li class="cancel">
{# <a class="btn btn-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">#}
{# {{ 'Cancel'|trans }}#}
{# </a>#}
</li>
{% endblock %}
{% block content_form_actions_before %}{% endblock %}
{% block content_form_actions_delete %}
{% if chill_crud_action_exists(crud_name, 'delete') %}
{% if is_granted(chill_crud_config('role', crud_name, 'delete'), entity) %}
<li class="">
<a class="btn btn-small btn-delete" href="{{ chill_path_add_return_path('chill_crud_'~crud_name~'_delete', { 'id': entity.id }) }}"></a>
</li>
{% endif %}
{% endif %}
{% endblock content_form_actions_delete %}
{% block content_form_actions_save_and_close %}
<li class="">
<button type="submit" name="submit" value="save-and-close" class="btn btn-update" form="{{ formId }}">
{{ 'crud.edit.save_and_close'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_after %}{% endblock %}
</ul>
{% endblock %}
{% endblock %}
{% endblock admin_content %}

View File

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

View File

@ -0,0 +1,79 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% form_theme form _self %}
{% block _gender_icon_widget %}
{% for child in form %}
<div class="form-check">
<input
type="radio"
id="{{ child.vars.id }}"
name="{{ child.vars.full_name }}"
value="{{ child.vars.value }}"
{% if child.vars.checked %}checked="checked"{% endif %}
/>
<label for="{{ child.vars.id }}">{{ child.vars.label|raw }}</label>
</div>
{% endfor %}
{% endblock %}
{% block admin_content %}
{% set formId = crudMainFormId|default('crud_main_form') %}
{% block crud_content_header %}
<h1>{{ ('crud.' ~ crud_name ~ '.title_new')|trans({'%crud_name%' : crud_name }) }}</h1>
{% endblock crud_content_header %}
{% block crud_content_form %}
{{ form_start(form, { 'attr' : { 'id': formId } }) }}
{{ form_row(form.label) }}
{{ form_row(form.genderTranslation) }}
{{ form_row(form.icon) }}
{{ form_row(form.active) }}
{{ form_row(form.order) }}
{{ form_end(form) }}
{% block crud_content_after_form %}{% endblock %}
{% block crud_content_form_actions %}
<ul class="record_actions sticky-form-buttons">
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_save_and_close %}
<li class="">
<button type="submit" name="submit" value="save-and-close" class="btn btn-create" form="{{ formId }}">
{{ 'crud.new.save_and_close'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_save_and_show %}
<li class="">
<button type="submit" name="submit" value="save-and-show" class="btn btn-create" form="{{ formId }}">
{{ 'crud.new.save_and_show'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_save_and_new %}
<li class="">
<button type="submit" name="submit" value="save-and-new" class="btn btn-create" form="{{ formId }}">
{{ 'crud.new.save_and_new'|trans }}
</button>
</li>
{% endblock %}
</ul>
{% endblock %}
{{ form_end(form) }}
{% endblock %}
{% endblock admin_content %}

View File

@ -62,12 +62,12 @@ abstract class AbstractSearch implements SearchInterface
$recomposed .= ' '.$term.':';
$containsSpace = str_contains((string) $terms[$term], ' ');
if ($containsSpace) {
if ($containsSpace || is_numeric($terms[$term])) {
$recomposed .= '"';
}
$recomposed .= (false === mb_stristr(' ', (string) $terms[$term])) ? $terms[$term] : '('.$terms[$term].')';
if ($containsSpace) {
if ($containsSpace || is_numeric($terms[$term])) {
$recomposed .= '"';
}
}

View File

@ -35,7 +35,7 @@ interface ChillEntityRenderInterface
*
* @phpstan-pure
*/
public function renderBox($entity, array $options): string;
public function renderBox(mixed $entity, array $options): string;
/**
* Return the entity as a string.
@ -46,7 +46,7 @@ interface ChillEntityRenderInterface
*
* @phpstan-pure
*/
public function renderString($entity, array $options): string;
public function renderString(mixed $entity, array $options): string;
/**
* Return true if the class support this object for the given options.

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Templating\Entity;
use Chill\MainBundle\Entity\GenderIconEnum;
/**
* @implements ChillEntityRenderInterface<GenderIconEnum>
*/
final readonly class ChillGenderIconRender implements ChillEntityRenderInterface
{
public function renderBox($icon, array $options): string
{
return '<i class="'.htmlspecialchars($icon->value, ENT_QUOTES, 'UTF-8').'"></i>';
}
public function renderString($icon, array $options): string
{
return $icon->value;
}
public function supports($icon, array $options): bool
{
return $icon instanceof GenderIconEnum;
}
}

View File

@ -9,9 +9,9 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Tests\Service;
namespace Chill\MainBundle\Tests\Workflow\Helper;
use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
@ -36,7 +36,7 @@ use Symfony\Component\Workflow\WorkflowInterface;
*
* @coversNothing
*/
class WorkflowStoredObjectPermissionHelperTest extends TestCase
class WorkflowRelatedEntityPermissionHelperTest extends TestCase
{
use ProphecyTrait;
@ -53,6 +53,19 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase
self::assertEquals($expected, $helper->notBlockedByWorkflow($entityWorkflow), $message);
}
/**
* @dataProvider provideDataAllowedByWorkflow
*/
public function testAllowedByWorkflow(EntityWorkflow $entityWorkflow, User $user, bool $expected, string $message): void
{
// all entities must have this workflow name, so we are ok to set it here
$entityWorkflow->setWorkflowName('dummy');
$object = new \stdClass();
$helper = $this->buildHelper($object, $entityWorkflow, $user);
self::assertEquals($expected, $helper->isAllowedByWorkflow($entityWorkflow), $message);
}
public function testNoWorkflow(): void
{
$object = new \stdClass();
@ -60,7 +73,7 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase
self::assertTrue($helper->notBlockedByWorkflow($object), "the user is not blocked by the user, as there aren't any user inside");
}
private function buildHelper(object $relatedEntity, ?EntityWorkflow $entityWorkflow, User $user): WorkflowStoredObjectPermissionHelper
private function buildHelper(object $relatedEntity, ?EntityWorkflow $entityWorkflow, User $user): WorkflowRelatedEntityPermissionHelper
{
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
@ -72,7 +85,55 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase
$entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn([]);
}
return new WorkflowStoredObjectPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry());
return new WorkflowRelatedEntityPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry());
}
public static function provideDataAllowedByWorkflow(): iterable
{
$entityWorkflow = new EntityWorkflow();
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User());
yield [$entityWorkflow, new User(), false, 'not allowed because the user is not present as a dest user'];
$entityWorkflow = new EntityWorkflow();
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$dto->futureDestUsers[] = $user = new User();
$entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User());
yield [$entityWorkflow, $user, true, 'allowed because the user is a current user'];
$entityWorkflow = new EntityWorkflow();
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$dto->futureDestUsers[] = $user = new User();
$entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User());
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$dto->futureDestUsers[] = new User();
$entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User());
yield [$entityWorkflow, $user, true, 'allowed because the user was a previous user'];
$entityWorkflow = new EntityWorkflow();
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$dto->futureDestUsers[] = $user = new User();
$entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User());
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$entityWorkflow->setStep('final_positive', $dto, 'to_final_positive', new \DateTimeImmutable(), new User());
$entityWorkflow->getCurrentStep()->setIsFinal(true);
yield [$entityWorkflow, $user, false, 'not allowed because: user was a previous user, but it is finalized positive'];
$entityWorkflow = new EntityWorkflow();
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$dto->futureDestUsers[] = $user = new User();
$entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable());
$dto = new WorkflowTransitionContextDTO($entityWorkflow);
$entityWorkflow->setStep('final_negative', $dto, 'to_final_negative', new \DateTimeImmutable());
$entityWorkflow->getCurrentStep()->setIsFinal(true);
yield [$entityWorkflow, $user, true, 'allowed: user was a previous user, it is finalized, but finalized negative'];
}
public static function provideDataNotBlockByWorkflow(): iterable

View File

@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service;
namespace Chill\MainBundle\Workflow\Helper;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
@ -19,7 +19,7 @@ use Symfony\Component\Workflow\Registry;
/**
* Check if an object, associated with a workflow, is blocked, or not, by this workflow.
*/
class WorkflowStoredObjectPermissionHelper
class WorkflowRelatedEntityPermissionHelper
{
public function __construct(
private readonly Security $security,
@ -27,6 +27,38 @@ class WorkflowStoredObjectPermissionHelper
private readonly Registry $registry,
) {}
public function isAllowedByWorkflow(object $entity): bool
{
$entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity);
$currentUser = $this->security->getUser();
foreach ($entityWorkflows as $entityWorkflow) {
// if the user is finalized, we have to check if the workflow is finalPositive, or not
if ($entityWorkflow->isFinal()) {
$workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
$marking = $workflow->getMarkingStore()->getMarking($entityWorkflow);
foreach ($marking->getPlaces() as $place => $int) {
$placeMetadata = $workflow->getMetadataStore()->getPlaceMetadata($place);
if (true === ($placeMetadata['isFinalPositive'] ?? false)) {
// the workflow is final, and final positive, so we stop here.
return false;
}
}
}
}
foreach ($entityWorkflows as $entityWorkflow) {
// so, the workflow is running... We return true if the current user is involved
foreach ($entityWorkflow->getSteps() as $step) {
if ($step->getAllDestUser()->contains($currentUser)) {
return true;
}
}
}
return false;
}
/**
* Return true if the user is allowed to update the given object.
*

View File

@ -54,6 +54,8 @@ services:
Chill\MainBundle\Templating\Entity\NewsItemRender: ~
Chill\MainBundle\Templating\Entity\ChillGenderIconRender: ~
Chill\MainBundle\Templating\Entity\UserRender: ~
Chill\MainBundle\Templating\Entity\UserGroupRender: ~

View File

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20240926093955 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create gender table and default entities';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE SEQUENCE chill_main_gender_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_main_gender (id INT NOT NULL, label JSON NOT NULL, active BOOLEAN NOT NULL, genderTranslation VARCHAR(255) NOT NULL, icon VARCHAR(255) NOT NULL, ordering DOUBLE PRECISION DEFAULT \'0.0\', PRIMARY KEY(id))');
// Insert the four gender records into the chill_main_gender table
$this->addSql("
INSERT INTO chill_main_gender (id, label, active, genderTranslation, icon, ordering)
VALUES
(nextval('chill_main_gender_id_seq'),
'{\"fr\": \"homme\", \"nl\": \"man\"}',
true,
'man',
'bi bi-gender-male',
1.0
),
(nextval('chill_main_gender_id_seq'),
'{\"fr\": \"femme\", \"nl\": \"vrouw\"}',
true,
'woman',
'bi bi-gender-female',
1.1
),
(nextval('chill_main_gender_id_seq'),
'{\"fr\": \"neutre\", \"nl\": \"neutraal\"}',
true,
'neutral',
'bi bi-gender-neuter',
1.1
),
(nextval('chill_main_gender_id_seq'),
'{\"fr\": \"inconnu\", \"nl\": \"ongekend\"}',
true,
'unknown',
'bi bi-question',
1.2
)
");
}
public function down(Schema $schema): void
{
$this->addSql('DROP SEQUENCE chill_main_gender_id_seq CASCADE');
$this->addSql('DROP TABLE chill_main_gender');
}
}

View File

@ -43,6 +43,7 @@ lifecycleUpdate: Evenements de création et mise à jour
address_fields: Données liées à l'adresse
Datas: Données
No title: Aucun titre
icon: icône
user:
profile:
@ -474,6 +475,12 @@ crud:
title_delete: Supprimer une actualité
button_delete: Supprimer
confirm_message_delete: Êtes-vous sûr de vouloir supprimer l'actualité, "%as_string%" ?
main_gender:
index:
title: Liste des genres
add_new: Ajouter un genre
title_new: Nouveau genre
title_edit: Modifier un genre
No entities: Aucun élément
@ -781,4 +788,9 @@ news:
read_more: Lire la suite
show_details: Voir l'actualité
gender:
genderTranslation: traduction grammaticale
not defined: Non défini
pick gender: Choisir une genre

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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