diff --git a/exports_alias_conventions.csv b/exports_alias_conventions.csv index 1215479d8..59b4c0fee 100644 --- a/exports_alias_conventions.csv +++ b/exports_alias_conventions.csv @@ -11,10 +11,10 @@ AccompanyingPeriod::class,,,acp ,User::class,acp.user,acpuser AccompanyingPeriodWork::class,,,acpw ,AccompanyingPeriodWorkEvaluation::class,acpw.accompanyingPeriodWorkEvaluations,workeval -,Goal::class,acpw.goals,goal ,User::class,acpw.referrers,acpwuser -,Result::class,acpw.results,acpwresult ,SocialAction::class,acpw.socialAction,acpwsocialaction +,Goal::class,acpw.goals,goal +,Result::class,acpw.results,result AccompanyingPeriodParticipation::class,,,acppart ,Person::class,acppart.person,partperson AccompanyingPeriodWorkEvaluation::class,,,workeval @@ -23,17 +23,17 @@ Goal::class,,,goal ,Result::class,goal.results,goalresult Person::class,,,person ,Center::class,person.center,center -,HouseholdMember::class,partperson.householdParticipations,member +,HouseholdMember::class,partperson.householdParticipations,householdmember ,MaritalStatus::class,person.maritalStatus,personmarital +,VendeePerson::class,,vp +,VendeePersonMineur::class,,vpm ResidentialAddress::class,,,resaddr -,Person::class,resaddr.person,resaddrperson -,Center::class,resaddrperson.center,resaddrcenter ,ThirdParty::class,resaddr.hostThirdParty,tparty ThirdParty::class,,,tparty ,ThirdPartyCategory::class,tparty.categories,tpartycat -HouseholdMember::class,,,member -,Household::class,member.household,household -,Person::class,member.person,memberperson +HouseholdMember::class,,,householdmember +,Household::class,householdmember.household,household +,Person::class,householdmember.person,memberperson ,,memberperson.center,membercenter Household::class,,,household ,HouseholdComposition::class,household.compositions,composition @@ -58,11 +58,6 @@ Calendar::class,,,cal ,Location::class,cal.location,calloc ,User::class,cal.user,caluser VendeePerson::class,,,vp -,Person::class,vp.person,vpperson -,Center::class,vpperson.center,vpcenter ,SituationProfessionelle::class,vp.situationProfessionelle,vpprof ,StatutLogement::class,vp.statutLogement,vplog ,TempsDeTravail::class,vp.tempsDeTravail,vptt -VendeePersonMineur::class,,,vpm -,Person::class,vpm.person,vpmperson -,Center::class,vpmperson.center,vpmcenter diff --git a/exports_alias_conventions.md b/exports_alias_conventions.md index 85973eec1..f04c97ff2 100644 --- a/exports_alias_conventions.md +++ b/exports_alias_conventions.md @@ -5,72 +5,67 @@ Add condition with distinct alias on each export join clauses (Indicators + Filt These are alias conventions : -| Entity | Join | Attribute | Alias | -| :--- | :--- |:-------------------------------------------|:----------------------------------| -| AccompanyingPeriod::class | | | acp | -| | AccompanyingPeriodWork::class | acp.works | acpw | -| | AccompanyingPeriodParticipation::class | acp.participations | acppart | -| | Location::class | acp.administrativeLocation | acploc | -| | ClosingMotive::class | acp.closingMotive | acpmotive | -| | UserJob::class | acp.job | acpjob | -| | Origin::class | acp.origin | acporigin | -| | Scope::class | acp.scopes | acpscope | -| | SocialIssue::class | acp.socialIssues | acpsocialissue | -| | User::class | acp.user | acpuser | -| AccompanyingPeriodWork::class | | | acpw | -| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval | -| | Goal::class | acpw.goals | goal | -| | User::class | acpw.referrers | acpwuser | -| | Result::class | acpw.results | acpwresult | -| | SocialAction::class | acpw.socialAction | acpwsocialaction | -| AccompanyingPeriodParticipation::class | | | acppart | -| | Person::class | acppart.person | partperson | -| AccompanyingPeriodWorkEvaluation::class | | | workeval | -| | Evaluation::class | workeval.evaluation | eval | -| Goal::class | | | goal | -| | Result::class | goal.results | goalresult | -| Person::class | | | person | -| | Center::class | person.center | center | -| | HouseholdMember::class | partperson.householdParticipations | member | -| | MaritalStatus::class | person.maritalStatus | personmarital | -| ResidentialAddress::class | | | resaddr | -| | Person::class | resaddr.person | resaddrperson | -| | Center::class | resaddrperson.center | resaddrcenter | -| | ThirdParty::class | resaddr.hostThirdParty | tparty | -| ThirdParty::class | | | tparty | -| | ThirdPartyCategory::class | tparty.categories | tpartycat | -| HouseholdMember::class | | | member | -| | Household::class | member.household | household | -| | Person::class | member.person | memberperson | -| | | memberperson.center | membercenter | -| Household::class | | | household | -| | HouseholdComposition::class | household.compositions | composition | -| Activity::class | | | activity | -| | Person::class | activity.person | actperson | -| | AccompanyingPeriod::class | activity.accompanyingPeriod | actacp | -| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity | -| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity | -| | ActivityType::class | activity.activityType | acttype | -| | Location::class | activity.location | actloc | -| | SocialAction::class | activity.socialActions | actsocialaction | -| | SocialIssue::class | activity.socialIssues | actsocialssue | -| | ThirdParty::class | activity.thirdParties | acttparty | -| | User::class | activity.user | actuser | -| | User::class | activity.users | actusers | -| | ActivityReason::class | activity.reasons | actreasons | -| | Center::class | actperson.center | actcenter | -| ActivityReason::class | | | actreasons | -| | ActivityReasonCategory::class | actreason.category | actreasoncat | -| Calendar::class | | | cal | -| | CancelReason::class | cal.cancelReason | calcancel | -| | Location::class | cal.location | calloc | -| | User::class | cal.user | caluser | -| VendeePerson::class | | | vp | -| | Person::class | vp.person | vpperson | -| | Center::class | vpperson.center | vpcenter | -| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof | -| | StatutLogement::class | vp.statutLogement | vplog | -| | TempsDeTravail::class | vp.tempsDeTravail | vptt | -| VendeePersonMineur::class | | | vpm | -| | Person::class | vpm.person | vpmperson | -| | Center::class | vpmperson.center | vpmcenter | +| Entity | Join | Attribute | Alias | +|:----------------------------------------|:----------------------------------------|:-------------------------------------------|:----------------------------------| +| AccompanyingPeriod::class | | | acp | +| | AccompanyingPeriodWork::class | acp.works | acpw | +| | AccompanyingPeriodParticipation::class | acp.participations | acppart | +| | Location::class | acp.administrativeLocation | acploc | +| | ClosingMotive::class | acp.closingMotive | acpmotive | +| | UserJob::class | acp.job | acpjob | +| | Origin::class | acp.origin | acporigin | +| | Scope::class | acp.scopes | acpscope | +| | SocialIssue::class | acp.socialIssues | acpsocialissue | +| | User::class | acp.user | acpuser | +| AccompanyingPeriodWork::class | | | acpw | +| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval | +| | User::class | acpw.referrers | acpwuser | +| | SocialAction::class | acpw.socialAction | acpwsocialaction | +| | Goal::class | acpw.goals | goal | +| | Result::class | acpw.results | result | +| AccompanyingPeriodParticipation::class | | | acppart | +| | Person::class | acppart.person | partperson | +| AccompanyingPeriodWorkEvaluation::class | | | workeval | +| | Evaluation::class | workeval.evaluation | eval | +| Goal::class | | | goal | +| | Result::class | goal.results | goalresult | +| Person::class | | | person | +| | Center::class | person.center | center | +| | HouseholdMember::class | partperson.householdParticipations | householdmember | +| | MaritalStatus::class | person.maritalStatus | personmarital | +| | VendeePerson::class | | vp | +| | VendeePersonMineur::class | | vpm | +| ResidentialAddress::class | | | resaddr | +| | ThirdParty::class | resaddr.hostThirdParty | tparty | +| ThirdParty::class | | | tparty | +| | ThirdPartyCategory::class | tparty.categories | tpartycat | +| HouseholdMember::class | | | householdmember | +| | Household::class | householdmember.household | household | +| | Person::class | householdmember.person | memberperson | +| | | memberperson.center | membercenter | +| Household::class | | | household | +| | HouseholdComposition::class | household.compositions | composition | +| Activity::class | | | activity | +| | Person::class | activity.person | actperson | +| | AccompanyingPeriod::class | activity.accompanyingPeriod | actacp | +| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity | +| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity | +| | ActivityType::class | activity.activityType | acttype | +| | Location::class | activity.location | actloc | +| | SocialAction::class | activity.socialActions | actsocialaction | +| | SocialIssue::class | activity.socialIssues | actsocialssue | +| | ThirdParty::class | activity.thirdParties | acttparty | +| | User::class | activity.user | actuser | +| | User::class | activity.users | actusers | +| | ActivityReason::class | activity.reasons | actreasons | +| | Center::class | actperson.center | actcenter | +| ActivityReason::class | | | actreasons | +| | ActivityReasonCategory::class | actreason.category | actreasoncat | +| Calendar::class | | | cal | +| | CancelReason::class | cal.cancelReason | calcancel | +| | Location::class | cal.location | calloc | +| | User::class | cal.user | caluser | +| VendeePerson::class | | | vp | +| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof | +| | StatutLogement::class | vp.statutLogement | vplog | +| | TempsDeTravail::class | vp.tempsDeTravail | vptt | diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php index be20d2b9c..b2346b8fd 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php @@ -101,7 +101,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface return [ Declarations::ACTIVITY, Declarations::ACTIVITY_ACP, - //PersonDeclarations::ACP_TYPE, + PersonDeclarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php index 021c82d72..0195992fe 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php @@ -101,7 +101,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac return [ Declarations::ACTIVITY, Declarations::ACTIVITY_ACP, - //PersonDeclarations::ACP_TYPE, + PersonDeclarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php index 1f8b742dd..e4202c33a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php @@ -105,7 +105,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface return [ Declarations::ACTIVITY, Declarations::ACTIVITY_ACP, - //PersonDeclarations::ACP_TYPE, + PersonDeclarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php index 4d9b43034..2e87623ef 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php @@ -104,7 +104,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface return [ Declarations::ACTIVITY, Declarations::ACTIVITY_ACP, - //PersonDeclarations::ACP_TYPE, + PersonDeclarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php index 212b1384f..5bb6d542e 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php @@ -104,7 +104,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac return [ Declarations::ACTIVITY, Declarations::ACTIVITY_ACP, - //PersonDeclarations::ACP_TYPE, + PersonDeclarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php index 398fb14bb..9f4d15ec7 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php @@ -109,7 +109,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface return [ Declarations::ACTIVITY, Declarations::ACTIVITY_PERSON, - //PersonDeclarations::PERSON_TYPE, + PersonDeclarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php similarity index 85% rename from src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActivityTypeFilter.php rename to src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php index 8e50bc48c..7c0b202bd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php @@ -9,13 +9,14 @@ declare(strict_types=1); -namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; +namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\ActivityType; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -40,14 +41,8 @@ class ActivityTypeFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - // One2many between activity and accompanyingperiod is not reversed ! - // we replace indicator 'from' clause by 'act', and put 'acp' in a join - - $qb->resetDQLPart('from'); - $qb->from(Activity::class, 'activity'); - - if (!in_array('actacp', $qb->getAllAliases(), true)) { - $qb->join('activity.accompanyingPeriod', 'actacp'); + if (!in_array('activity', $qb->getAllAliases(), true)) { + $qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp'); } if (!in_array('acttype', $qb->getAllAliases(), true)) { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php index 8db312e35..871271aaa 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php @@ -197,7 +197,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt public function getTitle() { - return 'Filtered by person having an activity in a period'; + return 'Filter by person having an activity in a period'; } public function validateForm($data, ExecutionContextInterface $context) diff --git a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php index 789e634e5..48448d5e3 100644 --- a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php +++ b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php @@ -13,10 +13,10 @@ namespace Chill\ActivityBundle\Security\Authorization; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; +use Chill\MainBundle\Security\Authorization\VoterHelperInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; - -use function in_array; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { @@ -24,14 +24,14 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar public const STATS = 'CHILL_ACTIVITY_STATS'; - /** - * @var AuthorizationHelper - */ - protected $helper; + protected VoterHelperInterface $helper; - public function __construct(AuthorizationHelper $helper) + public function __construct(VoterHelperFactoryInterface $voterHelperFactory) { - $this->helper = $helper; + $this->helper = $voterHelperFactory + ->generate(self::class) + ->addCheckFor(Center::class, [self::STATS, self::LISTS]) + ->build(); } public function getRoles(): array @@ -49,30 +49,14 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar return $this->getAttributes(); } - protected function getSupportedClasses() + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { - return [Center::class]; - } - - protected function isGranted($attribute, $object, $user = null) - { - if (!$user instanceof \Symfony\Component\Security\Core\User\UserInterface) { - return false; - } - - return $this->helper->userHasAccess($user, $object, $attribute); + return $this->helper->voteOnAttribute($attribute, $subject, $token); } protected function supports($attribute, $subject) { - if ( - $subject instanceof Center - && in_array($attribute, $this->getAttributes(), true) - ) { - return true; - } - - return false; + return $this->helper->supports($attribute, $subject); } private function getAttributes() diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index c88046c5f..9abf33487 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -67,6 +67,11 @@ services: name: chill.export_filter alias: 'activity_person_having_ac_bw_date_filter' + chill.person.export.filter_activitytype: + class: Chill\ActivityBundle\Export\Filter\ACPFilters\ActivityTypeFilter + tags: + - { name: chill.export_filter, alias: accompanyingcourse_activitytype_filter } + chill.activity.export.locationtype_filter: class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter tags: diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 1893a64b3..ffd73b777 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -23,6 +23,7 @@ use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -142,10 +143,8 @@ class ExportController extends AbstractController /** * Render the list of available exports. - * - * @return \Symfony\Component\HttpFoundation\Response */ - public function indexAction(Request $request) + public function indexAction(): Response { $exportManager = $this->exportManager; diff --git a/src/Bundle/ChillMainBundle/Export/ExportManager.php b/src/Bundle/ChillMainBundle/Export/ExportManager.php index e2d099ba8..c1384a3b8 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportManager.php +++ b/src/Bundle/ChillMainBundle/Export/ExportManager.php @@ -14,6 +14,7 @@ namespace Chill\MainBundle\Export; use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; use Generator; @@ -42,52 +43,38 @@ class ExportManager /** * The collected aggregators, injected by DI. * - * @var AggregatorInterface[] + * @var array|AggregatorInterface[] */ - private $aggregators = []; + private array $aggregators = []; - /** - * @var AuthorizationChecker - */ - private $authorizationChecker; + private AuthorizationCheckerInterface $authorizationChecker; - /** - * @var AuthorizationHelper - */ - private $authorizationHelper; + private AuthorizationHelperInterface $authorizationHelper; - /** - * @var EntityManagerInterface - */ - private $em; + private EntityManagerInterface $em; /** * Collected Exports, injected by DI. * - * @var ExportInterface[] + * @var array|ExportInterface[] */ - private $exports = []; + private array $exports = []; /** * The collected filters, injected by DI. * - * @var FilterInterface[] + * @var array|FilterInterface[] */ - private $filters = []; + private array $filters = []; /** * Collected Formatters, injected by DI. * - * @var FormatterInterface[] + * @var array|FormatterInterface[] */ - private $formatters = []; + private array $formatters = []; - /** - * a logger. - * - * @var LoggerInterface - */ - private $logger; + private LoggerInterface $logger; /** * @var \Symfony\Component\Security\Core\User\UserInterface @@ -98,7 +85,7 @@ class ExportManager LoggerInterface $logger, EntityManagerInterface $em, AuthorizationCheckerInterface $authorizationChecker, - AuthorizationHelper $authorizationHelper, + AuthorizationHelperInterface $authorizationHelper, TokenStorageInterface $tokenStorage ) { $this->logger = $logger; @@ -547,19 +534,16 @@ class ExportManager . 'an ExportInterface.'); } - if (null === $centers) { - $centers = $this->authorizationHelper->getReachableCenters( + if (null === $centers || [] === $centers) { + // we want to try if at least one center is reachable + return [] !== $this->authorizationHelper->getReachableCenters( $this->user, $role ); } - if (count($centers) === 0) { - return false; - } - foreach ($centers as $center) { - if ($this->authorizationChecker->isGranted($role, $center) === false) { + if (false === $this->authorizationChecker->isGranted($role, $center)) { //debugging $this->logger->debug('user has no access to element', [ 'method' => __METHOD__, @@ -568,10 +552,6 @@ class ExportManager 'role' => $role, ]); - ///// Bypasse les autorisations qui empêche d'afficher les nouveaux exports - return true; - ///// TODO supprimer le return true - return false; } } diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php index 86c304508..6d6a685b7 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php @@ -230,7 +230,8 @@ class SpreadSheetFormatter implements FormatterInterface $worksheet->fromArray( $sortedResults, null, - 'A' . $line + 'A' . $line, + true ); return $line + count($sortedResults) + 1; diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php index c73402dd3..07776cb71 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php @@ -15,6 +15,7 @@ use Chill\MainBundle\Center\GroupingCenterInterface; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Doctrine\ORM\EntityRepository; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; @@ -24,6 +25,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\User\UserInterface; use function array_intersect; use function array_key_exists; use function array_merge; @@ -38,30 +40,24 @@ class PickCenterType extends AbstractType { public const CENTERS_IDENTIFIERS = 'c'; - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; + protected AuthorizationHelperInterface $authorizationHelper; + + protected ExportManager $exportManager; /** - * @var ExportManager + * @var array|GroupingCenterInterface[] */ - protected $exportManager; - - /** - * @var GroupingCenterInterface[] - */ - protected $groupingCenters = []; + protected array $groupingCenters = []; /** * @var \Symfony\Component\Security\Core\User\UserInterface */ - protected $user; + protected UserInterface $user; public function __construct( TokenStorageInterface $tokenStorage, ExportManager $exportManager, - AuthorizationHelper $authorizationHelper + AuthorizationHelperInterface $authorizationHelper ) { $this->exportManager = $exportManager; $this->user = $tokenStorage->getToken()->getUser(); @@ -78,22 +74,12 @@ class PickCenterType extends AbstractType $export = $this->exportManager->getExport($options['export_alias']); $centers = $this->authorizationHelper->getReachableCenters( $this->user, - (string) $export->requiredRole() + $export->requiredRole() ); $builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, [ 'class' => Center::class, - 'query_builder' => static function (EntityRepository $er) use ($centers) { - $qb = $er->createQueryBuilder('c'); - $ids = array_map( - static function (Center $el) { - return $el->getId(); - }, - $centers - ); - - return $qb->where($qb->expr()->in('c.id', $ids)); - }, + 'choices' => $centers, 'multiple' => true, 'expanded' => true, 'choice_label' => static function (Center $c) { diff --git a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php index 554f39880..d8e54d1c4 100644 --- a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php @@ -16,7 +16,7 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\Persistence\ObjectRepository; -final class CenterRepository implements ObjectRepository +final class CenterRepository implements CenterRepositoryInterface { private EntityRepository $repository; @@ -30,6 +30,11 @@ final class CenterRepository implements ObjectRepository return $this->repository->find($id, $lockMode, $lockVersion); } + public function findActive(): array + { + return $this->findAll(); + } + /** * @return Center[] */ diff --git a/src/Bundle/ChillMainBundle/Repository/CenterRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/CenterRepositoryInterface.php new file mode 100644 index 000000000..27ba64caf --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/CenterRepositoryInterface.php @@ -0,0 +1,18 @@ + + + + + {{ export_group|trans }} + diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig index fa568d857..84eb85100 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig @@ -36,10 +36,7 @@ window.addEventListener("DOMContentLoaded", function(e) { {% block content %}
-
- - {{ export_group|trans }} -
+ {{ include('@ChillMain/Export/_breadcrumb.html.twig') }}

{{ export.title|trans }}

{{ "Download export"|trans }}

diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig index 8aac6c253..ad49d9aa6 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig @@ -22,15 +22,15 @@ {% block js %} {{ encore_entry_script_tags('page_export') }} + {% if export_alias == 'count_social_work_actions' %} + {{ encore_entry_script_tags('vue_export_action_goal_result') }} + {% endif %} {% endblock js %} {% block content %}
-
- - {{ export_group|trans }} -
+ {{ include('@ChillMain/Export/_breadcrumb.html.twig') }}

{{ export.title|trans }}

diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig index 4a2d9ab9e..8874744c4 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig @@ -22,11 +22,8 @@ {% block content %}
- -
- - {{ export_group|trans }} -
+ + {{ include('@ChillMain/Export/_breadcrumb.html.twig') }}

{{ export.title|trans }}

diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/new_formatter_step.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/new_formatter_step.html.twig index 443816611..8ecaf6dd8 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/new_formatter_step.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/new_formatter_step.html.twig @@ -23,10 +23,7 @@ {% block content %}
-
- - {{ export_group|trans }} -
+ {{ include('@ChillMain/Export/_breadcrumb.html.twig') }}

{{ export.title|trans }}

@@ -36,19 +33,21 @@

{{ 'Formatter'| trans }}

-
{% if form.children.formatter.children|length == 0 %}

{{ "No options availables. Your report is fully configured."|trans }}

{{ form_widget(form.children.formatter) }} {% else %} - {# we always have to render children, to mark as rendered #} - {% for input in form.children.formatter.children %} - {{ form_row(input) }} - {% endfor %} +
+ {# we always have to render children, to mark as rendered #} + {% for input in form.children.formatter.children %} +
+ {{ form_row(input) }} +
+ {% endfor %} +
{% endif %} -
diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php index ec1a0479d..b98564adf 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php @@ -19,24 +19,23 @@ class ChillExportVoter extends Voter { public const EXPORT = 'chill_export'; - protected AuthorizationHelperInterface $authorizationHelper; + private VoterHelperInterface $helper; - public function __construct(AuthorizationHelperInterface $authorizationHelper) + public function __construct(VoterHelperFactoryInterface $voterHelperFactory) { - $this->authorizationHelper = $authorizationHelper; + $this->helper = $voterHelperFactory + ->generate(self::class) + ->addCheckFor(null, [self::EXPORT]) + ->build(); } protected function supports($attribute, $subject): bool { - return self::EXPORT === $attribute; + return $this->helper->supports($attribute, $subject); } protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { - if (!$token->getUser() instanceof User) { - return false; - } - - return [] !== $this->authorizationHelper->getReachableCenters($token->getUser(), $attribute); + return $this->helper->voteOnAttribute($attribute, $subject, $token); } } diff --git a/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php b/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php index a25624719..ae274ca1d 100644 --- a/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php +++ b/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php @@ -18,6 +18,7 @@ namespace Chill\MainBundle\Test; * and use tearDownTrait after usage. * * @codeCoverageIgnore + * @deprecated use @class{Prophecy\PhpUnit\ProphecyTrait} instead */ trait ProphecyTrait { diff --git a/src/Bundle/ChillMainBundle/config/services.yaml b/src/Bundle/ChillMainBundle/config/services.yaml index 456f05936..10164932f 100644 --- a/src/Bundle/ChillMainBundle/config/services.yaml +++ b/src/Bundle/ChillMainBundle/config/services.yaml @@ -89,12 +89,8 @@ services: - { name: validator.constraint_validator, alias: 'role_scope_scope_presence' } Chill\MainBundle\Export\ExportManager: - arguments: - - "@logger" - - "@doctrine.orm.entity_manager" - - "@security.authorization_checker" - - "@chill.main.security.authorization.helper" - - "@security.token_storage" + autoconfigure: true + autowire: true Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface: '@Chill\MainBundle\Security\Resolver\CenterResolverDispatcher' diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml index 754d3b042..0d0739e23 100644 --- a/src/Bundle/ChillMainBundle/config/services/form.yaml +++ b/src/Bundle/ChillMainBundle/config/services/form.yaml @@ -81,12 +81,8 @@ services: chill.main.form.pick_centers_type: class: Chill\MainBundle\Form\Type\Export\PickCenterType - arguments: - - "@security.token_storage" - - '@Chill\MainBundle\Export\ExportManager' - - "@chill.main.security.authorization.helper" - tags: - - { name: form.type } + autowire: true + autoconfigure: true chill.main.form.formatter_type: class: Chill\MainBundle\Form\Type\Export\FormatterType diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php index 4c784e08d..925160a2d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php @@ -45,7 +45,7 @@ final class OriginAggregator implements AggregatorInterface $qb->join('acp.origin', 'acporigin'); } - $qb->addSelect('o.id AS origin_aggregator'); + $qb->addSelect('acporigin.id AS origin_aggregator'); $groupby = $qb->getDQLPart('groupBy'); diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php index c0b52053d..89c0bb8f5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php @@ -16,8 +16,10 @@ use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Household\HouseholdMember; +use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\PositionRepository; use DateTime; +use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; @@ -31,8 +33,11 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl private TranslatorInterface $translator; - public function __construct(TranslatorInterface $translator, TranslatableStringHelper $translatableStringHelper, PositionRepository $positionRepository) - { + public function __construct( + TranslatorInterface $translator, + TranslatableStringHelper $translatableStringHelper, + PositionRepository $positionRepository + ) { $this->translator = $translator; $this->positionRepository = $positionRepository; $this->translatableStringHelper = $translatableStringHelper; @@ -45,28 +50,25 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl public function alterQuery(QueryBuilder $qb, $data) { - $qb->resetDQLPart('from'); - $qb->from(HouseholdMember::class, 'member'); - - if (!in_array('memberperson', $qb->getAllAliases(), true)) { - $qb->join('member.person', 'memberperson'); + if (!in_array('householdmember', $qb->getAllAliases(), true)) { + $qb->join(HouseholdMember::class, 'householdmember', Expr\Join::WITH, 'householdmember.person = person'); } - if (!in_array('membercenter', $qb->getAllAliases(), true)) { - $qb->join('memberperson.center', 'membercenter'); + if (!in_array('center', $qb->getAllAliases(), true)) { + $qb->join('person.center', 'center'); } $qb->andWhere($qb->expr()->andX( - $qb->expr()->lte('member.startDate', ':date'), + $qb->expr()->lte('householdmember.startDate', ':date'), $qb->expr()->orX( - $qb->expr()->isNull('member.endDate'), - $qb->expr()->gte('member.endDate', ':date') + $qb->expr()->isNull('householdmember.endDate'), + $qb->expr()->gte('householdmember.endDate', ':date') ) )); $qb->setParameter('date', $data['date_position']); - $qb->addSelect('IDENTITY(member.position) AS household_position_aggregator'); + $qb->addSelect('IDENTITY(householdmember.position) AS household_position_aggregator'); $groupBy = $qb->getDQLPart('groupBy'); @@ -79,7 +81,7 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl public function applyOn() { - return 'person'; + return Declarations::PERSON_TYPE; } public function buildForm(FormBuilderInterface $builder) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php index b76db495d..fb64b3e01 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php @@ -29,6 +29,7 @@ final class ActionTypeAggregator implements AggregatorInterface SocialActionRender $actionRender ) { $this->socialActionRepository = $socialActionRepository; + $this->actionRender = $actionRender; } public function addRole(): ?string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php index 4310dcac2..bc534c678 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php @@ -41,7 +41,7 @@ final class GoalAggregator implements AggregatorInterface $qb->join('acpw.goals', 'goal'); } - $qb->addSelect('goal.id as goal_aggregator'); + $qb->addSelect('IDENTITY(goal.goal) as goal_aggregator'); $groupBy = $qb->getDQLPart('groupBy'); @@ -52,7 +52,7 @@ final class GoalAggregator implements AggregatorInterface } } - public function applyOn() + public function applyOn(): string { return Declarations::SOCIAL_WORK_ACTION_TYPE; } @@ -70,17 +70,19 @@ final class GoalAggregator implements AggregatorInterface } $g = $this->goalRepository->find($value); - - return $this->translatableStringHelper->localize($g->getTitle()); + + return $this->translatableStringHelper->localize( + $g->getTitle() + ); }; } - public function getQueryKeys($data) + public function getQueryKeys($data): array { return ['goal_aggregator']; } - public function getTitle() + public function getTitle(): string { return 'Group social work actions by goal'; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php new file mode 100644 index 000000000..aeced53d7 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php @@ -0,0 +1,138 @@ +resultRepository = $resultRepository; + $this->goalRepository = $goalRepository; + $this->translatableStringHelper = $translatableStringHelper; + } + + + /** + * @inheritDoc + */ + public function getLabels($key, array $values, $data) + { + return function ($value) use ($key): string { + switch ($key) { + case 'goal_aggregator': + + if ('_header' === $value) { + return 'Goal Type'; + } + + $g = $this->goalRepository->find($value); + + return $this->translatableStringHelper->localize( + $g->getTitle() + ); + + case 'result_aggregator': + + if ('_header' === $value) { + return 'Result Type'; + } + + $r = $this->resultRepository->find($value); + + return $this->translatableStringHelper->localize( + $r->getTitle() + ); + + default: + throw new \LogicException(); + } + }; + } + + /** + * @inheritDoc + */ + public function getQueryKeys($data): array + { + return [ + 'goal_aggregator', + 'result_aggregator' + ]; + } + + /** + * @inheritDoc + */ + public function buildForm(FormBuilderInterface $builder) + { + // no form + } + + /** + * @inheritDoc + */ + public function getTitle(): string + { + return 'Group social work actions by goal and result'; + } + + /** + * @inheritDoc + */ + public function addRole(): ?string + { + return null; + } + + /** + * @inheritDoc + */ + public function alterQuery(QueryBuilder $qb, $data) + { + if (!in_array('goal', $qb->getAllAliases(), true)) { + $qb->join('acpw.goals', 'goal'); + } + + if (!in_array('goalresult', $qb->getAllAliases(), true)) { + $qb->join('goal.results', 'goalresult'); + } + + $qb->addSelect('IDENTITY(goal.goal) as goal_aggregator'); + $qb->addSelect('goalresult.id as result_aggregator'); + + $groupBy = $qb->getDQLPart('groupBy'); + + if (!empty($groupBy)) { + $qb->addGroupBy('goal_aggregator'); + } else { + $qb->groupBy('goal_aggregator'); + } + + $qb->addGroupBy('result_aggregator'); + } + + /** + * @inheritDoc + */ + public function applyOn(): string + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php index 47391ed69..8f7ac0624 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php @@ -37,19 +37,11 @@ final class ResultAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - if (!in_array('acpwresult', $qb->getAllAliases(), true)) { - $qb->join('acpw.results', 'acpwresult'); + if (!in_array('result', $qb->getAllAliases(), true)) { + $qb->join('acpw.results', 'result'); } - if (!in_array('goal', $qb->getAllAliases(), true)) { - $qb->join('acpw.goals', 'goal'); - } - - if (!in_array('goalresult', $qb->getAllAliases(), true)) { - $qb->join('goal.results', 'goalresult'); - } - - $qb->addSelect('acpwresult.id, IDENTITY(goal.results) as result_aggregator'); + $qb->addSelect('result.id as result_aggregator'); $groupBy = $qb->getDQLPart('groupBy'); @@ -60,7 +52,7 @@ final class ResultAggregator implements AggregatorInterface } } - public function applyOn() + public function applyOn(): string { return Declarations::SOCIAL_WORK_ACTION_TYPE; } @@ -77,18 +69,20 @@ final class ResultAggregator implements AggregatorInterface return 'Result Type'; } - $g = $this->resultRepository->find($value); + $r = $this->resultRepository->find($value); - return $this->translatableStringHelper->localize($g->getTitle()); + return $this->translatableStringHelper->localize( + $r->getTitle() + ); }; } - public function getQueryKeys($data) + public function getQueryKeys($data): array { return ['result_aggregator']; } - public function getTitle() + public function getTitle(): string { return 'Group social work actions by result'; } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php index 5b2ab65eb..7178a54c8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php @@ -112,8 +112,8 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface { return [ Declarations::EVAL_TYPE, - //Declarations::ACP_TYPE, - //Declarations::SOCIAL_WORK_ACTION_TYPE, + Declarations::SOCIAL_WORK_ACTION_TYPE, + Declarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php index f60f66310..18ddbaea1 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php @@ -121,7 +121,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface { return [ Declarations::HOUSEHOLD_TYPE, - //Declarations::ACP_TYPE + Declarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php index 800023fc5..51d85c479 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php @@ -111,8 +111,8 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor public function supportsModifiers(): array { return [ - Declarations::ACP_TYPE, Declarations::PERSON_TYPE, + Declarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php b/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php index 17de7e5ae..2ad6e9f1b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php @@ -110,6 +110,7 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface { return [ Declarations::SOCIAL_WORK_ACTION_TYPE, + Declarations::ACP_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php index 00d05117b..a161df44f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php @@ -108,6 +108,6 @@ class DeadOrAliveFilter implements FilterInterface public function getTitle() { - return 'Filtered by person\'s that are alive or have deceased at a certain date'; + return "Filter by person's that are alive or have deceased at a certain date"; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php index ed69d6c3d..c96fd680f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php @@ -39,15 +39,12 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->resetDQLPart('from'); - $qb->from(ResidentialAddress::class, 'resaddr'); - - if (!in_array('resaddrperson', $qb->getAllAliases(), true)) { - $qb->join('resaddr.person', 'resaddrperson'); + if (!in_array('resaddr', $qb->getAllAliases(), true)) { + $qb->join(ResidentialAddress::class, 'resaddr', Expr\Join::WITH, 'resaddr.person = person'); } - if (!in_array('resaddrcenter', $qb->getAllAliases(), true)) { - $qb->join('resaddrperson.center', 'resaddrcenter'); + if (!in_array('center', $qb->getAllAliases(), true)) { + $qb->join('person.center', 'center'); } if (!in_array('tparty', $qb->getAllAliases(), true)) { @@ -109,6 +106,6 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface public function getTitle() { - return 'Filtered by person\'s who have a residential address located at a thirdparty of type'; + return "Filter by person's who have a residential address located at a thirdparty of type"; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php index 96b867e57..482312143 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php @@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Entity\Person\ResidentialAddress; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; @@ -26,15 +27,12 @@ class ResidentialAddressAtUserFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->resetDQLPart('from'); - $qb->from(ResidentialAddress::class, 'resaddr'); - - if (!in_array('resaddrperson', $qb->getAllAliases(), true)) { - $qb->join('resaddr.person', 'resaddrperson'); + if (!in_array('resaddr', $qb->getAllAliases(), true)) { + $qb->join(ResidentialAddress::class, 'resaddr', Expr\Join::WITH, 'resaddr.person = person'); } - if (!in_array('resaddrcenter', $qb->getAllAliases(), true)) { - $qb->join('resaddrperson.center', 'resaddrcenter'); + if (!in_array('center', $qb->getAllAliases(), true)) { + $qb->join('person.center', 'center'); } $where = $qb->getDQLPart('where'); @@ -61,11 +59,11 @@ class ResidentialAddressAtUserFilter implements FilterInterface public function describeAction($data, $format = 'string') { - return ['Filtered by person\'s who have a residential address located at another user']; + return ["Filtered by person's who have a residential address located at another user"]; } public function getTitle() { - return 'Filtered by person\'s who have a residential address located at another user'; + return "Filter by person's who have a residential address located at another user"; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php index fc41459ca..0cf7f979d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php @@ -13,35 +13,119 @@ namespace Chill\PersonBundle\Export\Filter\SocialWorkFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; -use Chill\PersonBundle\Entity\SocialWork\Goal; use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\PersonBundle\Entity\SocialWork\Goal; +use Chill\PersonBundle\Entity\SocialWork\Result; use Chill\PersonBundle\Export\Declarations; -use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository; -use Chill\PersonBundle\Templating\Entity\SocialActionRender; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; -use Symfony\Component\Form\FormInterface; +use Chill\PersonBundle\Templating\Entity\SocialActionRender; class SocialWorkTypeFilter implements FilterInterface { private SocialActionRender $socialActionRender; - private SocialActionRepository $socialActionRepository; - private TranslatableStringHelper $translatableStringHelper; - public function __construct( + private EntityManagerInterface $em; + + public function __construct + ( SocialActionRender $socialActionRender, TranslatableStringHelper $translatableStringHelper, - SocialActionRepository $socialActionRepository - ) { + EntityManagerInterface $em + ) + { $this->socialActionRender = $socialActionRender; $this->translatableStringHelper = $translatableStringHelper; - $this->socialActionRepository = $socialActionRepository; + $this->em = $em; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('actionType', HiddenType::class) + ->get('actionType') + ->addModelTransformer( + $this->iterableToIdTransformer(SocialAction::class) + ) + ; + $builder + ->add('goal', HiddenType::class) + ->get('goal') + ->addModelTransformer( + $this->iterableToIdTransformer(Goal::class) + ) + ; + $builder + ->add('result', HiddenType::class) + ->get('result') + ->addModelTransformer( + $this->iterableToIdTransformer(Result::class) + ) + ; + } + + private function iterableToIdTransformer(string $entity): CallbackTransformer + { + return new CallbackTransformer( + static function (?iterable $asIterable): string { + if (null === $asIterable) { return ''; } + $ids = []; + foreach ($asIterable as $value) { + $ids[] = $value->getId(); + } + return implode(',', $ids); + }, + function (?string $asString) use ($entity): array { + if (null === $asString) { return []; } + return array_map( + fn (string $id) + => $this->em + ->getRepository($entity) + ->findOneBy(['id' => (int) $id]), + explode(',', $asString) + ); + } + ); + } + + public function getTitle(): string + { + return 'Filter by type of action, goals and results'; + } + + public function describeAction($data, $format = 'string'): array + { + $actionTypes = []; + $goals = []; + $results = []; + + foreach ($data['actionType'] as $at) { + $actionTypes[] = $this->translatableStringHelper->localize( + $at->getTitle() + ); + } + + foreach ($data['goal'] as $g) { + $goals[] = $this->translatableStringHelper->localize( + $g->getTitle() + ); + } + + foreach ($data['result'] as $r) { + $results[] = $this->translatableStringHelper->localize( + $r->getTitle() + ); + } + + return ['Filtered actions by type, goals and results: %selected%', [ + '%selected%' => implode(', ', array_merge($actionTypes, $goals, $results)) + ]]; } public function addRole(): ?string @@ -52,93 +136,48 @@ class SocialWorkTypeFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->in('r', ':referrers'); - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); + if (count($data['actionType']) > 0) { + $clause = $qb->expr()->in('acpw.socialAction', ':actionType'); + + if ($where instanceof Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->setParameter('actionType', $data['actionType']); + } + + if (count($data['goal']) > 0) { + if (!in_array('goal', $qb->getAllAliases(), true)) { + $qb->join('acpw.goals', 'goal'); + } + + $where->add( + $qb->expr()->in('goal.id', ':goals') + ); + + $qb->setParameter('goals', $data['goal']); + } + + if (count($data['result']) > 0) { + if (!in_array('result', $qb->getAllAliases(), true)) { + $qb->join('acpw.results', 'result'); + } + + $where->add( + $qb->expr()->in('result.id', ':results') + ); + + $qb->setParameter('results', $data['result']); } $qb->add('where', $where); - $qb->setParameter('referrers', $data['referrers']); } public function applyOn(): string { return Declarations::SOCIAL_WORK_ACTION_TYPE; } - - public function buildForm(FormBuilderInterface $builder) - { - $socialActions = $this->socialActionRepository->findAll(); - - $builder->add('actionType', ChoiceType::class, [ - 'choices' => $socialActions, - 'choice_label' => function (SocialAction $sa) { - return $this->socialActionRender->renderString($sa, []); - }, - 'multiple' => true, - 'expanded' => true, - ]); - - /* - $refreshGoals = function (FormInterface $form, SocialAction $actionType = null) { - - $goals = null === $actionType ? [] : $actionType->getGoals(); - - $form->add('goal', ChoiceType::class, [ - 'placeholder' => '', - 'choices' => $goals, - 'choice_label' => function (Goal $g) { - return $this->translatableStringHelper->localize($g->getTitle()); - }, - ]); - }; - - $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($refreshGoals) { - $data = $event->getData(); - dump($data); - - $refreshGoals($event->getForm(), $data); - }); - - $builder->get('actionType')->addEventListener( - FormEvents::POST_SUBMIT, - function (FormEvent $event) use ($refreshGoals) { - $actionType = $event->getForm()->getData(); - dump($actionType); - $refreshGoals($event->getForm()->getParent(), $actionType); - } - ); - */ - } - - public function describeAction($data, $format = 'string'): array - { - $actionTypes = []; - $objectives = []; - $results = []; - - foreach ($data['actionType'] as $at) { - $actionTypes[] = $at->getTitle(); - } - - foreach ($data['objectives'] as $o) { - $objectives[] = $o->getTitle(); - } - - foreach ($data['results'] as $r) { - $results[] = $r->getTitle(); - } - - return ['Filtered by referrers: only %actionTypes%', [ - '%actionTypes%' => implode(', ou ', $actionTypes), - ]]; - } - - public function getTitle(): string - { - return 'Filter by type of action, objectives and results'; - } } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/App.vue new file mode 100644 index 000000000..d4d1be1b6 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/App.vue @@ -0,0 +1,381 @@ + + + + + \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/api.js new file mode 100644 index 000000000..afcece4f4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/api.js @@ -0,0 +1,41 @@ +import { fetchResults } from 'ChillMainAssets/lib/api/apiMethods'; + +const getSocialActions = () => fetchResults( + '/api/1.0/person/social/social-action.json', { + item_per_page: 200 + } +); + +const getGoalByAction = (id) => { + let url = `/api/1.0/person/social-work/goal/by-social-action/${id}.json`; + return fetch(url) + .then(response => { + if (response.ok) { return response.json(); } + throw Error('Error with request resource response'); + }); +}; + +const getResultByAction = (id) => { + let url = `/api/1.0/person/social-work/result/by-social-action/${id}.json`; + return fetch(url) + .then(response => { + if (response.ok) { return response.json(); } + throw Error('Error with request resource response'); + }); +}; + +const getResultByGoal = (id) => { + let url = `/api/1.0/person/social-work/result/by-goal/${id}.json`; + return fetch(url) + .then(response => { + if (response.ok) { return response.json(); } + throw Error('Error with request resource response'); + }); +}; + +export { + getSocialActions, + getGoalByAction, + getResultByAction, + getResultByGoal, +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/index.js new file mode 100644 index 000000000..d838fb0be --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/ExportFormActionGoalResult/index.js @@ -0,0 +1,13 @@ +import { createApp } from "vue"; +import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'; +import App from './App.vue'; + +const i18n = _createI18n({}); + +const app = createApp({ + template: ``, +}) +.use(i18n) +.component('app', App) +.mount('#export_export') +; \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php index 8da2036d7..b9c9fb219 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Security\Authorization; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; @@ -119,6 +120,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH ->addCheckFor(null, [self::CREATE, self::REASSIGN_BULK]) ->addCheckFor(AccompanyingPeriod::class, [self::TOGGLE_CONFIDENTIAL, ...self::ALL]) ->addCheckFor(Person::class, [self::SEE, self::CREATE]) + ->addCheckFor(Center::class, [self::STATS]) ->build(); } diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php index ca956db63..0288c9e61 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php @@ -11,6 +11,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Security\Authorization; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; +use Chill\MainBundle\Security\Authorization\VoterHelperInterface; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -19,7 +23,7 @@ use Symfony\Component\Security\Core\Security; use UnexpectedValueException; use function in_array; -class HouseholdVoter extends Voter +class HouseholdVoter extends Voter implements ProvideRoleHierarchyInterface { public const EDIT = 'CHILL_PERSON_HOUSEHOLD_EDIT'; @@ -36,17 +40,40 @@ class HouseholdVoter extends Voter self::EDIT, self::SEE, ]; + private VoterHelperInterface $helper; + private Security $security; - public function __construct(Security $security) + public function __construct(Security $security, VoterHelperFactoryInterface $voterHelperFactory) { $this->security = $security; + $this->helper = $voterHelperFactory + ->generate(self::class) + ->addCheckFor(Center::class, [self::STATS]) + ->build(); + } + + public function getRolesWithHierarchy(): array + { + return [ 'Person' => $this->getRoles() ]; + } + + public function getRoles(): array + { + return [self::STATS]; + } + + public function getRolesWithoutScope(): array + { + return $this->getRoles(); } protected function supports($attribute, $subject) { - return $subject instanceof Household - && in_array($attribute, self::ALL, true); + return ($subject instanceof Household + && in_array($attribute, self::ALL, true)) + || $this->helper->supports($attribute, $subject) + ; } protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool @@ -58,6 +85,9 @@ class HouseholdVoter extends Voter case self::EDIT: return $this->checkAssociatedMembersRole($subject, PersonVoter::UPDATE); + case self::STATS: + return $this->voteOnAttribute($attribute, $subject, $token); + default: throw new UnexpectedValueException('attribute not supported'); } diff --git a/src/Bundle/ChillPersonBundle/chill.webpack.config.js b/src/Bundle/ChillPersonBundle/chill.webpack.config.js index 85ee83c93..a445959e5 100644 --- a/src/Bundle/ChillPersonBundle/chill.webpack.config.js +++ b/src/Bundle/ChillPersonBundle/chill.webpack.config.js @@ -13,6 +13,7 @@ module.exports = function(encore, entries) encore.addEntry('vue_accourse_work_create', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkCreate/index.js'); encore.addEntry('vue_accourse_work_edit', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js'); encore.addEntry('vue_visgraph', __dirname + '/Resources/public/vuejs/VisGraph/index.js'); + encore.addEntry('vue_export_action_goal_result', __dirname + '/Resources/public/vuejs/ExportFormActionGoalResult/index.js'); encore.addEntry('mod_set_referrer', __dirname + '/Resources/public/mod/AccompanyingPeriod/setReferrer.js'); diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml index 73bd1cce3..f19db0649 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml @@ -65,13 +65,6 @@ services: tags: - { name: chill.export_filter, alias: accompanyingcourse_evaluation_filter } - chill.person.export.filter_activitytype: - class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\ActivityTypeFilter - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: accompanyingcourse_activitytype_filter } - chill.person.export.filter_origin: class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\OriginFilter autowire: true diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml index ac0f33cd8..9ee66f69e 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml @@ -79,3 +79,10 @@ services: autoconfigure: true tags: - { name: chill.export_aggregator, alias: social_work_actions_result_aggregator } + + chill.person.export.aggregator_goalresult: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\GoalResultAggregator + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: social_work_actions_goal_result_aggregator } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index cef8e6376..ddaf847c2 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -86,8 +86,8 @@ Civility: Civilité choose civility: -- All genders: tous les genres Any person selected: Aucune personne sélectionnée -Create a household and add an address: Ajouter une adresse pour un usager non suivi et seul dans un ménage -A new household will be created. The person will be member of this household.: Un nouveau ménage va être créé. L'usager sera membre de ce ménage. +Create a household and add an address: Ajouter une adresse pour une personne non suivie et seule dans un ménage +A new household will be created. The person will be member of this household.: Un nouveau ménage va être créé. La personne sera membre de ce ménage. Comment on the gender: Commentaire sur le genre # dédoublonnage @@ -127,8 +127,8 @@ address_country_code: Code pays 'Alreay existing person': 'Dossiers déjà encodés' 'Add the person': 'Ajouter la personne' -'Add the person and create an accompanying period': "Créer l'usager ET créer une période d'accompagnement" -'Add the person and create a household': "Créer l'usager ET créer un ménage" +'Add the person and create an accompanying period': "Créer la personne ET créer une période d'accompagnement" +'Add the person and create a household': "Créer la personne ET créer un ménage" Show person: Voir le dossier de la personne 'Confirm the creation': 'Confirmer la création' 'You will create this person': 'Vous allez créer le dossier suivant' @@ -200,7 +200,7 @@ Participants: Personnes impliquées Create an accompanying course: Créer un parcours Accompanying courses of users: Parcours des utilisateurs This accompanying course is still a draft: Ce parcours est encore à l'état brouillon. -Associated peoples: Usagers concernés +Associated peoples: Personnes concernées Resources: Interlocuteurs privilégiés Any requestor to this accompanying course: Aucun demandeur pour ce parcours Social action: Action d'accompagnement @@ -217,7 +217,7 @@ See this period: Voir cette période Requestor: Demandeur No requestor: Pas de demandeur No resources: "Pas d'interlocuteurs privilégiés" -Persons associated: Usagers concernés +Persons associated: Personnes concernés Referrer: Référent Referrers: Agents traitants Some peoples does not belong to any household currently. Add them to an household soon: Certaines personnes n'appartiennent à aucun ménage actuellement. Renseignez leur ménage dès que possible. @@ -244,7 +244,7 @@ List of resources: "Liste des ressources" There are no available resources: "Aucun ressource" no comment found: "Aucun commentaire" Select a type: "Choisissez un type" -Select a person: "Choisissez un usager" +Select a person: "Choisissez une personne" Select a thirdparty: "Choisissez un tiers" Contact person: "Personne de contact" Kind: "Type" @@ -276,11 +276,11 @@ Which kind of residential address would you create ?: Quel type d'adresse de ré The address of another person: L'adresse d'une autre personne The address of a third party: L'adresse d'un tiers A new address: Une nouvelle adresse -residential_address_person_explanation: L'adresse sera positionnée auprès d'un usager. Lorsque l'usager déménage, l'adresse de résidence suivra également cet usager +residential_address_person_explanation: L'adresse sera positionnée auprès d'une personne. Lorsque la personne déménage, l'adresse de résidence suivra également cette personne residential_address_third_party_explanation: L'adresse sera associée à celle d'un tiers. residential_address_new_address_explanation: Créer une nouvelle adresse. L'adresse sera fixe. New residential address: Nouvelle adresse de résidence -Host person: Choisir l'adresse d'un usager +Host person: Choisir l'adresse d'une personne Host third party: Choisir l'adresse d'un tiers The new residential address was created successfully: La nouvelle adresse de résidence a été créée Edit a residential address: Modifier l'addresse de résidence @@ -318,6 +318,7 @@ CHILL_PERSON_ACCOMPANYING_PERIOD_FULL: Voir les détails, créer, supprimer et m CHILL_PERSON_ACCOMPANYING_COURSE_REASSIGN_BULK: Réassigner les parcours en lot CHILL_PERSON_ACCOMPANYING_PERIOD_SEE_DETAILS: Voir les détails d'une période d'accompagnement CHILL_PERSON_ACCOMPANYING_PERIOD_STATS: Statistiques sur les parcours d'accompagnement +CHILL_PERSON_HOUSEHOLD_STATS: Statistiques sur les ménages #period Period closed!: Période clôturée! @@ -330,16 +331,16 @@ Accompanyied people: Personnes accompagnées ## exports Exports of persons: Exports des personnes -Count people by various parameters.: Compte le nombre d'usagers en fonction de différents filtres. -Count people: Nombre d'usagers +Count people by various parameters.: Compte le nombre de personnes en fonction de différents filtres. +Count people: Nombre de personnes List peoples: Liste des personnes Create a list of people according to various filters.: Crée une liste des personnes selon différents filtres. Fields to include in export: Champs à inclure dans l'export Address valid at this date: Addresse valide à cette date List duplicates: Liste des doublons Create a list of duplicate people: Créer la liste des personnes détectées comme doublons. -Count people participating in an accompanying course by various parameters.: Nombre d'usagers concernées par un parcours -Count people participating in an accompanying course: Nombre d'usagers concernés par un parcours +Count people participating in an accompanying course by various parameters.: Nombre de personnes concernées par un parcours +Count people participating in an accompanying course: Nombre de personnes concernés par un parcours Exports of accompanying courses: Exports des parcours d'accompagnement Count accompanying courses: Nombre de parcours @@ -362,72 +363,77 @@ Count households: Nombre de ménages Count household by various parameters.: Compte le nombre de ménages impliqués dans un parcours selon différents filtres. ## persons filters -Filter by person gender: Filtrer par genre de la personne +Filter by person gender: Filtrer les personnes par genre Accepted genders: Genres acceptés 'Filtering by genders: only %genders%': 'Filtré par genre: seulement %genders%' -Filter by person's nationality: Filtrer par nationalité +Filter by person's nationality: Filtrer les personnes par nationalité Nationalities: Nationalités Choose countries: Choisir les nationalités 'Filtered by nationality : %nationalities%': 'Filtré par nationalité : seulement %nationalities%' -Filter by person's birthdate: Filtrer par date de naissance de la personne +Filter by person's birthdate: Filtrer les personnes par date de naissance Born after this date: Nés après cette date Born before this date: Nés avant cette date This field should not be empty: Ce champ ne peut pas être vide This date should be after the date given in "born after" field: Cette date doit être après la date donnée du le champ "nés après le" "Filtered by person's birthdate: between %date_from% and %date_to%": "Filtré par date de naissance de la personne: uniquement nés entre le %date_from% et %date_to%" -Filter by person's deathdate: Filtrer par date de décès de la personne +Filter by person's deathdate: Filtrer les personnes par date de décès "Filtered by person's deathdate: between %date_from% and %date_to%": "Filtré par date de naissance de la personne: uniquement nés entre le %date_from% et %date_to%" Death after this date: Décédé après cette date Deathdate before: Décédé avant cette date - Alive: Vivant Deceased: Décédé Filter in relation to this date: Filtrer par rapport à cette date "Filtered by a state of %deadOrAlive% at this date %date_calc%": Filtré par personnes qui sont %deadOrAlive% à cette date %date_calc% -Filter by person's age: Filtrer par âge de la personne +Filter by person's age: Filtrer les personnes par age "Filtered by person's age: between %min_age% and %max_age%": "Filtré par âge de la personne entre %min_age% et %max_age%" Minimum age: Âge minimum Maximum age: Âge maximum The minimum age should be less than the maximum age.: L'âge minimum doit être plus bas que l'âge maximum. Date during which residential address was valid: Date de validité -Filtered by person\'s who have a residential address located at a thirdparty of type %thirparty_type%: Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% +Filtered by person\'s who have a residential address located at a thirdparty of type %thirparty_type%: Uniquement les personnes qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% Family composition: Composition familiale Family composition at this time: Composition familiale à cette date. +Filter by person's marital status: Filtrer les personnes par état matrimonial Filtered by person's marital status: Filtré par état matrimonial -Filter by person's marital status: Filtrer par état matrimonial Marital status at this time: État matrimonial par rapport à cette date -Filter by entrusted child status: Filtrer les usagers qui sont "enfant confié" -Filtered by entrusted child status: Uniquement les usagers qui sont "enfant confié" +Filter by entrusted child status: Filtrer les personnes "enfant confié" +Filtered by entrusted child status: Uniquement les personnes qui sont "enfant confié" -Filter by nomadic status: Filtrer les usagers qui sont "gens de voyage" -Filtered by nomadic status: Uniquement les usagers qui sont "gens de voyage" +Filter by nomadic status: Filtrer les personnes "gens du voyage" +Filtered by nomadic status: Uniquement les personnes qui sont "gens du voyage" -Filtered by person's who have a residential address located at another user: Uniquement les usagers qui ont une addresse de résidence chez un autre usager +"Filter by person's who have a residential address located at another user": Filtrer les personnes qui ont une addresse de résidence chez une autre personne +"Filtered by person's who have a residential address located at another user": Uniquement les personnes qui ont une addresse de résidence chez une autre personne -Filtered by person's that are alive or have deceased at a certain date: Filtrer par usagers qui sont décédé ou vivant à une certaine date +Filter by person's that are alive or have deceased at a certain date: Filtrer les personnes qui sont décédées ou vivantes à une certaine date +Filtered by person's that are alive or have deceased at a certain date: Uniquement les personnes qui sont décédées ou vivantes à une certaine date -"Filter by accompanying period: active period": "Filtrer par période d'accompagnement: en file active" +"Filter by accompanying period: active period": "Filtrer les personnes par période d'accompagnement: en file active" Having an accompanying period opened after this date: Ayant une période d'accompagnement ouverte après cette date Having an accompanying period ending before this date, or still opened at this date: Ayant une période d'accompagnement fermée après cette date, ou toujours ouverte à cette date "Filtered by accompanying period: persons having an accompanying period opened after the %date_from% and closed before the %date_to% (or still opened at the %date_to%)": "Filtré par période d'accompagnement: personnes ayant une période d'accompagnement ouverte après le %date_from%, et cloturée le %date_to% (ou toujours ouverte le %date_to%)" -"Filter by accompanying period: starting between two dates": "Filtrer par période d'accompagnement: début de la période entre deux dates" +"Filter by accompanying period: starting between two dates": "Filtrer les personnes par période d'accompagnement: début de la période entre deux dates" "Having an accompanying period opened before this date": "Ayant une période d'accompagnement ouverte avant cette date" "Filtered by accompanying period: persons having an accompanying period opened between the %date_from% and %date_to%": "Filtrer par période d'accompagnement: ayant une période ouverte entre le %date_from% et le %date_to%" -"Filter by accompanying period: closed between two dates": "Filtrer par période d'accompagnement: période fermée entre deux dates" +"Filter by accompanying period: closed between two dates": "Filtrer les personnes par période d'accompagnement: période fermée entre deux dates" Having an accompanying period closed after this date: Ayant une période d'accompagnement fermée après cette date "Having an accompanying period closed before this date": "Ayant une période d'accompagnement fermée avant cette date" "Filtered by accompanying period: persons having an accompanying period closed between the %date_from% and %date_to%": "Filtrer par période d'accompagnement: ayant une période fermée entre le %date_from% et le %date_to%" +Filter by person having an activity in a period: Filtrer les personnes ayant eu une échange pendant la période donnée +Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Uniquement les personnes associées à une échange entre %date_from% et %date_to% avec les sujets %reasons_name% + + ## accompanying course filters/aggr Filter by user scope: Filtrer les parcours par service du référent "Filtered by user main scope: only %scope%": "Filtré par service du référent: uniquement %scope%" @@ -456,7 +462,9 @@ Filter by socialaction: Filtrer les parcours par action d'accompagnement Accepted socialactions: Actions d'accompagnement "Filtered by socialactions: only %socialactions%": "Filtré par action d'accompagnement: uniquement %socialactions%" Group by social action: Grouper les parcours par action d'accompagnement -Filter by type of action, objectives and results: "Filtrer par type d'action, objectif et résultat" + +Filter by type of action, goals and results: "Filtrer les actions par type, objectif et résultat" +'Filtered actions by type, goals and results: %selected%': "Actions filtrées par: %selected%" Filter by evaluation: Filtrer les parcours par évaluation Accepted evaluations: Évaluations @@ -484,13 +492,13 @@ Administrative location: Localisation administrative "Filtered by administratives locations: only %locations%": "Filtré par localisation administrative: uniquement %locations%" Group by administrative location: Grouper les parcours par localisation administrative -Filter by requestor: Filtrer les parcours selon la présence du demandeur au sein des usagers concernés +Filter by requestor: Filtrer les parcours selon la présence du demandeur au sein des personnes concernées Accepted choices: '' -is person concerned: Le demandeur est un usager concerné -is other person: Le demandeur est un usager, mais n'est pas concerné +is person concerned: Le demandeur est une personne concernée +is other person: Le demandeur est une personne, mais n'est pas concernée is thirdparty: Le demandeur est un tiers no requestor: Le parcours ne comporte pas de demandeur -"Filtered by requestor: only %choice%": "Filtré par présence du demandeur au sein des usagers concernés: uniquement si %choice%" +"Filtered by requestor: only %choice%": "Filtré par présence du demandeur au sein des personnes concernées: uniquement si %choice%" Group by requestor: Grouper les parcours selon la nature du demandeur Filter by confidential: Filtrer les parcours par confidentialité @@ -553,6 +561,10 @@ Group by treating agent: Grouper les actions par agent traitant Group social work actions by action type: Grouper les actions par type Group social work actions by goal: Grouper les actions par objectif Group social work actions by result: Grouper les actions par résultat +Group social work actions by goal and result: Grouper les actions par objectif et résultat +Goal Type: Objectif +Result Type: Résultat +Goal and result Type: Objectif et résultat ## evaluations filters/aggr Filter by evaluation type: Filtrer les évaluations par type @@ -576,7 +588,7 @@ Group by composition: Grouper les ménages par composition familiale Group by number of children: Grouper les ménages par nombre d'enfants ## persons aggregators -Group by duration: Grouper par durée du parcours +Group by duration: Grouper les parcours par durée Rounded month duration: Durée en mois (arrondie) current duration: en cours duration 0 month: 0 mois (<15 jours) @@ -589,13 +601,15 @@ Group by country: Grouper par pays Group people by gender: Grouper les personnes par genre Group people by their professional situation: Grouper les personnes par situation professionelle Group people by marital status: Grouper les personnes par état matrimonial -Aggregate by household position: Grouper par position dans le ménage + +Aggregate by household position: Grouper les personnes par position dans le ménage Household position in relation to this date: Position dans le ménage par rapport à cette date Household position: Position dans le ménage -Filtered by person's who have a residential address located at a thirdparty of type: Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie "xxx" -"Filtered by person's who have a residential address located at a thirdparty of type %thirdparty_type% and valid on %date_calc%": "Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% et valide sur la date %date_calc%" -Aggregate by age: Grouper par âge +Filter by person's who have a residential address located at a thirdparty of type: Filtrer les personnes qui ont une addresse de résidence chez un tiers de catégorie "xxx" +"Filtered by person's who have a residential address located at a thirdparty of type %thirdparty_type% and valid on %date_calc%": "Uniquement les personnes qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% et valide sur la date %date_calc%" + +Aggregate by age: Grouper les personnes par âge Calculate age in relation to this date: Calculer l'âge par rapport à cette date Group people by country of birth: Grouper les personnes par pays de naissance @@ -763,7 +777,7 @@ This course is located at a temporarily address. You should locate this course t Accompanying course location: Localisation du parcours This course is located by: Localisé auprès de This course has a temporarily location: Localisation temporaire -Choose a person to locate by: Localiser auprès d'un usager concerné +Choose a person to locate by: Localiser auprès d'une personne concernée Associate at least one member with an household, and set an address to this household: Associez au moins un membre du parcours à un ménage, et indiquez une adresse à ce ménage. Locate by: Localiser auprès de fix it: Compléter @@ -848,7 +862,7 @@ Person addresses: Adresses de résidence Household addresses: Adresses de domicile Insert an address: Insérer une adresse see social issues: Voir les problématiques sociales -see persons associated: Voir les usagers concernés +see persons associated: Voir les personnes concernées docgen: Accompanying Period basic: "Parcours d'accompagnement (basique)" @@ -869,10 +883,10 @@ docgen: period_notification: period_designated_subject: Vous êtes référent d'un parcours d'accompagnement You are designated to a new period: Vous avez été désigné référent d'un parcours d'accompagnement. - Persons are: Les usagers concernés sont les suivants + Persons are: Les personnes concernées sont les suivantes Social issues are: Les problématiques sociales renseignées sont les suivantes See it online: Visualisez le parcours en ligne - Person locating period has moved: L'usager qui localise un parcours a déménagé + Person locating period has moved: La personne qui localise un parcours a déménagé You are getting a notification for a period which does not exists any more: Cette notification ne correspond pas à une période d'accompagnement valide. You are getting a notification for a period you are not allowed to see: La notification fait référence à une période d'accompagnement à laquelle vous n'avez pas accès.