mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-29 21:46:14 +00:00
Merge branch 'master' into upgrade-php82
This commit is contained in:
commit
950ca42f68
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\PickUserLocationType;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class LocationFilter implements FilterInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->andWhere(
|
||||
$qb->expr()->in('activity.location', ':location')
|
||||
);
|
||||
|
||||
$qb->setParameter('location', $data['accepted_location']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_location', PickUserLocationType::class, [
|
||||
'multiple' => true,
|
||||
'label' => 'pick location'
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$locations = [];
|
||||
|
||||
foreach ($data['accepted_location'] as $location) {
|
||||
$locations[] = $location->getName();
|
||||
}
|
||||
|
||||
return ['Filtered activity by location: only %locations%', [
|
||||
'%locations%' => implode(', ', $locations),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by location';
|
||||
}
|
||||
}
|
@ -79,6 +79,11 @@ services:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'accompanyingcourse_activitytype_filter' }
|
||||
|
||||
chill.activity.export.location_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_location_filter' }
|
||||
|
||||
chill.activity.export.locationtype_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter
|
||||
tags:
|
||||
|
@ -252,6 +252,8 @@ Activity reasons for those activities: Sujets de ces activités
|
||||
|
||||
Filter by activity type: Filtrer les activités par type
|
||||
|
||||
Filter activity by location: Filtrer les activités par localisation
|
||||
'Filtered activity by location: only %locations%': "Filtré par localisation: uniquement %locations%"
|
||||
Filter activity by locationtype: Filtrer les activités par type de localisation
|
||||
'Filtered activity by locationtype: only %types%': "Filtré par type de localisation: uniquement %types%"
|
||||
Accepted locationtype: Types de localisation
|
||||
|
@ -53,19 +53,15 @@ class ByActivityTypeAggregator implements AggregatorInterface
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
$this->asideActivityCategoryRepository->findBy(['id' => $values]);
|
||||
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'export.aggregator.Aside activity type';
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
if (null === $value || null === $t = $this->asideActivityCategoryRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$t = $this->asideActivityCategoryRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize($t->getTitle());
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
<?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\AsideActivityBundle\Export\Aggregator;
|
||||
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
use function in_array;
|
||||
|
||||
class ByUserJobAggregator implements AggregatorInterface
|
||||
{
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
private UserJobRepositoryInterface $userJobRepository;
|
||||
|
||||
public function __construct(UserJobRepositoryInterface $userJobRepository, TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
$this->userJobRepository = $userJobRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('aside_user', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('aside.agent', 'aside_user');
|
||||
}
|
||||
|
||||
$qb
|
||||
->addSelect('IDENTITY(aside_user.userJob) AS aside_activity_user_job_aggregator')
|
||||
->addGroupBy('aside_activity_user_job_aggregator');
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// nothing to add in the form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Users \'s job';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$j = $this->userJobRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['aside_activity_user_job_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'export.aggregator.Aggregate by user job';
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
<?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\AsideActivityBundle\Export\Aggregator;
|
||||
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
use function in_array;
|
||||
|
||||
class ByUserScopeAggregator implements AggregatorInterface
|
||||
{
|
||||
private ScopeRepositoryInterface $scopeRepository;
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
public function __construct(ScopeRepositoryInterface $scopeRepository, TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('aside_user', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('aside.agent', 'aside_user');
|
||||
}
|
||||
|
||||
$qb
|
||||
->addSelect('IDENTITY(aside_user.mainScope) AS aside_activity_user_scope_aggregator')
|
||||
->addGroupBy('aside_activity_user_scope_aggregator');
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// nothing to add in the form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Users \'s scope';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$s = $this->scopeRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['aside_activity_user_scope_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'export.aggregator.Aggregate by user scope';
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
<?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\AsideActivityBundle\Export\Export;
|
||||
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\AsideActivityBundle\Repository\AsideActivityRepository;
|
||||
use Chill\AsideActivityBundle\Security\AsideActivityVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class AvgAsideActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private AsideActivityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
AsideActivityRepository $repository
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'export.Average aside activities duration';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'export.Exports of aside activities';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_avg_aside_activity_duration' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Average duration aside activities' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_avg_aside_activity_duration'];
|
||||
}
|
||||
|
||||
public function getResult($query, $data)
|
||||
{
|
||||
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'export.Average aside activities duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('aside');
|
||||
|
||||
$qb
|
||||
->select('AVG(aside.duration) as export_avg_aside_activity_duration')
|
||||
->andWhere($qb->expr()->isNotNull('aside.duration'));
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return AsideActivityVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [Declarations::ASIDE_ACTIVITY_TYPE];
|
||||
}
|
||||
}
|
@ -100,6 +100,8 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [];
|
||||
return [
|
||||
Declarations::ASIDE_ACTIVITY_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AsideActivityBundle\Export\Export;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\AsideActivityBundle\Form\AsideActivityCategoryType;
|
||||
use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository;
|
||||
use Chill\AsideActivityBundle\Security\AsideActivityVoter;
|
||||
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\MainBundle\Export\Helper\DateTimeHelper;
|
||||
use Chill\MainBundle\Export\Helper\UserHelper;
|
||||
use Chill\MainBundle\Export\ListInterface;
|
||||
use Chill\MainBundle\Repository\CenterRepositoryInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Closure;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private UserHelper $userHelper;
|
||||
|
||||
private DateTimeHelper $dateTimeHelper;
|
||||
|
||||
private ScopeRepositoryInterface $scopeRepository;
|
||||
|
||||
private CenterRepositoryInterface $centerRepository;
|
||||
|
||||
private AsideActivityCategoryRepository $asideActivityCategoryRepository;
|
||||
|
||||
private CategoryRender $categoryRender;
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
DateTimeHelper $dateTimeHelper,
|
||||
UserHelper $userHelper,
|
||||
ScopeRepositoryInterface $scopeRepository,
|
||||
CenterRepositoryInterface $centerRepository,
|
||||
AsideActivityCategoryRepository $asideActivityCategoryRepository,
|
||||
CategoryRender $categoryRender,
|
||||
TranslatableStringHelperInterface $translatableStringHelper
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->dateTimeHelper = $dateTimeHelper;
|
||||
$this->userHelper = $userHelper;
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->centerRepository = $centerRepository;
|
||||
$this->asideActivityCategoryRepository = $asideActivityCategoryRepository;
|
||||
$this->categoryRender = $categoryRender;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_LIST];
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'export.aside_activity.List of aside activities';
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'export.aside_activity.List of aside activities';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'export.Exports of aside activities';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'id':
|
||||
case 'note':
|
||||
return function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return 'export.aside_activity.' . $key;
|
||||
}
|
||||
|
||||
return $value ?? '';
|
||||
};
|
||||
case 'duration':
|
||||
return function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return 'export.aside_activity.' . $key;
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return $value->format('H:i:s');
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
|
||||
case 'createdAt':
|
||||
case 'updatedAt':
|
||||
case 'date':
|
||||
return $this->dateTimeHelper->getLabel('export.aside_activity.'.$key);
|
||||
|
||||
case 'agent_id':
|
||||
case 'creator_id':
|
||||
return $this->userHelper->getLabel($key, $values, 'export.aside_activity.' . $key);
|
||||
|
||||
case 'aside_activity_type':
|
||||
return function ($value) {
|
||||
if ('_header' === $value) {
|
||||
return 'export.aside_activity.aside_activity_type';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value || null === $c = $this->asideActivityCategoryRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->categoryRender->renderString($c, []);
|
||||
};
|
||||
|
||||
case 'main_scope':
|
||||
return function ($value) {
|
||||
if ('_header' === $value) {
|
||||
return 'export.aside_activity.main_scope';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value || null === $c = $this->scopeRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize($c->getName());
|
||||
};
|
||||
|
||||
case 'main_center':
|
||||
return function ($value) {
|
||||
if ('_header' === $value) {
|
||||
return 'export.aside_activity.main_center';
|
||||
}
|
||||
|
||||
/** @var Center $c */
|
||||
if (null === $value || '' === $value || null === $c = $this->centerRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $c->getName();
|
||||
};
|
||||
|
||||
default:
|
||||
throw new \LogicException('this key is not supported : ' . $key);
|
||||
}
|
||||
}
|
||||
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
return [
|
||||
'id',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'agent_id',
|
||||
'creator_id',
|
||||
'main_scope',
|
||||
'main_center',
|
||||
'aside_activity_type',
|
||||
'date',
|
||||
'duration',
|
||||
'note'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $query
|
||||
* @param array $data
|
||||
*/
|
||||
public function getResult($query, $data): array
|
||||
{
|
||||
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder()
|
||||
->from(AsideActivity::class, 'aside')
|
||||
->leftJoin('aside.agent', 'agent')
|
||||
;
|
||||
|
||||
$qb
|
||||
->addSelect('aside.id AS id')
|
||||
->addSelect('aside.createdAt AS createdAt')
|
||||
->addSelect('aside.updatedAt AS updatedAt')
|
||||
->addSelect('IDENTITY(aside.agent) AS agent_id')
|
||||
->addSelect('IDENTITY(aside.createdBy) AS creator_id')
|
||||
->addSelect('IDENTITY(agent.mainScope) AS main_scope')
|
||||
->addSelect('IDENTITY(agent.mainCenter) AS main_center')
|
||||
->addSelect('IDENTITY(aside.type) AS aside_activity_type')
|
||||
->addSelect('aside.date')
|
||||
->addSelect('aside.duration')
|
||||
->addSelect('aside.note')
|
||||
;
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return AsideActivityVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return [Declarations::ASIDE_ACTIVITY_TYPE];
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
<?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\AsideActivityBundle\Export\Export;
|
||||
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\AsideActivityBundle\Repository\AsideActivityRepository;
|
||||
use Chill\AsideActivityBundle\Security\AsideActivityVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class SumAsideActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private AsideActivityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
AsideActivityRepository $repository
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'export.Sum aside activities duration';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'export.Exports of aside activities';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_sum_aside_activity_duration' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Sum duration aside activities' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_sum_aside_activity_duration'];
|
||||
}
|
||||
|
||||
public function getResult($query, $data)
|
||||
{
|
||||
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'export.Sum aside activities duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('aside');
|
||||
|
||||
$qb->select('SUM(aside.duration) as export_sum_aside_activity_duration')
|
||||
->andWhere($qb->expr()->isNotNull('aside.duration'));
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return AsideActivityVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [Declarations::ASIDE_ACTIVITY_TYPE];
|
||||
}
|
||||
}
|
@ -80,8 +80,8 @@ class ByActivityTypeFilter implements FilterInterface
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$types = array_map(
|
||||
fn (AsideActivityCategory $t): string => $this->translatableStringHelper->localize($t->getName()),
|
||||
$this->asideActivityTypeRepository->findBy(['id' => $data['types']->toArray()])
|
||||
fn (AsideActivityCategory $t): string => $this->translatableStringHelper->localize($t->getTitle()),
|
||||
$data['types']->toArray()
|
||||
);
|
||||
|
||||
return ['export.filter.Filtered by aside activity type: only %type%', [
|
||||
|
@ -46,25 +46,18 @@ class ByDateFilter implements FilterInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->between(
|
||||
'aside.date',
|
||||
':date_from',
|
||||
':date_to'
|
||||
);
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
$qb->andWhere($clause);
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter(
|
||||
'date_from',
|
||||
$this->rollingDateConverter->convert($data['date_from'])
|
||||
);
|
||||
$qb->setParameter(
|
||||
)->setParameter(
|
||||
'date_to',
|
||||
$this->rollingDateConverter->convert($data['date_to'])
|
||||
);
|
||||
|
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\AsideActivityBundle\Export\Filter;
|
||||
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class ByUserFilter implements FilterInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
public function __construct(UserRender $userRender)
|
||||
{
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$clause = $qb->expr()->in('aside.agent', ':users');
|
||||
|
||||
$qb
|
||||
->andWhere($clause)
|
||||
->setParameter('users', $data['accepted_users']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_users', PickUserDynamicType::class, [
|
||||
'multiple' => true,
|
||||
'label' => 'Creators',
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$users = [];
|
||||
|
||||
foreach ($data['accepted_users'] as $u) {
|
||||
$users[] = $this->userRender->renderString($u, []);
|
||||
}
|
||||
|
||||
return ['export.filter.Filtered aside activity by user: only %users%', [
|
||||
'%users%' => implode(', ', $users),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'export.filter.Filter aside activity by user';
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?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\AsideActivityBundle\Export\Filter;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\UserJob;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class ByUserJobFilter implements FilterInterface
|
||||
{
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM ' . AsideActivity::class . ' aside_activity_user_job_filter_act
|
||||
JOIN aside_activity_user_job_filter_act.agent aside_activity_user_job_filter_user WHERE aside_activity_user_job_filter_user.userJob IN (:aside_activity_user_job_filter_jobs) AND aside_activity_user_job_filter_act = aside'
|
||||
)
|
||||
)
|
||||
->setParameter('aside_activity_user_job_filter_jobs', $data['jobs']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('jobs', EntityType::class, [
|
||||
'class' => UserJob::class,
|
||||
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize($j->getLabel()),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
return ['export.filter.Filtered aside activities by user jobs: only %jobs%', [
|
||||
'%jobs%' => implode(
|
||||
', ',
|
||||
array_map(
|
||||
fn (UserJob $job) => $this->translatableStringHelper->localize($job->getLabel()),
|
||||
$data['jobs']->toArray()
|
||||
)
|
||||
),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'export.filter.Filter by user jobs';
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
<?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\AsideActivityBundle\Export\Filter;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||
use Chill\AsideActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class ByUserScopeFilter implements FilterInterface
|
||||
{
|
||||
private ScopeRepositoryInterface $scopeRepository;
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
ScopeRepositoryInterface $scopeRepository,
|
||||
TranslatableStringHelperInterface $translatableStringHelper
|
||||
) {
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM ' . AsideActivity::class . ' aside_activity_user_scope_filter_act
|
||||
JOIN aside_activity_user_scope_filter_act.agent aside_activity_user_scope_filter_user WHERE aside_activity_user_scope_filter_user.mainScope IN (:aside_activity_user_scope_filter_scopes) AND aside_activity_user_scope_filter_act = aside '
|
||||
)
|
||||
)
|
||||
->setParameter('aside_activity_user_scope_filter_scopes', $data['scopes']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
{
|
||||
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('scopes', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'choices' => $this->scopeRepository->findAllActive(),
|
||||
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
return ['export.filter.Filtered aside activities by user scope: only %scopes%', [
|
||||
'%scopes%' => implode(
|
||||
', ',
|
||||
array_map(
|
||||
fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()),
|
||||
$data['scopes']->toArray()
|
||||
)
|
||||
),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'export.filter.Filter by user scope';
|
||||
}
|
||||
}
|
@ -20,33 +20,3 @@ services:
|
||||
resource: "../Controller"
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
|
||||
## Exports
|
||||
|
||||
# indicators
|
||||
Chill\AsideActivityBundle\Export\Export\CountAsideActivity:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export, alias: count_asideactivity }
|
||||
|
||||
# filters
|
||||
Chill\AsideActivityBundle\Export\Filter\ByDateFilter:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: asideactivity_bydate_filter }
|
||||
|
||||
Chill\AsideActivityBundle\Export\Filter\ByActivityTypeFilter:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: asideactivity_activitytype_filter }
|
||||
|
||||
# aggregators
|
||||
Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: asideactivity_activitytype_aggregator }
|
||||
|
@ -3,11 +3,23 @@ services:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\AsideActivityBundle\Export\Export\ListAsideActivity:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'list_aside_activity' }
|
||||
|
||||
## Indicators
|
||||
Chill\AsideActivityBundle\Export\Export\CountAsideActivity:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'count_aside_activity' }
|
||||
|
||||
Chill\AsideActivityBundle\Export\Export\SumAsideActivityDuration:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'sum_aside_activity_duration' }
|
||||
|
||||
Chill\AsideActivityBundle\Export\Export\AvgAsideActivityDuration:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'avg_aside_activity_duration' }
|
||||
|
||||
## Filters
|
||||
chill.aside_activity.export.date_filter:
|
||||
class: Chill\AsideActivityBundle\Export\Filter\ByDateFilter
|
||||
@ -19,9 +31,34 @@ services:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'aside_activity_type_filter' }
|
||||
|
||||
chill.aside_activity.export.user_job_filter:
|
||||
class: Chill\AsideActivityBundle\Export\Filter\ByUserJobFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'aside_activity_user_job_filter' }
|
||||
|
||||
chill.aside_activity.export.user_scope_filter:
|
||||
class: Chill\AsideActivityBundle\Export\Filter\ByUserScopeFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'aside_activity_user_scope_filter' }
|
||||
|
||||
chill.aside_activity.export.user_filter:
|
||||
class: Chill\AsideActivityBundle\Export\Filter\ByUserFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'aside_activity_user_filter' }
|
||||
|
||||
## Aggregators
|
||||
|
||||
chill.aside_activity.export.type_aggregator:
|
||||
class: Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_type_aggregator }
|
||||
- { name: chill.export_aggregator, alias: activity_type_aggregator }
|
||||
|
||||
chill.aside_activity.export.user_job_aggregator:
|
||||
class: Chill\AsideActivityBundle\Export\Aggregator\ByUserJobAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: aside_activity_user_job_aggregator }
|
||||
|
||||
chill.aside_activity.export.user_scope_aggregator:
|
||||
class: Chill\AsideActivityBundle\Export\Aggregator\ByUserScopeAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: aside_activity_user_scope_aggregator }
|
||||
|
@ -29,16 +29,16 @@ location: Lieu
|
||||
|
||||
# Crud
|
||||
crud:
|
||||
aside_activity:
|
||||
title_view: Détail de l'activité annexe
|
||||
title_new: Nouvelle activité annexe
|
||||
title_edit: Édition d'une activité annexe
|
||||
title_delete: Supprimer une activité annexe
|
||||
button_delete: Supprimer
|
||||
confirm_message_delete: Êtes-vous sûr de vouloir supprimer cette activité annexe?
|
||||
aside_activity_category:
|
||||
title_new: Nouvelle catégorie d'activité annexe
|
||||
title_edit: Édition d'une catégorie de type d'activité
|
||||
aside_activity:
|
||||
title_view: Détail de l'activité annexe
|
||||
title_new: Nouvelle activité annexe
|
||||
title_edit: Édition d'une activité annexe
|
||||
title_delete: Supprimer une activité annexe
|
||||
button_delete: Supprimer
|
||||
confirm_message_delete: Êtes-vous sûr de vouloir supprimer cette activité annexe?
|
||||
aside_activity_category:
|
||||
title_new: Nouvelle catégorie d'activité annexe
|
||||
title_edit: Édition d'une catégorie de type d'activité
|
||||
|
||||
#forms
|
||||
Create a new aside activity type: Nouvelle categorie d'activité annexe
|
||||
@ -169,19 +169,43 @@ Aside activity configuration: Configuration des activités annexes
|
||||
|
||||
# exports
|
||||
export:
|
||||
Exports of aside activities: Exports des activités annexes
|
||||
Count aside activities: Nombre d'activités annexes
|
||||
Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères
|
||||
filter:
|
||||
Filter by aside activity date: Filtrer les activités annexes par date
|
||||
Filter by aside activity type: Filtrer les activités annexes par type d'activité
|
||||
'Filtered by aside activity type: only %type%': "Filtré par type d'activité annexe: uniquement %type%"
|
||||
This date should be after the date given in "Implied in an aside activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités annexes après cette date"
|
||||
Aside activities after this date: Actvitités annexes après cette date
|
||||
Aside activities before this date: Actvitités annexes avant cette date
|
||||
aggregator:
|
||||
Group by aside activity type: Grouper les activités annexes par type d'activité
|
||||
Aside activity type: Type d'activité annexe
|
||||
aside_activity:
|
||||
List of aside activities: Liste des activités annexes
|
||||
createdAt: Création
|
||||
updatedAt: Dernière mise à jour
|
||||
agent_id: Utilisateur
|
||||
creator_id: Créateur
|
||||
main_scope: Service principal de l'utilisateur
|
||||
main_center: Centre principal de l'utilisteur
|
||||
aside_activity_type: Catégorie d'activité annexe
|
||||
date: Date
|
||||
duration: Durée
|
||||
note: Note
|
||||
|
||||
Exports of aside activities: Exports des activités annexes
|
||||
Count aside activities: Nombre d'activités annexes
|
||||
Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères
|
||||
Average aside activities duration: Durée moyenne des activités annexes
|
||||
Sum aside activities duration: Durée des activités annexes
|
||||
filter:
|
||||
Filter by aside activity date: Filtrer les activités annexes par date
|
||||
Filter by aside activity type: Filtrer les activités annexes par type d'activité
|
||||
'Filtered by aside activity type: only %type%': "Filtré par type d'activité annexe: uniquement %type%"
|
||||
Filtered by aside activities between %dateFrom% and %dateTo%: Filtré par date d'activité annexe, entre %dateFrom% et %dateTo%
|
||||
This date should be after the date given in "Implied in an aside activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités annexes après cette date"
|
||||
Aside activities after this date: Actvitités annexes après cette date
|
||||
Aside activities before this date: Actvitités annexes avant cette date
|
||||
'Filtered aside activity by user: only %users%': "Filtré par utilisateur: uniquement %users%"
|
||||
Filter aside activity by user: Filtrer par utilisateur
|
||||
'Filtered aside activities by user jobs: only %jobs%': "Filtré par métier des utilisateurs: uniquement %jobs%"
|
||||
Filter by user jobs: Filtrer les activités annexes par métier des utilisateurs
|
||||
'Filtered aside activities by user scope: only %scopes%': "Filtré par service des utilisateur: uniquement %scopes%"
|
||||
Filter by user scope: Filtrer les activités annexes par service d'utilisateur
|
||||
aggregator:
|
||||
Group by aside activity type: Grouper les activités annexes par type d'activité
|
||||
Aside activity type: Type d'activité annexe
|
||||
Aggregate by user job: Grouper les activités annexes par métier des utilisateurs
|
||||
Aggregate by user scope: Grouper les activités annexes par service des utilisateurs
|
||||
|
||||
# ROLES
|
||||
CHILL_ASIDE_ACTIVITY_STATS: Statistiques pour les activités annexes
|
||||
|
@ -12,12 +12,17 @@ declare(strict_types=1);
|
||||
namespace Chill\BudgetBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Type of charge.
|
||||
*
|
||||
* @ORM\Table(name="chill_budget.charge_type")
|
||||
* @ORM\Table(name="chill_budget.charge_type",
|
||||
* uniqueConstraints={@ORM\UniqueConstraint(name="charge_kind_unique_type_idx", fields={"kind"})}
|
||||
* )
|
||||
* @ORM\Entity
|
||||
* @UniqueEntity(fields={"kind"})
|
||||
*/
|
||||
class ChargeKind
|
||||
{
|
||||
@ -35,6 +40,8 @@ class ChargeKind
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, options={"default": ""}, nullable=false)
|
||||
* @Assert\Regex(pattern="/^[a-z0-9\-_]{1,}$/", message="budget.admin.form.kind.only_alphanumeric")
|
||||
* @Assert\Length(min=3)
|
||||
*/
|
||||
private string $kind = '';
|
||||
|
||||
|
@ -12,12 +12,17 @@ declare(strict_types=1);
|
||||
namespace Chill\BudgetBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Type of resource.
|
||||
*
|
||||
* @ORM\Table(name="chill_budget.resource_type")
|
||||
* @ORM\Table(name="chill_budget.resource_type", uniqueConstraints={
|
||||
* @ORM\UniqueConstraint(name="resource_kind_unique_type_idx", fields={"kind"})
|
||||
* })
|
||||
* @ORM\Entity
|
||||
* @UniqueEntity(fields={"kind"})
|
||||
*/
|
||||
class ResourceKind
|
||||
{
|
||||
@ -35,6 +40,8 @@ class ResourceKind
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=false, options={"default": ""})
|
||||
* @Assert\Regex(pattern="/^[a-z0-9\-_]{1,}$/", message="budget.admin.form.kind.only_alphanumeric")
|
||||
* @Assert\Length(min=3)
|
||||
*/
|
||||
private string $kind = '';
|
||||
|
||||
|
@ -16,6 +16,7 @@ use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
@ -25,7 +26,11 @@ class ChargeKindType extends AbstractType
|
||||
{
|
||||
$builder
|
||||
->add('name', TranslatableStringFormType::class, [
|
||||
'label' => 'Nom',
|
||||
'label' => 'Title',
|
||||
])
|
||||
->add('kind', TextType::class, [
|
||||
'label' => 'budget.admin.form.Charge_kind_key',
|
||||
'help' => 'budget.admin.form.This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document'
|
||||
])
|
||||
->add('ordering', NumberType::class)
|
||||
->add('isActive', CheckboxType::class, [
|
||||
|
@ -16,6 +16,7 @@ use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
@ -25,7 +26,11 @@ class ResourceKindType extends AbstractType
|
||||
{
|
||||
$builder
|
||||
->add('name', TranslatableStringFormType::class, [
|
||||
'label' => 'Nom',
|
||||
'label' => 'Title',
|
||||
])
|
||||
->add('kind', TextType::class, [
|
||||
'label' => 'budget.admin.form.Resource_kind_key',
|
||||
'help' => 'budget.admin.form.This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document'
|
||||
])
|
||||
->add('ordering', NumberType::class)
|
||||
->add('isActive', CheckboxType::class, [
|
||||
|
@ -82,11 +82,6 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
return $this->repository->findOneBy($criteria);
|
||||
}
|
||||
|
||||
public function findOneByKind(string $kind): ?ResourceKind
|
||||
{
|
||||
return $this->repository->findOneBy(['kind' => $kind]);
|
||||
}
|
||||
|
||||
public function getClassName(): string
|
||||
{
|
||||
return ResourceKind::class;
|
||||
|
@ -19,7 +19,10 @@
|
||||
{% for entity in entities %}
|
||||
<tr>
|
||||
<td>{{ entity.ordering }}</td>
|
||||
<td>{{ entity|chill_entity_render_box }}</td>
|
||||
<td>
|
||||
{{ entity|chill_entity_render_box }}<br/>
|
||||
<strong>{{ 'budget.admin.form.Charge_kind_key'|trans }} :</strong> <code>{{ entity.kind }}</code>
|
||||
</td>
|
||||
<td style="text-align:center;">
|
||||
{%- if entity.isActive -%}
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
@ -39,6 +42,8 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<a href="{{ path('chill_crud_charge_kind_new') }}" class="btn btn-create">
|
||||
|
@ -19,7 +19,10 @@
|
||||
{% for entity in entities %}
|
||||
<tr>
|
||||
<td>{{ entity.ordering }}</td>
|
||||
<td>{{ entity|chill_entity_render_box }}</td>
|
||||
<td>
|
||||
{{ entity|chill_entity_render_box }}<br/>
|
||||
<strong>{{ 'budget.admin.form.Resource_kind_key'|trans }} :</strong> <code>{{ entity.kind }}</code>
|
||||
</td>
|
||||
<td style="text-align:center;">
|
||||
{%- if entity.isActive -%}
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
@ -39,6 +42,8 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<a href="{{ path('chill_crud_resource_kind_new') }}" class="btn btn-create">
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Budget;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230209161546 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Budget: add unique constraint on kind for charge_kind and resource_kind';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql("UPDATE chill_budget.resource_type SET kind=md5(random()::text) WHERE kind = ''");
|
||||
$this->addSql("UPDATE chill_budget.charge_type SET kind=md5(random()::text) WHERE kind = ''");
|
||||
$this->addSql('CREATE UNIQUE INDEX resource_kind_unique_type_idx ON chill_budget.resource_type (kind);');
|
||||
$this->addSql('CREATE UNIQUE INDEX charge_kind_unique_type_idx ON chill_budget.charge_type (kind);');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP INDEX resource_kind_unique_type_idx');
|
||||
$this->addSql('DROP INDEX charge_kind_unique_type_idx');
|
||||
}
|
||||
}
|
@ -77,6 +77,13 @@ The balance: Différence entre ressources et charges
|
||||
Valid since %startDate% until %endDate%: Valide depuis le %startDate% jusqu'au %endDate%
|
||||
Valid since %startDate%: Valide depuis le %startDate%
|
||||
|
||||
budget:
|
||||
admin:
|
||||
form:
|
||||
Charge_kind_key: Clé d'identification
|
||||
Resource_kind_key: Clé d'identification
|
||||
This kind must contains only alphabeticals characters, and dashes. This string is in use during document generation. Changes may have side effect on document: Cette clé sert à identifier le type de charge ou de revenu lors de la génération de document. Seuls les caractères alpha-numériques sont autorisés. Modifier cette clé peut avoir un effet lors de la génération de nouveaux documents.
|
||||
|
||||
# ROLES
|
||||
Budget elements: Budget
|
||||
CHILL_BUDGET_ELEMENT_CREATE: Créer une ressource/charge
|
||||
|
@ -1,2 +1,8 @@
|
||||
The amount cannot be empty: Le montant ne peut pas être vide ou égal à zéro
|
||||
The budget element's end date must be after the start date: La date de fin doit être après la date de début
|
||||
The budget element's end date must be after the start date: La date de fin doit être après la date de début
|
||||
|
||||
budget:
|
||||
admin:
|
||||
form:
|
||||
kind:
|
||||
only_alphanumeric
|
||||
|
@ -28,7 +28,7 @@ class LocationController extends CRUDController
|
||||
|
||||
protected function customizeQuery(string $action, Request $request, $query): void
|
||||
{
|
||||
$query->where('e.availableForUsers = true'); //TODO not working
|
||||
$query->where('e.availableForUsers = "TRUE"');
|
||||
}
|
||||
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
|
@ -83,9 +83,9 @@ interface ExportInterface extends ExportElementInterface
|
||||
*
|
||||
* @param string $key The column key, as added in the query
|
||||
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
|
||||
* @param mixed $data The data from the export's form (as defined in `buildForm`
|
||||
* @param mixed $data The data from the export's form (as defined in `buildForm`)
|
||||
*
|
||||
* @return Closure where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }`
|
||||
* @return pure-callable(null|string|int|float|'_header' $value):string|int|\DateTimeInterface where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }`
|
||||
*/
|
||||
public function getLabels($key, array $values, $data);
|
||||
|
||||
|
@ -35,6 +35,10 @@ class DateTimeHelper
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// warning: won't work with DateTimeImmutable as we reset time a few lines later
|
||||
$date = DateTime::createFromFormat('Y-m-d', $value);
|
||||
$hasTime = false;
|
||||
|
@ -229,6 +229,7 @@ Create a new circle: Créer un nouveau cercle
|
||||
|
||||
#admin section for location
|
||||
Location: Localisation
|
||||
pick location: Localisation
|
||||
Location type list: Liste des types de localisation
|
||||
Create a new location type: Créer un nouveau type de localisation
|
||||
Available for users: Disponible aux utilisateurs
|
||||
|
@ -19,7 +19,7 @@ use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
final class JobAggregator implements AggregatorInterface
|
||||
final class UserJobAggregator implements AggregatorInterface
|
||||
{
|
||||
private UserJobRepository $jobRepository;
|
||||
|
||||
@ -40,11 +40,11 @@ final class JobAggregator implements AggregatorInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('acpjob', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('acp.job', 'acpjob');
|
||||
if (!in_array('acpuser', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('acp.user', 'acpuser');
|
||||
}
|
||||
|
||||
$qb->addSelect('IDENTITY(acp.job) AS job_aggregator');
|
||||
$qb->addSelect('IDENTITY(acpuser.userJob) AS job_aggregator');
|
||||
$qb->addGroupBy('job_aggregator');
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ class HasTemporaryLocationFilter implements FilterInterface
|
||||
{
|
||||
$builder
|
||||
->add('having_temporarily', ChoiceType::class, [
|
||||
'label' => 'export.filter.course.having_temporarily.label',
|
||||
'choices' => [
|
||||
'export.filter.course.having_temporarily.Having a temporarily location' => true,
|
||||
'export.filter.course.having_temporarily.Having a person\'s location' => false,
|
||||
|
@ -126,12 +126,4 @@ class UserJobFilter implements FilterInterface
|
||||
{
|
||||
return 'Filter by user job';
|
||||
}
|
||||
|
||||
private function getUserJob(): UserJob
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->security->getUser();
|
||||
|
||||
return $user->getUserJob();
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\PersonBundle\Export\Filter\SocialWorkFilters;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
@ -61,13 +60,8 @@ class ReferrerFilter implements FilterInterface
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_agents', EntityType::class, [
|
||||
'class' => User::class,
|
||||
'choice_label' => function (User $u) {
|
||||
return $this->userRender->renderString($u, []);
|
||||
},
|
||||
$builder->add('accepted_agents', PickUserDynamicType::class, [
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||
import { fetchResults } from 'ChillMainAssets/lib/api/apiMethods';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
@ -58,23 +58,17 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getOptions() {
|
||||
const url = `/api/1.0/main/location.json`;
|
||||
makeFetch('GET', url)
|
||||
fetchResults(`/api/1.0/main/location.json`)
|
||||
.then(response => {
|
||||
let options = response.results;
|
||||
let uniqueLocationTypeId = [...new Set(options.map(o => o.locationType.id))];
|
||||
let uniqueLocationTypeId = [...new Set(response.map(o => o.locationType.id))];
|
||||
let results = [];
|
||||
for (let id of uniqueLocationTypeId) {
|
||||
results.push({
|
||||
locationCategories: options.filter(o => o.locationType.id === id)[0].locationType.title.fr,
|
||||
locations: options.filter(o => o.locationType.id === id)
|
||||
locationCategories: response.filter(o => o.locationType.id === id)[0].locationType.title.fr,
|
||||
locations: response.filter(o => o.locationType.id === id)
|
||||
})
|
||||
}
|
||||
this.options = results;
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.open({message: error.txt})
|
||||
})
|
||||
},
|
||||
updateAdminLocation(value) {
|
||||
|
@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Serializer\Normalizer;
|
||||
use Chill\BudgetBundle\Service\Summary\SummaryBudgetInterface;
|
||||
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Civility;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
@ -87,6 +88,7 @@ class PersonDocGenNormalizer implements
|
||||
$dateContext['docgen:expects'] = DateTimeInterface::class;
|
||||
$addressContext = array_merge($context, ['docgen:expects' => Address::class]);
|
||||
$phonenumberContext = array_merge($context, ['docgen:expects' => PhoneNumber::class]);
|
||||
$centerContext = array_merge($context, ['docgen:expects' => Center::class]);
|
||||
$personResourceContext = array_merge($context, [
|
||||
'docgen:expects' => Person\PersonResource::class,
|
||||
// we simplify the list of attributes for the embedded persons
|
||||
@ -139,6 +141,7 @@ class PersonDocGenNormalizer implements
|
||||
'numberOfChildren' => (string) $person->getNumberOfChildren(),
|
||||
'address' => $this->normalizer->normalize($person->getCurrentPersonAddress(), $format, $addressContext),
|
||||
'resources' => $this->normalizer->normalize($person->getResources(), $format, $personResourceContext),
|
||||
'center' => $this->normalizer->normalize($person->getCenter(), $format, $centerContext),
|
||||
];
|
||||
|
||||
if ($context['docgen:person:with-household'] ?? false) {
|
||||
@ -240,6 +243,7 @@ class PersonDocGenNormalizer implements
|
||||
|
||||
$attributes = [
|
||||
'id', 'firstName', 'lastName', 'age', 'altNames', 'text',
|
||||
'center' => Center::class,
|
||||
'civility' => Civility::class,
|
||||
'birthdate' => DateTimeInterface::class,
|
||||
'deathdate' => DateTimeInterface::class,
|
||||
|
@ -13,16 +13,16 @@ namespace Chill\PersonBundle\Tests\Export\Aggregator\AccompanyingCourseAggregato
|
||||
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\JobAggregator;
|
||||
use Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\UserJobAggregator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
final class JobAggregatorTest extends AbstractAggregatorTest
|
||||
final class UserJobAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private JobAggregator $aggregator;
|
||||
private UserJobAggregator $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
@ -40,6 +40,7 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
|
||||
|
||||
private const BLANK = [
|
||||
'id' => '',
|
||||
'center' => '',
|
||||
'firstName' => '',
|
||||
'lastName' => '',
|
||||
'altNames' => '',
|
||||
@ -64,6 +65,7 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
|
||||
'numberOfChildren' => '',
|
||||
'age' => '@ignored',
|
||||
'resources' => [],
|
||||
'center' => '@ignored',
|
||||
];
|
||||
|
||||
private NormalizerInterface $normalizer;
|
||||
|
@ -136,7 +136,7 @@ services:
|
||||
- { name: chill.export_aggregator, alias: accompanyingcourse_scope_aggregator }
|
||||
|
||||
chill.person.export.aggregator_referrer_job:
|
||||
class: Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\JobAggregator
|
||||
class: Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\UserJobAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: accompanyingcourse_referrer_job_aggregator }
|
||||
|
||||
|
@ -1068,6 +1068,7 @@ export:
|
||||
by_referrer:
|
||||
Computation date for referrer: Date à laquelle le référent était actif
|
||||
having_temporarily:
|
||||
label: Qualité de la localisation
|
||||
Having a temporarily location: Ayant une localisation temporaire
|
||||
Having a person's location: Ayant une localisation auprès d'un usager
|
||||
Calculation date: Date de la localisation
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 3cb4c26fe774229b4c566cffd2d5f79bf6ca848b
|
||||
Subproject commit 5e478fdfbf429baf3ce852ae69eb1f7101b1b416
|
Loading…
x
Reference in New Issue
Block a user