Feature: [export] Add a list of accompanying periods

This commit is contained in:
Julien Fastré 2022-10-28 22:25:53 +02:00
parent bf58c5d59c
commit b5a9dac62e
13 changed files with 778 additions and 93 deletions

View File

@ -34,6 +34,8 @@ use Chill\MainBundle\Doctrine\DQL\Replace;
use Chill\MainBundle\Doctrine\DQL\Similarity;
use Chill\MainBundle\Doctrine\DQL\STContains;
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
use Chill\MainBundle\Doctrine\DQL\STX;
use Chill\MainBundle\Doctrine\DQL\STY;
use Chill\MainBundle\Doctrine\DQL\ToChar;
use Chill\MainBundle\Doctrine\DQL\Unaccent;
use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator;
@ -245,6 +247,8 @@ class ChillMainExtension extends Extension implements
'STRICT_WORD_SIMILARITY_OPS' => StrictWordSimilarityOPS::class,
'ST_CONTAINS' => STContains::class,
'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class,
'ST_X' => STX::class,
'ST_Y' => STY::class,
],
'datetime_functions' => [
'EXTRACT' => Extract::class,

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class STX extends FunctionNode
{
private $field;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf('ST_X(%s)', $this->field->dispatch($sqlWalker));
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class STY extends FunctionNode
{
private $field;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf('ST_Y(%s)', $this->field->dispatch($sqlWalker));
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Export\Helper;
use DateTime;
use Exception;
use Symfony\Contracts\Translation\TranslatorInterface;
class DateTimeHelper
{
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function getLabel($header): callable
{
return function ($value) use ($header) {
if ('_header' === $value) {
return $this->translator->trans($header);
}
if (null === $value) {
return '';
}
// warning: won't work with DateTimeImmutable as we reset time a few lines later
$date = DateTime::createFromFormat('Y-m-d', $value);
$hasTime = false;
if (false === $date) {
$date = DateTime::createFromFormat('Y-m-d H:i:s', $value);
$hasTime = true;
}
// check that the creation could occurs.
if (false === $date) {
throw new Exception(sprintf('The value %s could '
. 'not be converted to %s', $value, DateTime::class));
}
if (!$hasTime) {
$date->setTime(0, 0, 0);
}
return $date;
};
}
}

View File

@ -14,9 +14,11 @@ namespace Chill\MainBundle\Export\Helper;
use Chill\MainBundle\Repository\AddressRepository;
use Chill\MainBundle\Templating\Entity\AddressRender;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder;
use LogicException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use function in_array;
use function strlen;
/**
@ -24,6 +26,10 @@ use function strlen;
*/
class ExportAddressHelper
{
public const F_ALL =
self::F_ATTRIBUTES | self::F_BUILDING | self::F_COUNTRY |
self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET;
public const F_AS_STRING = 0b00010000;
public const F_ATTRIBUTES = 0b01000000;
@ -77,6 +83,87 @@ class ExportAddressHelper
$this->addressRender = $addressRender;
}
public function addSelectClauses(int $params, QueryBuilder $queryBuilder, $entityName = 'address', $prefix = 'add')
{
foreach (self::ALL as $key => $bitmask) {
if (($params & $bitmask) === $bitmask) {
foreach (self::COLUMN_MAPPING[$key] as $field) {
switch ($field) {
case 'id':
case '_as_string':
$queryBuilder->addSelect(sprintf('%s.id AS %s%s', $entityName, $prefix, $field));
break;
case 'street':
case 'streetNumber':
case 'building':
case 'floor':
case 'corridor':
case 'steps':
case 'buildingName':
case 'flat':
case 'distribution':
case 'extra':
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $entityName, $field, $prefix, $field));
break;
case 'country':
case 'postcode_name':
case 'postcode_code':
$postCodeAlias = sprintf('%spostcode_t', $prefix);
if (!in_array($postCodeAlias, $queryBuilder->getAllAliases(), true)) {
$queryBuilder->leftJoin($entityName . '.postcode', $postCodeAlias);
}
if ('postcode_name' === $field) {
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $postCodeAlias, 'name', $prefix, $field));
break;
}
if ('postcode_code' === $field) {
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $postCodeAlias, 'code', $prefix, $field));
break;
}
$countryAlias = sprintf('%scountry_t', $prefix);
if (!in_array($countryAlias, $queryBuilder->getAllAliases(), true)) {
$queryBuilder->leftJoin(sprintf('%s.country', $postCodeAlias), $countryAlias);
}
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $countryAlias, 'name', $prefix, $field));
break;
case 'isNoAddress':
case 'confidential':
$queryBuilder->addSelect(sprintf('CASE WHEN %s.%s = \'TRUE\' THEN 1 ELSE 0 END AS %s%s', $entityName, $field, $prefix, $field));
break;
case '_lat':
$queryBuilder->addSelect(sprintf('ST_Y(%s.point) AS %s%s', $entityName, $prefix, $field));
break;
case '_lon':
$queryBuilder->addSelect(sprintf('ST_X(%s.point) AS %s%s', $entityName, $prefix, $field));
break;
default:
throw new LogicException('This key is not supported: ' . $key);
}
}
}
}
}
/**
* @param self::F_* $params
*
@ -115,23 +202,11 @@ class ExportAddressHelper
case 'extra':
case 'flat':
case 'floor':
return function ($value) use ($sanitizedKey, $translationPrefix) {
if ('_header' === $value) {
return $translationPrefix . $sanitizedKey;
}
if (null === $value) {
return '';
}
$address = $this->addressRepository->find($value);
return $this->propertyAccess->getValue($address, $sanitizedKey);
};
case '_lat':
case '_lon':
return function ($value) use ($sanitizedKey, $translationPrefix) {
case 'postcode_code':
case 'postcode_name':
return static function ($value) use ($sanitizedKey, $translationPrefix) {
if ('_header' === $value) {
return $translationPrefix . $sanitizedKey;
}
@ -140,28 +215,25 @@ class ExportAddressHelper
return '';
}
$address = $this->addressRepository->find($value);
$geom = $address->getPoint();
return $value;
};
if (null === $geom) {
case 'country':
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp' . $key;
}
if (null === $value) {
return '';
}
switch ($sanitizedKey) {
case '_lat':
return $geom->getLat();
case '_lon':
return $geom->getLon();
default:
throw new LogicException('only _lat or _lon accepted, given: ' . $sanitizedKey);
}
return $this->translatableStringHelper->localize(json_decode($value, true));
};
case 'isNoAddress':
case 'confidential':
return function ($value) use ($sanitizedKey, $translationPrefix) {
return static function ($value) use ($sanitizedKey, $translationPrefix) {
if ('_header' === $value) {
return $translationPrefix . $sanitizedKey;
}
@ -170,9 +242,7 @@ class ExportAddressHelper
return '';
}
$address = $this->addressRepository->find($value);
switch ($val = $this->propertyAccess->getValue($address, $sanitizedKey)) {
switch ($value) {
case null:
return '';
@ -187,21 +257,6 @@ class ExportAddressHelper
}
};
case 'country':
return function ($value) use ($sanitizedKey, $translationPrefix) {
if ('_header' === $value) {
return $translationPrefix . $sanitizedKey;
}
if (null === $value) {
return '';
}
$address = $this->addressRepository->find($value);
return $this->translatableStringHelper->localize($address->getPostcode()->getCountry()->getName());
};
case '_as_string':
return function ($value) use ($sanitizedKey, $translationPrefix) {
if ('_header' === $value) {
@ -217,31 +272,6 @@ class ExportAddressHelper
return $this->addressRender->renderString($address, []);
};
case 'postcode_code':
case 'postcode_name':
return function ($value) use ($sanitizedKey, $translationPrefix) {
if ('_header' === $value) {
return $translationPrefix . $sanitizedKey;
}
if (null === $value) {
return '';
}
$address = $this->addressRepository->find($value);
switch ($sanitizedKey) {
case 'postcode_code':
return $address->getPostcode()->getCode();
case 'postcode_name':
return $address->getPostcode()->getName();
default:
throw new LogicException('this key is not supported: ' . $sanitizedKey);
}
};
default:
throw new LogicException('this key is not supported: ' . $sanitizedKey);
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Export\Helper;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Templating\Entity\UserRender;
class UserHelper
{
private UserRender $userRender;
private UserRepositoryInterface $userRepository;
public function __construct(UserRender $userRender, UserRepositoryInterface $userRepository)
{
$this->userRender = $userRender;
$this->userRepository = $userRepository;
}
public function getLabel($key, array $values, string $header): callable
{
return function ($value) use ($header) {
if ('_header' === $value) {
return $header;
}
if (null === $value || null === $user = $this->userRepository->find($value)) {
return '';
}
return $this->userRender->renderString($user, []);
};
}
}

View File

@ -38,7 +38,7 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface
public function buildForm(FormBuilderInterface $builder): void
{
// TODO: Implement buildForm() method.
// Nothing to add here
}
public function getAllowedFormattersTypes(): array

View File

@ -0,0 +1,416 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Export;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\Helper\DateTimeHelper;
use Chill\MainBundle\Export\Helper\ExportAddressHelper;
use Chill\MainBundle\Export\Helper\UserHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use DateTimeImmutable;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function strlen;
class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
{
private const FIELDS = [
'id',
'step',
'stepSince',
'openingDate',
'closingDate',
'referrer',
'referrerSince',
'administrativeLocation',
'locationIsPerson',
'locationIsTemp',
'locationPersonName',
'locationPersonId',
'origin',
'closingMotive',
'confidential',
'emergency',
'intensity',
'job',
'isRequestorPerson',
'isRequestorThirdParty',
'requestorPerson',
'requestorPersonId',
'requestorThirdParty',
'requestorThirdPartyId',
'scopes',
'socialIssues',
'createdAt',
'createdBy',
'updatedAt',
'updatedBy',
];
private ExportAddressHelper $addressHelper;
private DateTimeHelper $dateTimeHelper;
private EntityManagerInterface $entityManager;
private PersonRenderInterface $personRender;
private PersonRepository $personRepository;
private SocialIssueRender $socialIssueRender;
private SocialIssueRepository $socialIssueRepository;
private ThirdPartyRender $thirdPartyRender;
private ThirdPartyRepository $thirdPartyRepository;
private TranslatableStringHelperInterface $translatableStringHelper;
private UserHelper $userHelper;
public function __construct(
ExportAddressHelper $addressHelper,
DateTimeHelper $dateTimeHelper,
EntityManagerInterface $entityManager,
PersonRenderInterface $personRender,
PersonRepository $personRepository,
ThirdPartyRepository $thirdPartyRepository,
ThirdPartyRender $thirdPartyRender,
SocialIssueRepository $socialIssueRepository,
SocialIssueRender $socialIssueRender,
TranslatableStringHelperInterface $translatableStringHelper,
UserHelper $userHelper
) {
$this->addressHelper = $addressHelper;
$this->dateTimeHelper = $dateTimeHelper;
$this->entityManager = $entityManager;
$this->personRender = $personRender;
$this->personRepository = $personRepository;
$this->socialIssueRender = $socialIssueRender;
$this->socialIssueRepository = $socialIssueRepository;
$this->thirdPartyRender = $thirdPartyRender;
$this->thirdPartyRepository = $thirdPartyRepository;
$this->translatableStringHelper = $translatableStringHelper;
$this->userHelper = $userHelper;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('calc_date', ChillDateType::class, [
'input' => 'datetime_immutable',
'label' => 'export.list.acp.Date of calculation for associated elements',
'help' => 'export.list.acp.The associated referree, localisation, and other elements will be valid at this date',
'required' => true,
]);
}
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_LIST];
}
public function getDescription()
{
return 'export.list.acp.Generate a list of accompanying periods, filtered on different parameters.';
}
public function getGroup(): string
{
return 'Exports of accompanying courses';
}
public function getLabels($key, array $values, $data)
{
if (substr($key, 0, strlen('address_fields')) === 'address_fields') {
return $this->addressHelper->getLabel($key, $values, $data, 'address_fields');
}
switch ($key) {
case 'stepSince':
case 'openingDate':
case 'closingDate':
case 'referrerSince':
case 'createdAt':
case 'updatedAt':
return $this->dateTimeHelper->getLabel('export.list.acp.' . $key);
case 'origin':
case 'closingMotive':
case 'job':
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp.' . $key;
}
if (null === $value) {
return '';
}
return $this->translatableStringHelper->localize(json_decode($value, true));
};
case 'locationPersonName':
case 'requestorPerson':
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp.' . $key;
}
if (null === $value || null === $person = $this->personRepository->find($value)) {
return '';
}
return $this->personRender->renderString($person, []);
};
case 'requestorThirdParty':
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp.' . $key;
}
if (null === $value || null === $thirdparty = $this->thirdPartyRepository->find($value)) {
return '';
}
return $this->thirdPartyRender->renderString($thirdparty, []);
};
case 'scopes':
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp.' . $key;
}
if (null === $value) {
return '';
}
return implode(
'|',
array_map(
fn ($s) => $this->translatableStringHelper->localize($s),
json_decode($value, true)
)
);
};
case 'socialIssues':
return function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp.' . $key;
}
if (null === $value) {
return '';
}
return implode(
'|',
array_map(
fn ($s) => $this->socialIssueRender->renderString($this->socialIssueRepository->find($s), []),
json_decode($value, true)
)
);
};
default:
return static function ($value) use ($key) {
if ('_header' === $value) {
return 'export.list.acp.' . $key;
}
if (null === $value) {
return '';
}
return $value;
};
}
}
public function getQueryKeys($data)
{
return array_merge(
self::FIELDS,
$this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields')
);
}
public function getResult($query, $data)
{
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
}
public function getTitle()
{
return 'export.list.acp.List of accompanying periods';
}
public function getType()
{
return Declarations::PERSON_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->entityManager->createQueryBuilder();
$qb
->from(AccompanyingPeriod::class, 'acp')
->andWhere('acp.step != :list_acp_step')
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('list_acp_step', AccompanyingPeriod::STEP_DRAFT)
->setParameter('authorized_centers', $centers);
$this->addSelectClauses($qb, $data['calc_date']);
return $qb;
}
public function requiredRole(): string
{
return PersonVoter::LISTS;
}
public function supportsModifiers()
{
return [
Declarations::ACP_TYPE,
];
}
private function addSelectClauses(QueryBuilder $qb, DateTimeImmutable $calcDate): void
{
// add the regular fields
foreach (['id', 'openingDate', 'closingDate', 'confidential', 'emergency', 'intensity', 'createdAt', 'updatedAt'] as $field) {
$qb->addSelect(sprintf('acp.%s AS %s', $field, $field));
}
// add the field which are simple association
foreach (['origin' => 'label', 'closingMotive' => 'name', 'job' => 'label', 'createdBy' => 'label', 'updatedBy' => 'label', 'administrativeLocation' => 'name'] as $entity => $field) {
$qb
->leftJoin(sprintf('acp.%s', $entity), "{$entity}_t")
->addSelect(sprintf('%s_t.%s AS %s', $entity, $field, $entity));
}
// step at date
$qb
->addSelect('stepHistory.step AS step')
->addSelect('stepHistory.startDate AS stepSince')
->leftJoin('acp.stepHistories', 'stepHistory')
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte('stepHistory.startDate', ':calcDate'),
$qb->expr()->orX($qb->expr()->isNull('stepHistory.endDate'), $qb->expr()->gt('stepHistory.endDate', ':calcDate'))
)
);
// referree at date
$qb
->addSelect('referrer_t.label AS referrer')
->addSelect('userHistory.startDate AS referrerSince')
->leftJoin('acp.userHistories', 'userHistory')
->leftJoin('userHistory.user', 'referrer_t')
->andWhere(
$qb->expr()->orX(
$qb->expr()->isNull('userHistory'),
$qb->expr()->andX(
$qb->expr()->lte('userHistory.startDate', ':calcDate'),
$qb->expr()->orX($qb->expr()->isNull('userHistory.endDate'), $qb->expr()->gt('userHistory.endDate', ':calcDate'))
)
)
);
// location of the acp
$qb
->addSelect('CASE WHEN locationHistory.personLocation IS NOT NULL THEN 1 ELSE 0 END AS locationIsPerson')
->addSelect('CASE WHEN locationHistory.personLocation IS NOT NULL THEN 0 ELSE 1 END AS locationIsTemp')
->addSelect('IDENTITY(locationHistory.personLocation) AS locationPersonName')
->addSelect('IDENTITY(locationHistory.personLocation) AS locationPersonId')
->leftJoin('acp.locationHistories', 'locationHistory')
->andWhere(
$qb->expr()->orX(
$qb->expr()->isNull('locationHistory'),
$qb->expr()->andX(
$qb->expr()->lte('locationHistory.startDate', ':calcDate'),
$qb->expr()->orX($qb->expr()->isNull('locationHistory.endDate'), $qb->expr()->gt('locationHistory.endDate', ':calcDate'))
)
)
)
->leftJoin(PersonHouseholdAddress::class, 'personAddress', Join::WITH, 'locationHistory.personLocation = personAddress.person')
->andWhere(
$qb->expr()->orX(
$qb->expr()->isNull('personAddress'),
$qb->expr()->andX(
$qb->expr()->lte('personAddress.validFrom', ':calcDate'),
$qb->expr()->orX($qb->expr()->isNull('personAddress.validTo'), $qb->expr()->gt('personAddress.validTo', ':calcDate'))
)
)
)
->leftJoin(Address::class, 'acp_address', Join::WITH, 'COALESCE(IDENTITY(locationHistory.addressLocation), IDENTITY(personAddress.address)) = acp_address.id');
$this->addressHelper->addSelectClauses(ExportAddressHelper::F_ALL, $qb, 'acp_address', 'address_fields');
// requestor
$qb
->addSelect('CASE WHEN acp.requestorPerson IS NULL THEN 1 ELSE 0 END AS isRequestorPerson')
->addSelect('CASE WHEN acp.requestorPerson IS NULL THEN 0 ELSE 1 END AS isRequestorThirdParty')
->addSelect('IDENTITY(acp.requestorPerson) AS requestorPersonId')
->addSelect('IDENTITY(acp.requestorThirdParty) AS requestorThirdPartyId')
->addSelect('IDENTITY(acp.requestorPerson) AS requestorPerson')
->addSelect('IDENTITY(acp.requestorThirdParty) AS requestorThirdParty');
$qb
// scopes
->addSelect('(SELECT AGGREGATE(scope.name) FROM ' . Scope::class . ' scope WHERE scope MEMBER OF acp.scopes) AS scopes')
// social issues
->addSelect('(SELECT AGGREGATE(socialIssue.id) FROM ' . SocialIssue::class . ' socialIssue WHERE socialIssue MEMBER OF acp.socialIssues) AS socialIssues');
// add parameter
$qb->setParameter('calcDate', $calcDate);
}
}

View File

@ -153,7 +153,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
}
if (substr($key, 0, strlen('address_fields')) === 'address_fields') {
$fields = array_merge($fields, $this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields'));
$fields = array_merge($fields, $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields'));
continue;
}

View File

@ -17,6 +17,7 @@ use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\Helper\ExportAddressHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
@ -121,7 +122,7 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac
}
if (substr($key, 0, strlen('address_fields')) === 'address_fields') {
$fields = array_merge($fields, $this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields'));
$fields = array_merge($fields, $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields'));
continue;
}
@ -173,6 +174,7 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac
$qb->from(Person::class, 'person')
->join('person.accompanyingPeriodParticipations', 'acppart')
->join('acppart.accompanyingPeriod', 'acp')
->andWhere($qb->expr()->neq('acp.step', "'" . AccompanyingPeriod::STEP_DRAFT . "'"))
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)'

View File

@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Helper;
use Chill\MainBundle\Export\Helper\ExportAddressHelper;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\CivilityRepositoryInterface;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Repository\LanguageRepositoryInterface;
@ -72,16 +73,10 @@ class ListPersonHelper
'lifecycleUpdate',
];
public const HELPER_ATTRIBUTES = ExportAddressHelper::F_ATTRIBUTES |
ExportAddressHelper::F_BUILDING |
ExportAddressHelper::F_COUNTRY |
ExportAddressHelper::F_GEOM |
ExportAddressHelper::F_POSTAL_CODE |
ExportAddressHelper::F_STREET |
ExportAddressHelper::F_AS_STRING;
private ExportAddressHelper $addressHelper;
private CenterRepositoryInterface $centerRepository;
private CivilityRepositoryInterface $civilityRepository;
private CountryRepository $countryRepository;
@ -98,6 +93,7 @@ class ListPersonHelper
public function __construct(
ExportAddressHelper $addressHelper,
CenterRepositoryInterface $centerRepository,
CivilityRepositoryInterface $civilityRepository,
CountryRepository $countryRepository,
LanguageRepositoryInterface $languageRepository,
@ -107,6 +103,7 @@ class ListPersonHelper
UserRepositoryInterface $userRepository
) {
$this->addressHelper = $addressHelper;
$this->centerRepository = $centerRepository;
$this->civilityRepository = $civilityRepository;
$this->countryRepository = $countryRepository;
$this->languageRepository = $languageRepository;
@ -134,12 +131,9 @@ class ListPersonHelper
break;
case 'address_fields':
foreach ($this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields') as $key) {
$qb
->addSelect(sprintf('IDENTITY(personHouseholdAddress.address) AS %s', $key));
}
$this->addCurrentAddressAt($qb, $computedDate);
$qb->leftJoin('personHouseholdAddress.address', 'personAddress');
$this->addressHelper->addSelectClauses(ExportAddressHelper::F_ALL, $qb, 'personAddress', 'address_fields');
break;
@ -154,7 +148,10 @@ class ListPersonHelper
}
if (in_array('address_fields', $fields, true)) {
$qb->addGroupBy('address_fieldsid');
$qb
->addGroupBy('address_fieldsid')
->addGroupBy('address_fieldscountry_t.id')
->addGroupBy('address_fieldspostcode_t.id');
}
if (in_array('household_id', $fields, true)) {
@ -234,7 +231,7 @@ class ListPersonHelper
return array_merge(
self::FIELDS,
['createdAt', 'createdBy', 'updatedAt', 'updatedBy'],
$this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields')
$this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields')
);
}
@ -245,6 +242,19 @@ class ListPersonHelper
}
switch ($key) {
case 'center':
return function ($value) use ($key) {
if ('_header' === $value) {
return $this->translator->trans($key);
}
if (null === $value || null === $center = $this->centerRepository->find($value)) {
return '';
}
return $center->getName();
};
case 'birthdate':
case 'deathdate':
case 'maritalStatusDate':
@ -413,7 +423,7 @@ class ListPersonHelper
->leftJoin('person.householdAddresses', 'personHouseholdAddress')
->andWhere(
$qb->expr()->orX(
// no address at this time
// no address at this time
$qb->expr()->isNull('personHouseholdAddress'),
// there is one address...
$qb->expr()->andX(

View File

@ -27,6 +27,12 @@ services:
tags:
- { name: chill.export, alias: list_person_with_acp }
Chill\PersonBundle\Export\Export\ListAccompanyingPeriod:
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: list_acp }
chill.person.export.list_person.duplicate:
class: Chill\PersonBundle\Export\Export\ListPersonDuplicate
arguments:

View File

@ -1020,8 +1020,48 @@ export:
by_referrer:
Computation date for referrer: Date à laquelle le référent était actif
list:
person_with_acp.List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement
Create a list of people having an accompaying periods, according to various filters.: Génère une liste des personnes ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager
person_with_acp:
List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement
Create a list of people having an accompaying periods, according to various filters.: Génère une liste des personnes ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager
acp:
List of accompanying periods: Liste de périodes d'accompagnements
Generate a list of accompanying periods, filtered on different parameters.: Génère une liste des périodes d'accompagnement, filtrée sur différents paramètres.
Date of calculation for associated elements: Date de calcul des éléments associés
The associated referree, localisation, and other elements will be valid at this date: Les éléments associés, comme la localisation, le référent et d'autres éléments seront valides à cette date
id: Identifiant du parcours
openingDate: Date d'ouverture du parcours
closingDate: Date de fermeture du parcours
confidential: Confidentiel
emergency: Urgent
intensity: Intensité
createdAt: Créé le
updatedAt: Dernière mise à jour le
acpOrigin: Origine du parcours
acpClosingMotive: Motif de fermeture
acpJob: Métier du parcours
createdBy: Créé par
updatedBy: Dernière modification par
administrativeLocation: Location administrative
step: Etape
stepSince: Dernière modification de l'étape
referrer: Référent
referrerSince: Référent depuis le
locationIsPerson: Parcours localisé auprès d'un usager concerné
locationIsTemp: Parcours avec une localisation temporaire
acpLocationPersonName: Usager auprès duquel le parcours est localisé
locationPersonId: Identifiant de l'usager auprès duquel le parcours est localisé
acpaddress_fieldscountry: Pays de l'adresse
isRequestorPerson: Le demandeur est-il un usager ?
isRequestorThirdParty: Le demandeur est-il un tiers ?
requestorPersonId: Identifiant du demandeur personne
requestorThirdPartyId: Identifiant du tiers
acprequestorPerson: Nom du demandeur personne
acprequestorThirdPaty: Nom du demandeur tiers
scopes: Services
socialIssues: Problématiques sociales
social_action:
and children: et dérivés