mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
181 lines
7.4 KiB
PHP
181 lines
7.4 KiB
PHP
<?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\BudgetBundle\Service\Summary;
|
|
|
|
use Chill\BudgetBundle\Entity\ChargeKind;
|
|
use Chill\BudgetBundle\Entity\ResourceKind;
|
|
use Chill\BudgetBundle\Repository\ChargeKindRepositoryInterface;
|
|
use Chill\BudgetBundle\Repository\ResourceKindRepositoryInterface;
|
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
|
use Chill\PersonBundle\Entity\Household\Household;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Doctrine\ORM\Query\ResultSetMapping;
|
|
use LogicException;
|
|
use RuntimeException;
|
|
use function count;
|
|
|
|
/**
|
|
* Helps to find a summary of the budget: the sum of resources and charges.
|
|
*/
|
|
final class SummaryBudget implements SummaryBudgetInterface
|
|
{
|
|
private const QUERY_CHARGE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, charge_id AS kind_id FROM chill_budget.charge WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY charge_id';
|
|
|
|
private const QUERY_CHARGE_BY_PERSON = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, charge_id AS kind_id FROM chill_budget.charge WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY charge_id';
|
|
|
|
private const QUERY_RESOURCE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, resource_id AS kind_id FROM chill_budget.resource WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY resource_id';
|
|
|
|
private const QUERY_RESOURCE_BY_PERSON = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, resource_id AS kind_id FROM chill_budget.resource WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY resource_id';
|
|
|
|
private ChargeKindRepositoryInterface $chargeKindRepository;
|
|
|
|
private EntityManagerInterface $em;
|
|
|
|
private ResourceKindRepositoryInterface $resourceKindRepository;
|
|
|
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
|
|
|
public function __construct(
|
|
EntityManagerInterface $em,
|
|
TranslatableStringHelperInterface $translatableStringHelper,
|
|
ResourceKindRepositoryInterface $resourceKindRepository,
|
|
ChargeKindRepositoryInterface $chargeKindRepository
|
|
) {
|
|
$this->em = $em;
|
|
$this->translatableStringHelper = $translatableStringHelper;
|
|
$this->resourceKindRepository = $resourceKindRepository;
|
|
$this->chargeKindRepository = $chargeKindRepository;
|
|
}
|
|
|
|
public function getSummaryForHousehold(?Household $household): array
|
|
{
|
|
if (null === $household) {
|
|
return [
|
|
'resources' => $this->getEmptyResourceArray(),
|
|
'charges' => $this->getEmptyChargeArray(),
|
|
];
|
|
}
|
|
|
|
$personIds = $household->getCurrentPersons()->map(static fn (Person $p) => $p->getId());
|
|
$ids = implode(', ', array_fill(0, count($personIds), '?'));
|
|
|
|
$parameters = [...$personIds, $household->getId()];
|
|
|
|
$rsm = $this->buildRsm();
|
|
|
|
$resources = $this->em->createNativeQuery(strtr(self::QUERY_RESOURCE_BY_HOUSEHOLD, ['_ids_' => $ids]), $rsm)
|
|
->setParameters($parameters)
|
|
->getResult();
|
|
$charges = $this->em->createNativeQuery(strtr(self::QUERY_CHARGE_BY_HOUSEHOLD, ['_ids_' => $ids]), $rsm)
|
|
->setParameters($parameters)
|
|
->getResult();
|
|
|
|
return [
|
|
'resources' => array_merge($this->getEmptyResourceArray(), $this->rowToArray($resources, 'resource')),
|
|
'charges' => array_merge($this->getEmptyChargeArray(), $this->rowToArray($charges, 'charge')),
|
|
];
|
|
}
|
|
|
|
public function getSummaryForPerson(?Person $person): array
|
|
{
|
|
if (null === $person) {
|
|
return [
|
|
'resources' => $this->getEmptyResourceArray(),
|
|
'charges' => $this->getEmptyChargeArray(),
|
|
];
|
|
}
|
|
|
|
$rsm = $this->buildRsm();
|
|
|
|
$resources = $this->em->createNativeQuery(self::QUERY_RESOURCE_BY_PERSON, $rsm)
|
|
->setParameters([$person->getId()])
|
|
->getResult();
|
|
$charges = $this->em->createNativeQuery(self::QUERY_CHARGE_BY_PERSON, $rsm)
|
|
->setParameters([$person->getId()])
|
|
->getResult();
|
|
|
|
return [
|
|
'resources' => array_merge($this->getEmptyResourceArray(), $this->rowToArray($resources, 'resource')),
|
|
'charges' => array_merge($this->getEmptyChargeArray(), $this->rowToArray($charges, 'charge')),
|
|
];
|
|
}
|
|
|
|
private function buildRsm(): ResultSetMapping
|
|
{
|
|
$rsm = new ResultSetMapping();
|
|
$rsm
|
|
->addScalarResult('sum', 'sum')
|
|
->addScalarResult('kind_id', 'kind_id')
|
|
->addScalarResult('comment', 'comment');
|
|
|
|
return $rsm;
|
|
}
|
|
|
|
private function getEmptyChargeArray(): array
|
|
{
|
|
$keys = array_map(static fn (ChargeKind $kind) => $kind->getKind(), $this->chargeKindRepository->findAll());
|
|
|
|
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
|
|
}
|
|
|
|
private function getEmptyResourceArray(): array
|
|
{
|
|
$keys = array_map(static fn (ResourceKind $kind) => $kind->getKind(), $this->resourceKindRepository->findAll());
|
|
|
|
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
|
|
}
|
|
|
|
private function rowToArray(array $rows, string $kind): array
|
|
{
|
|
$result = [];
|
|
|
|
switch ($kind) {
|
|
case 'charge':
|
|
foreach ($rows as $row) {
|
|
$chargeKind = $this->chargeKindRepository->find($row['kind_id']);
|
|
|
|
if (null === $chargeKind) {
|
|
throw new RuntimeException('charge kind not found: ' . $row['kind_id']);
|
|
}
|
|
$result[$chargeKind->getKind()] = [
|
|
'sum' => (float) $row['sum'],
|
|
'label' => $this->translatableStringHelper->localize($chargeKind->getName()),
|
|
'comment' => (string) $row['comment'],
|
|
];
|
|
}
|
|
|
|
return $result;
|
|
|
|
case 'resource':
|
|
foreach ($rows as $row) {
|
|
$resourceKind = $this->resourceKindRepository->find($row['kind_id']);
|
|
|
|
if (null === $resourceKind) {
|
|
throw new RuntimeException('charge kind not found: ' . $row['kind_id']);
|
|
}
|
|
|
|
$result[$resourceKind->getKind()] = [
|
|
'sum' => (float) $row['sum'],
|
|
'label' => $this->translatableStringHelper->localize($resourceKind->getName()),
|
|
'comment' => (string) $row['comment'],
|
|
];
|
|
}
|
|
|
|
return $result;
|
|
|
|
default:
|
|
throw new LogicException();
|
|
}
|
|
}
|
|
}
|