mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'master' into use_crud_for_center
This commit is contained in:
commit
9600543fec
6
.changes/unreleased/Feature-20230817-131059.yaml
Normal file
6
.changes/unreleased/Feature-20230817-131059.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Add locations in Aside Activity. By default, suggest user location, otherwise
|
||||||
|
a select with all locations.
|
||||||
|
time: 2023-08-17T13:10:59.152278661+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "133"
|
6
.changes/unreleased/Feature-20230817-131152.yaml
Normal file
6
.changes/unreleased/Feature-20230817-131152.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: 'Adapt Aside Activity exports: display location, filter by location, group by
|
||||||
|
location'
|
||||||
|
time: 2023-08-17T13:11:52.911356021+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "133"
|
5
.changes/unreleased/Fixed-20230817-131239.yaml
Normal file
5
.changes/unreleased/Fixed-20230817-131239.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Missing translation in Work Actions exports
|
||||||
|
time: 2023-08-17T13:12:39.159627128+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
6
.changes/unreleased/Fixed-20230822-142809.yaml
Normal file
6
.changes/unreleased/Fixed-20230822-142809.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: "Corrects a typing error in 2 filters, which caused an \nerror when trying to
|
||||||
|
reedit a saved export\n\n"
|
||||||
|
time: 2023-08-22T14:28:09.485466139+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "135"
|
6
.changes/unreleased/Fixed-20230829-181332.yaml
Normal file
6
.changes/unreleased/Fixed-20230829-181332.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: '[household] when moving a person to a sharing position to a not-sharing position
|
||||||
|
on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.'
|
||||||
|
time: 2023-08-29T18:13:32.799479781+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "136"
|
6
.changes/unreleased/Fixed-20230829-181837.yaml
Normal file
6
.changes/unreleased/Fixed-20230829-181837.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: |
|
||||||
|
Add missing translation for comment field placeholder in repositionning household editor.
|
||||||
|
time: 2023-08-29T18:18:37.691526331+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
5
.changes/unreleased/Fixed-20230906-154856.yaml
Normal file
5
.changes/unreleased/Fixed-20230906-154856.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Do not send an email to creator twice when adding a comment to a notification
|
||||||
|
time: 2023-09-06T15:48:56.991246312+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
6
.changes/unreleased/UX-20230829-181733.yaml
Normal file
6
.changes/unreleased/UX-20230829-181733.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: UX
|
||||||
|
body: |
|
||||||
|
Uniformize badge-person in household banner (background, size)
|
||||||
|
time: 2023-08-29T18:17:33.190396543+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
@ -94,7 +94,7 @@ class CountPerson implements ExportInterface
|
|||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
// we gather all center the user choose.
|
// we gather all center the user choose.
|
||||||
$centers = array_map(static fn($el) => $el['center'], $acl);
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
|
|
||||||
$qb = $this->entityManager->createQueryBuilder();
|
$qb = $this->entityManager->createQueryBuilder();
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class ChillMainConfiguration implements ConfigurationInterface
|
|||||||
->end() // end of widgets
|
->end() // end of widgets
|
||||||
->end() // end of root/children
|
->end() // end of root/children
|
||||||
->end() // end of root
|
->end() // end of root
|
||||||
;
|
;
|
||||||
|
|
||||||
return $treeBuilder;
|
return $treeBuilder;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
|
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
|
||||||
use Rector\Config\RectorConfig;
|
use Rector\Config\RectorConfig;
|
||||||
use Rector\Set\ValueObject\LevelSetList;
|
use Rector\Set\ValueObject\LevelSetList;
|
||||||
|
@ -320,7 +320,6 @@ final class ActivityController extends AbstractController
|
|||||||
|
|
||||||
private function buildFilterOrder(AccompanyingPeriod|Person $associated): FilterOrderHelper
|
private function buildFilterOrder(AccompanyingPeriod|Person $associated): FilterOrderHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
$filterBuilder = $this->filterOrderHelperFactory->create(self::class);
|
$filterBuilder = $this->filterOrderHelperFactory->create(self::class);
|
||||||
$types = $this->activityACLAwareRepository->findActivityTypeByAssociated($associated);
|
$types = $this->activityACLAwareRepository->findActivityTypeByAssociated($associated);
|
||||||
$jobs = $this->activityACLAwareRepository->findUserJobByAssociated($associated);
|
$jobs = $this->activityACLAwareRepository->findUserJobByAssociated($associated);
|
||||||
|
@ -22,11 +22,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||||||
class EmergencyFilter implements FilterInterface
|
class EmergencyFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
private const CHOICES = [
|
private const CHOICES = [
|
||||||
'activity is emergency' => true,
|
'activity is emergency' => 'true',
|
||||||
'activity is not emergency' => false,
|
'activity is not emergency' => 'false',
|
||||||
];
|
];
|
||||||
|
|
||||||
private const DEFAULT_CHOICE = false;
|
private const DEFAULT_CHOICE = 'false';
|
||||||
|
|
||||||
private TranslatorInterface $translator;
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ final readonly class ActivityACLAwareRepository implements ActivityACLAwareRepos
|
|||||||
$counter++;
|
$counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
|
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
|
||||||
if (!$this->security->isGranted(ActivityVoter::SEE, $participation->getAccompanyingPeriod())) {
|
if (!$this->security->isGranted(ActivityVoter::SEE, $participation->getAccompanyingPeriod())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -122,5 +122,4 @@ class ActivityDocumentACLAwareRepositoryTest extends KernelTestCase
|
|||||||
yield [$person, $scopes, true, null, new \DateTimeImmutable("1 week ago"), "content"];
|
yield [$person, $scopes, true, null, new \DateTimeImmutable("1 week ago"), "content"];
|
||||||
yield [$person, [], true, new \DateTimeImmutable("1 month ago"), new \DateTimeImmutable("1 week ago"), "content"];
|
yield [$person, [], true, new \DateTimeImmutable("1 month ago"), new \DateTimeImmutable("1 week ago"), "content"];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ final class AsideActivityController extends CRUDController
|
|||||||
$asideActivity = new AsideActivity();
|
$asideActivity = new AsideActivity();
|
||||||
|
|
||||||
$asideActivity->setAgent($this->getUser());
|
$asideActivity->setAgent($this->getUser());
|
||||||
|
$asideActivity->setLocation($this->getUser()->getCurrentLocation());
|
||||||
|
|
||||||
$duration = $request->query->get('duration', '300');
|
$duration = $request->query->get('duration', '300');
|
||||||
$duration = DateTime::createFromFormat('U', $duration);
|
$duration = DateTime::createFromFormat('U', $duration);
|
||||||
|
@ -14,6 +14,7 @@ namespace Chill\AsideActivityBundle\Entity;
|
|||||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Entity\Location;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
@ -60,9 +61,10 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
private ?int $id = null;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=100, nullable=true)
|
* @ORM\ManyToOne(targetEntity=Location::class)
|
||||||
|
* @ORM\JoinColumn(nullable=true)
|
||||||
*/
|
*/
|
||||||
private $location;
|
private ?Location $location = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="text", nullable=true)
|
* @ORM\Column(type="text", nullable=true)
|
||||||
@ -115,7 +117,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLocation(): ?string
|
public function getLocation(): ?Location
|
||||||
{
|
{
|
||||||
return $this->location;
|
return $this->location;
|
||||||
}
|
}
|
||||||
@ -175,7 +177,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLocation(?string $location): self
|
public function setLocation(?Location $location): self
|
||||||
{
|
{
|
||||||
$this->location = $location;
|
$this->location = $location;
|
||||||
|
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
<?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\LocationRepository;
|
||||||
|
use Closure;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class ByLocationAggregator implements AggregatorInterface
|
||||||
|
{
|
||||||
|
public function __construct(private LocationRepository $locationRepository)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
// no form
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
return function ($value): string {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'export.aggregator.Aside activity localisation';
|
||||||
|
}
|
||||||
|
if (null === $value || '' === $value || null === $l = $this->locationRepository->find($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $l->getName();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['by_aside_activity_location_aggregator'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.aggregator.Group by aside activity location';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data): void
|
||||||
|
{
|
||||||
|
$qb->addSelect('IDENTITY(aside.location) AS by_aside_activity_location_aggregator')
|
||||||
|
->addGroupBy('by_aside_activity_location_aggregator');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ use Chill\MainBundle\Export\Helper\DateTimeHelper;
|
|||||||
use Chill\MainBundle\Export\Helper\UserHelper;
|
use Chill\MainBundle\Export\Helper\UserHelper;
|
||||||
use Chill\MainBundle\Export\ListInterface;
|
use Chill\MainBundle\Export\ListInterface;
|
||||||
use Chill\MainBundle\Repository\CenterRepositoryInterface;
|
use Chill\MainBundle\Repository\CenterRepositoryInterface;
|
||||||
|
use Chill\MainBundle\Repository\LocationRepository;
|
||||||
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
@ -58,6 +59,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
|||||||
CenterRepositoryInterface $centerRepository,
|
CenterRepositoryInterface $centerRepository,
|
||||||
AsideActivityCategoryRepository $asideActivityCategoryRepository,
|
AsideActivityCategoryRepository $asideActivityCategoryRepository,
|
||||||
CategoryRender $categoryRender,
|
CategoryRender $categoryRender,
|
||||||
|
private LocationRepository $locationRepository,
|
||||||
TranslatableStringHelperInterface $translatableStringHelper
|
TranslatableStringHelperInterface $translatableStringHelper
|
||||||
) {
|
) {
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
@ -73,6 +75,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
|||||||
public function buildForm(FormBuilderInterface $builder)
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormDefaultData(): array
|
public function getFormDefaultData(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
@ -145,6 +148,19 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
|||||||
return $this->categoryRender->renderString($c, []);
|
return $this->categoryRender->renderString($c, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case 'location':
|
||||||
|
return function ($value) {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'export.aside_activity.location';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value || '' === $value || null === $l = $this->locationRepository->find($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $l->getName();
|
||||||
|
};
|
||||||
|
|
||||||
case 'main_scope':
|
case 'main_scope':
|
||||||
return function ($value) {
|
return function ($value) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
@ -191,6 +207,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
|||||||
'date',
|
'date',
|
||||||
'duration',
|
'duration',
|
||||||
'note',
|
'note',
|
||||||
|
'location',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +243,7 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
|||||||
->addSelect('IDENTITY(aside.type) AS aside_activity_type')
|
->addSelect('IDENTITY(aside.type) AS aside_activity_type')
|
||||||
->addSelect('aside.date')
|
->addSelect('aside.date')
|
||||||
->addSelect('aside.duration')
|
->addSelect('aside.duration')
|
||||||
|
->addSelect('IDENTITY(aside.location) AS location')
|
||||||
->addSelect('aside.note');
|
->addSelect('aside.note');
|
||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
<?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\Entity\Location;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\MainBundle\Form\Type\PickUserLocationType;
|
||||||
|
use Chill\MainBundle\Repository\LocationRepository;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
final readonly class ByLocationFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private Security $security
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.Filter by aside activity location';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('locations', PickUserLocationType::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
if ($user instanceof User) {
|
||||||
|
return [
|
||||||
|
'locations' => $user->getCurrentLocation(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'locations' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function describeAction($data, $format = 'string'): array
|
||||||
|
{
|
||||||
|
$locations = $data['locations']->map(fn (Location $l): string => $l->getName());
|
||||||
|
|
||||||
|
return ['export.filter.Filtered by aside activity location: only %location%', [
|
||||||
|
'%location%' => implode(', ', $locations),
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data): void
|
||||||
|
{
|
||||||
|
$clause = $qb->expr()->in('aside.location', ':locations');
|
||||||
|
|
||||||
|
$qb->andWhere($clause);
|
||||||
|
$qb->setParameter('locations', $data['locations']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
}
|
@ -13,13 +13,16 @@ namespace Chill\AsideActivityBundle\Form;
|
|||||||
|
|
||||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
use Chill\AsideActivityBundle\Form\Type\PickAsideActivityCategoryType;
|
use Chill\AsideActivityBundle\Form\Type\PickAsideActivityCategoryType;
|
||||||
|
use Chill\MainBundle\Entity\Location;
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||||
|
use Chill\MainBundle\Form\Type\PickUserLocationType;
|
||||||
use DateInterval;
|
use DateInterval;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
||||||
@ -77,7 +80,9 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
->add('note', ChillTextareaType::class, [
|
->add('note', ChillTextareaType::class, [
|
||||||
'label' => 'Note',
|
'label' => 'Note',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
]);
|
])
|
||||||
|
->add('location', PickUserLocationType::class)
|
||||||
|
;
|
||||||
|
|
||||||
foreach (['duration'] as $fieldName) {
|
foreach (['duration'] as $fieldName) {
|
||||||
$builder->get($fieldName)
|
$builder->get($fieldName)
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{%- if entity.location.name is defined -%}
|
||||||
|
<div><i class="fa fa-fw fa-map-marker"></i>{{ entity.location.name }}</div>
|
||||||
|
{%- endif -%}
|
||||||
</div>
|
</div>
|
||||||
<div class="item-col" style="justify-content: flex-end;">
|
<div class="item-col" style="justify-content: flex-end;">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
@ -22,6 +22,13 @@
|
|||||||
|
|
||||||
<dt class="inline">{{ 'Created for'|trans }}</dt>
|
<dt class="inline">{{ 'Created for'|trans }}</dt>
|
||||||
<dd>{{ entity.agent }}</dd>
|
<dd>{{ entity.agent }}</dd>
|
||||||
|
|
||||||
|
<dt class="inline">{{ 'Asideactivity location'|trans }}</dt>
|
||||||
|
{%- if entity.location.name is defined -%}
|
||||||
|
<dd>{{ entity.location.name }}</dd>
|
||||||
|
{%- else -%}
|
||||||
|
<dd><span class="chill-no-data-statement">{{ 'No data given'|trans }}</span></dd>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
||||||
|
|
||||||
|
@ -46,19 +46,27 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export_filter, alias: 'aside_activity_user_filter' }
|
- { name: chill.export_filter, alias: 'aside_activity_user_filter' }
|
||||||
|
|
||||||
|
Chill\AsideActivityBundle\Export\Filter\ByLocationFilter:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: 'aside_activity_location_filter' }
|
||||||
|
|
||||||
## Aggregators
|
## Aggregators
|
||||||
|
|
||||||
chill.aside_activity.export.type_aggregator:
|
chill.aside_activity.export.type_aggregator:
|
||||||
class: Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator
|
class: Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_type_aggregator }
|
- { name: chill.export_aggregator, alias: 'activity_type_aggregator' }
|
||||||
|
|
||||||
chill.aside_activity.export.user_job_aggregator:
|
chill.aside_activity.export.user_job_aggregator:
|
||||||
class: Chill\AsideActivityBundle\Export\Aggregator\ByUserJobAggregator
|
class: Chill\AsideActivityBundle\Export\Aggregator\ByUserJobAggregator
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: aside_activity_user_job_aggregator }
|
- { name: chill.export_aggregator, alias: 'aside_activity_user_job_aggregator' }
|
||||||
|
|
||||||
chill.aside_activity.export.user_scope_aggregator:
|
chill.aside_activity.export.user_scope_aggregator:
|
||||||
class: Chill\AsideActivityBundle\Export\Aggregator\ByUserScopeAggregator
|
class: Chill\AsideActivityBundle\Export\Aggregator\ByUserScopeAggregator
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: aside_activity_user_scope_aggregator }
|
- { name: chill.export_aggregator, alias: 'aside_activity_user_scope_aggregator' }
|
||||||
|
|
||||||
|
Chill\AsideActivityBundle\Export\Aggregator\ByLocationAggregator:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: 'aside_activity_location_aggregator' }
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\Migrations\AsideActivity;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20230816112809 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Update location attribute in asideactivity';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('DROP INDEX chill_asideactivity.IDX_A866DA0E64D218E');
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP CONSTRAINT FK_A866DA0E64D218E');
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP location_id');
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD location VARCHAR(100) DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ADD location_id INT DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity DROP location');
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ADD CONSTRAINT FK_A866DA0E64D218E FOREIGN KEY (location_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('CREATE INDEX IDX_A866DA0E64D218E ON chill_asideactivity.asideactivity (location_id)');
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ Users: Utilisateurs
|
|||||||
Emergency: Urgent
|
Emergency: Urgent
|
||||||
by: "Par "
|
by: "Par "
|
||||||
location: Lieu
|
location: Lieu
|
||||||
|
Asideactivity location: Localisation de l'activité
|
||||||
|
|
||||||
# Crud
|
# Crud
|
||||||
crud:
|
crud:
|
||||||
@ -182,6 +183,7 @@ export:
|
|||||||
duration: Durée
|
duration: Durée
|
||||||
note: Note
|
note: Note
|
||||||
id: Identifiant
|
id: Identifiant
|
||||||
|
location: Localisation
|
||||||
|
|
||||||
Exports of aside activities: Exports des activités annexes
|
Exports of aside activities: Exports des activités annexes
|
||||||
Count aside activities: Nombre d'activités annexes
|
Count aside activities: Nombre d'activités annexes
|
||||||
@ -202,11 +204,16 @@ export:
|
|||||||
Filter by user jobs: Filtrer les activités annexes par métier des utilisateurs
|
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%"
|
'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
|
Filter by user scope: Filtrer les activités annexes par service d'utilisateur
|
||||||
|
Filter by aside activity location: Filtrer les activités annexes par localisation
|
||||||
|
'Filtered by aside activity location: only %location%': "Filtré par localisation: uniquement %location%"
|
||||||
aggregator:
|
aggregator:
|
||||||
Group by aside activity type: Grouper les activités annexes par type d'activité
|
Group by aside activity type: Grouper les activités annexes par type d'activité
|
||||||
Aside activity type: Type d'activité annexe
|
Aside activity type: Type d'activité annexe
|
||||||
Aggregate by user job: Grouper les activités annexes par métier des utilisateurs
|
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
|
Aggregate by user scope: Grouper les activités annexes par service des utilisateurs
|
||||||
|
Aside activity location: Localisation des activités annexe
|
||||||
|
Group by aside activity location: Grouper les activités annexes par localisation
|
||||||
|
Aside activity localisation: Localisation
|
||||||
|
|
||||||
# ROLES
|
# ROLES
|
||||||
CHILL_ASIDE_ACTIVITY_STATS: Statistiques pour les activités annexes
|
CHILL_ASIDE_ACTIVITY_STATS: Statistiques pour les activités annexes
|
||||||
|
@ -29,11 +29,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||||||
class CalendarRangeFilter implements FilterInterface
|
class CalendarRangeFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
private const CHOICES = [
|
private const CHOICES = [
|
||||||
'Not made within a calendar range' => true,
|
'Not made within a calendar range' => 'true',
|
||||||
'Made within a calendar range' => false,
|
'Made within a calendar range' => 'false',
|
||||||
];
|
];
|
||||||
|
|
||||||
private const DEFAULT_CHOICE = false;
|
private const DEFAULT_CHOICE = 'false';
|
||||||
|
|
||||||
private TranslatorInterface $translator;
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
@ -65,5 +65,4 @@ final readonly class MSUserAbsenceReader implements MSUserAbsenceReaderInterface
|
|||||||
default => throw new UserAbsenceSyncException("this status is not documented by Microsoft")
|
default => throw new UserAbsenceSyncException("this status is not documented by Microsoft")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -190,6 +190,4 @@ final readonly class AccompanyingPeriodCalendarGenericDocProvider implements Gen
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -172,5 +172,4 @@ class MSUserAbsenceReaderTest extends TestCase
|
|||||||
"User is absent: absence is always enabled"
|
"User is absent: absence is always enabled"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -94,5 +94,4 @@ final readonly class GenericDocForAccompanyingPeriodController
|
|||||||
]
|
]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -91,5 +91,4 @@ final readonly class GenericDocForPerson
|
|||||||
]
|
]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,6 @@ class FetchQuery implements FetchQueryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
unset($this->wheres[$index], $this->whereParams[$index], $this->whereTypes[$index]);
|
unset($this->wheres[$index], $this->whereParams[$index], $this->whereTypes[$index]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeJoinClause(int $index): void
|
public function removeJoinClause(int $index): void
|
||||||
@ -92,7 +91,6 @@ class FetchQuery implements FetchQueryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
unset($this->joins[$index], $this->joinParams[$index], $this->joinTypes[$index]);
|
unset($this->joins[$index], $this->joinParams[$index], $this->joinTypes[$index]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSelectKeyString(): string
|
public function getSelectKeyString(): string
|
||||||
|
@ -27,5 +27,4 @@ interface GenericDocForAccompanyingPeriodProviderInterface
|
|||||||
* Return true if the user is allowed to see some documents for this provider.
|
* Return true if the user is allowed to see some documents for this provider.
|
||||||
*/
|
*/
|
||||||
public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool;
|
public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -143,5 +143,4 @@ final readonly class AccompanyingCourseDocumentGenericDocProvider implements Gen
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,5 +46,4 @@ final readonly class GenericDocExtensionRuntime implements RuntimeExtensionInter
|
|||||||
|
|
||||||
throw new \LogicException("no renderer found");
|
throw new \LogicException("no renderer found");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,4 @@ interface GenericDocRendererInterface
|
|||||||
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string;
|
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string;
|
||||||
|
|
||||||
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array;
|
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,6 @@ final readonly class PersonDocumentACLAwareRepository implements PersonDocumentA
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$orPersonId[] = $participation->getPerson()->getId();
|
$orPersonId[] = $participation->getPerson()->getId();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([] === $orPersonId) {
|
if ([] === $orPersonId) {
|
||||||
|
@ -54,9 +54,6 @@ class FetchQueryToSqlBuilderTest extends KernelTestCase
|
|||||||
);
|
);
|
||||||
self::assertEquals(['foo', 'bar_baz', 'baz'], $params);
|
self::assertEquals(['foo', 'bar_baz', 'baz'], $params);
|
||||||
self::assertEquals([Types::STRING, Types::STRING, Types::STRING], $types);
|
self::assertEquals([Types::STRING, Types::STRING, Types::STRING], $types);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testToSqlWithoutWhere(): void
|
public function testToSqlWithoutWhere(): void
|
||||||
@ -85,5 +82,4 @@ class FetchQueryToSqlBuilderTest extends KernelTestCase
|
|||||||
self::assertEquals([], $params);
|
self::assertEquals([], $params);
|
||||||
self::assertEquals([], $types);
|
self::assertEquals([], $types);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,6 @@ class PersonDocumentACLAwareRepositoryTest extends KernelTestCase
|
|||||||
yield [$period, new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), null];
|
yield [$period, new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), null];
|
||||||
yield [$period, null, null, 'test'];
|
yield [$period, null, null, 'test'];
|
||||||
yield [$period, new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test'];
|
yield [$period, new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test'];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideDataBuildFetchQueryForPerson(): iterable
|
public function provideDataBuildFetchQueryForPerson(): iterable
|
||||||
@ -154,5 +153,4 @@ class PersonDocumentACLAwareRepositoryTest extends KernelTestCase
|
|||||||
yield [null, null, 'test'];
|
yield [null, null, 'test'];
|
||||||
yield [new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test'];
|
yield [new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test'];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ class EventSearch extends AbstractSearch
|
|||||||
$orWhere = $qb->expr()->orX();
|
$orWhere = $qb->expr()->orX();
|
||||||
|
|
||||||
foreach ($reachableCenters as $center) {
|
foreach ($reachableCenters as $center) {
|
||||||
$n = $n+1;
|
$n = $n + 1;
|
||||||
$circles = $this->authorizationHelper->getReachableScopes(
|
$circles = $this->authorizationHelper->getReachableScopes(
|
||||||
$this->security->getUser(),
|
$this->security->getUser(),
|
||||||
'CHILL_EVENT_SEE',
|
'CHILL_EVENT_SEE',
|
||||||
|
@ -88,7 +88,6 @@ class CronManager implements CronManagerInterface
|
|||||||
foreach ($orderedJobs as $job) {
|
foreach ($orderedJobs as $job) {
|
||||||
if ($job->canRun($lasts[$job->getKey()] ?? null)) {
|
if ($job->canRun($lasts[$job->getKey()] ?? null)) {
|
||||||
if (array_key_exists($job->getKey(), $lasts)) {
|
if (array_key_exists($job->getKey(), $lasts)) {
|
||||||
|
|
||||||
$executionData = $lasts[$job->getKey()]->getLastExecutionData();
|
$executionData = $lasts[$job->getKey()]->getLastExecutionData();
|
||||||
|
|
||||||
$this->entityManager
|
$this->entityManager
|
||||||
|
@ -122,7 +122,6 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType
|
|||||||
foreach ($helper->getUserPickers() as $name => [
|
foreach ($helper->getUserPickers() as $name => [
|
||||||
'label' => $label, 'options' => $opts
|
'label' => $label, 'options' => $opts
|
||||||
]) {
|
]) {
|
||||||
|
|
||||||
$userPickersBuilder->add(
|
$userPickersBuilder->add(
|
||||||
$name,
|
$name,
|
||||||
PickUserDynamicType::class,
|
PickUserDynamicType::class,
|
||||||
@ -136,7 +135,6 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType
|
|||||||
|
|
||||||
$builder->add($userPickersBuilder);
|
$builder->add($userPickersBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function buildCheckboxChoices(array $choices, array $trans = []): array
|
public static function buildCheckboxChoices(array $choices, array $trans = []): array
|
||||||
|
@ -40,13 +40,18 @@ class NotificationMailer
|
|||||||
|
|
||||||
public function postPersistComment(NotificationComment $comment, PostPersistEventArgs $eventArgs): void
|
public function postPersistComment(NotificationComment $comment, PostPersistEventArgs $eventArgs): void
|
||||||
{
|
{
|
||||||
foreach (
|
$dests = [$comment->getNotification()->getSender(), ...$comment->getNotification()->getAddressees()->toArray()];
|
||||||
array_merge(
|
|
||||||
$comment->getNotification()->getAddressees()->toArray(),
|
$uniqueDests = [];
|
||||||
[$comment->getNotification()->getSender()]
|
foreach ($dests as $dest) {
|
||||||
) as $dest
|
// avoid duplication
|
||||||
) {
|
if (in_array(spl_object_hash($dest), $uniqueDests, true)) {
|
||||||
if (null === $dest->getEmail() || $comment->getCreatedBy() !== $dest) {
|
continue;
|
||||||
|
}
|
||||||
|
$uniqueDests[] = spl_object_hash($dest);
|
||||||
|
|
||||||
|
// do not send if the sender does not have any email, nor to the creator of the comment
|
||||||
|
if (null === $dest->getEmail() || $comment->getCreatedBy() === $dest) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$email = new TemplatedEmail();
|
$email = new TemplatedEmail();
|
||||||
|
@ -65,7 +65,6 @@ class CronJobDatabaseInteractionTest extends KernelTestCase
|
|||||||
// run a second time
|
// run a second time
|
||||||
$manager->run();
|
$manager->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class JobWithReturn implements CronJobInterface
|
class JobWithReturn implements CronJobInterface
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
<?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 Notification\Email;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Notification;
|
||||||
|
use Chill\MainBundle\Entity\NotificationComment;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationMailer;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Prophecy\Argument;
|
||||||
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
|
use Psr\Log\NullLogger;
|
||||||
|
use Symfony\Component\Mailer\MailerInterface;
|
||||||
|
use Symfony\Component\Mime\Email;
|
||||||
|
use Symfony\Component\Translation\Translator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class NotificationMailerTest extends TestCase
|
||||||
|
{
|
||||||
|
use ProphecyTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public function testPostPersistComment(): void
|
||||||
|
{
|
||||||
|
$user1 = (new User())->setEmail('user1@foo.com');
|
||||||
|
$user2 = (new User())->setEmail('user2@foo.com');
|
||||||
|
$user3 = (new User())->setEmail('user3@foo.com');
|
||||||
|
|
||||||
|
$notification = new Notification();
|
||||||
|
$notification
|
||||||
|
->setTitle('test notification')
|
||||||
|
->setSender($user1)
|
||||||
|
->addAddressee($user2)
|
||||||
|
->addAddressee($user3)
|
||||||
|
;
|
||||||
|
|
||||||
|
$comment = (new NotificationComment())
|
||||||
|
->setContent("foo bar baz")
|
||||||
|
->setCreatedBy($user2)
|
||||||
|
;
|
||||||
|
$notification->addComment($comment);
|
||||||
|
|
||||||
|
$mailer = $this->prophesize(MailerInterface::class);
|
||||||
|
|
||||||
|
// a mail only to user1 and user3 should have been sent
|
||||||
|
$mailer->send(Argument::that(function (Email $email) {
|
||||||
|
foreach ($email->getTo() as $address) {
|
||||||
|
if ($address->getAddress() === 'user1@foo.com' || $address->getAddress() === 'user3@foo.com') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}))->shouldBeCalledTimes(2);
|
||||||
|
|
||||||
|
$objectManager = $this->prophesize(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$mailer = $this->buildNotificationMailer($mailer->reveal());
|
||||||
|
$mailer->postPersistComment($comment, new PostPersistEventArgs($comment, $objectManager->reveal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPostPersistCommentDestWithNullEmail(): void
|
||||||
|
{
|
||||||
|
$user1 = (new User())->setEmail('user1@foo.com');
|
||||||
|
$user2 = (new User())->setEmail('user2@foo.com');
|
||||||
|
$user3 = (new User())->setEmail(null);
|
||||||
|
|
||||||
|
$notification = new Notification();
|
||||||
|
$notification
|
||||||
|
->setTitle('test notification')
|
||||||
|
->setSender($user1)
|
||||||
|
->addAddressee($user2)
|
||||||
|
->addAddressee($user3)
|
||||||
|
;
|
||||||
|
|
||||||
|
$comment = (new NotificationComment())
|
||||||
|
->setContent("foo bar baz")
|
||||||
|
->setCreatedBy($user2)
|
||||||
|
;
|
||||||
|
$notification->addComment($comment);
|
||||||
|
|
||||||
|
$mailer = $this->prophesize(MailerInterface::class);
|
||||||
|
|
||||||
|
// a mail only to user1 and user3 should have been sent
|
||||||
|
$mailer->send(Argument::that(function (Email $email) {
|
||||||
|
foreach ($email->getTo() as $address) {
|
||||||
|
if ($address->getAddress() === 'user1@foo.com') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}))->shouldBeCalledTimes(1);
|
||||||
|
|
||||||
|
$objectManager = $this->prophesize(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$mailer = $this->buildNotificationMailer($mailer->reveal());
|
||||||
|
$mailer->postPersistComment($comment, new PostPersistEventArgs($comment, $objectManager->reveal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildNotificationMailer(
|
||||||
|
MailerInterface $mailer = null,
|
||||||
|
): NotificationMailer {
|
||||||
|
return new NotificationMailer(
|
||||||
|
$mailer,
|
||||||
|
new NullLogger(),
|
||||||
|
new Translator('fr')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -64,5 +64,4 @@ class CollateAddressWithReferenceOrPostalCodeCronJobTest extends TestCase
|
|||||||
yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-01T12:00:00'), true];
|
yield [new \DateTimeImmutable('2023-07-10T12:00:00'), new \DateTimeImmutable('2023-07-01T12:00:00'), true];
|
||||||
yield [new \DateTimeImmutable('2023-07-10T12:00:00'), null, true];
|
yield [new \DateTimeImmutable('2023-07-10T12:00:00'), null, true];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ final class PersonController extends AbstractController
|
|||||||
{
|
{
|
||||||
$person = new Person();
|
$person = new Person();
|
||||||
|
|
||||||
$authorizedCenters =$this->authorizationHelper->getReachableCenters($this->getUser(), PersonVoter::CREATE);
|
$authorizedCenters = $this->authorizationHelper->getReachableCenters($this->getUser(), PersonVoter::CREATE);
|
||||||
|
|
||||||
if (1 === count($authorizedCenters)) {
|
if (1 === count($authorizedCenters)) {
|
||||||
$person->setCenter($authorizedCenters[0]);
|
$person->setCenter($authorizedCenters[0]);
|
||||||
|
@ -55,6 +55,14 @@ class MembersEditor
|
|||||||
$this->eventDispatcher = $eventDispatcher;
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a person to the household
|
||||||
|
*
|
||||||
|
* The person is added to the household associated with this editor's instance.
|
||||||
|
*
|
||||||
|
* If the person is also a member of another household, or the same household at the same position, the person
|
||||||
|
* is not associated any more with the previous household.
|
||||||
|
*/
|
||||||
public function addMovement(DateTimeImmutable $date, Person $person, ?Position $position, ?bool $holder = false, ?string $comment = null): self
|
public function addMovement(DateTimeImmutable $date, Person $person, ?Position $position, ?bool $holder = false, ?string $comment = null): self
|
||||||
{
|
{
|
||||||
if (null === $this->household) {
|
if (null === $this->household) {
|
||||||
@ -69,68 +77,66 @@ class MembersEditor
|
|||||||
->setComment($comment);
|
->setComment($comment);
|
||||||
$this->household->addMember($membership);
|
$this->household->addMember($membership);
|
||||||
|
|
||||||
if (null !== $position) {
|
if ($membership->getShareHousehold()) {
|
||||||
if ($position->getShareHousehold()) {
|
// launch event only if moving to a "share household" position,
|
||||||
// launch event only if moving to a "share household" position,
|
// and if the destination household is different than the previous one
|
||||||
// and if the destination household is different than the previous one
|
$event = new PersonAddressMoveEvent($person);
|
||||||
$event = new PersonAddressMoveEvent($person);
|
$event->setNextMembership($membership);
|
||||||
$event->setNextMembership($membership);
|
|
||||||
|
|
||||||
$counter = 0;
|
$counter = 0;
|
||||||
|
|
||||||
foreach ($person->getHouseholdParticipationsShareHousehold() as $participation) {
|
foreach ($person->getHouseholdParticipationsShareHousehold() as $participation) {
|
||||||
if ($participation === $membership) {
|
if ($participation === $membership) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if ($participation->getStartDate() > $membership->getStartDate()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
++$counter;
|
|
||||||
|
|
||||||
if ($participation->getEndDate() === null || $participation->getEndDate() > $date) {
|
|
||||||
$participation->setEndDate($date);
|
|
||||||
$this->membershipsAffected[] = $participation;
|
|
||||||
$this->oldMembershipsHashes[] = spl_object_hash($participation);
|
|
||||||
|
|
||||||
if ($participation->getHousehold() !== $this->household) {
|
|
||||||
$event->setPreviousMembership($participation);
|
|
||||||
$this->events[] = $event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send also the event if there was no participation before
|
if ($participation->getStartDate() > $membership->getStartDate()) {
|
||||||
if (0 === $counter) {
|
continue;
|
||||||
$this->events[] = $event;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
|
++$counter;
|
||||||
if ($participation->getHousehold() === $this->household
|
|
||||||
&& $participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate()
|
if ($participation->getEndDate() === null || $participation->getEndDate() > $date) {
|
||||||
&& $participation->getStartDate() <= $membership->getStartDate()
|
$participation->setEndDate($date);
|
||||||
) {
|
$this->membershipsAffected[] = $participation;
|
||||||
$participation->setEndDate($membership->getStartDate());
|
$this->oldMembershipsHashes[] = spl_object_hash($participation);
|
||||||
|
|
||||||
|
if ($participation->getHousehold() !== $this->household) {
|
||||||
|
$event->setPreviousMembership($participation);
|
||||||
|
$this->events[] = $event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// if a members is moved to the same household than the one he belongs to,
|
|
||||||
// we should make it leave the household
|
// send also the event if there was no participation before
|
||||||
if ($person->getCurrentHousehold($date) === $this->household) {
|
if (0 === $counter) {
|
||||||
$this->leaveMovement($date, $person);
|
$this->events[] = $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
|
||||||
|
if ($participation->getHousehold() === $this->household
|
||||||
|
&& $participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate()
|
||||||
|
&& $participation->getStartDate() <= $membership->getStartDate()
|
||||||
|
) {
|
||||||
|
$participation->setEndDate($membership->getStartDate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if there are multiple belongings not sharing household, close the others
|
||||||
|
foreach ($person->getHouseholdParticipations() as $participation) {
|
||||||
|
if ($participation === $membership) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are multiple belongings not sharing household, close the others
|
if ($participation->getHousehold() === $this->household
|
||||||
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
|
&& ($participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate())
|
||||||
if ($participation === $membership) {
|
&& $participation->getStartDate() <= $membership->getStartDate()
|
||||||
continue;
|
) {
|
||||||
}
|
if ($participation->getShareHousehold()) {
|
||||||
|
// if a members is moved to the same household than the one he belongs to,
|
||||||
if ($participation->getHousehold() === $this->household
|
// we should make it leave the household
|
||||||
&& ($participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate())
|
$this->leaveMovement($date, $person);
|
||||||
&& $participation->getStartDate() <= $membership->getStartDate()
|
} else {
|
||||||
) {
|
|
||||||
$participation->setEndDate($membership->getStartDate());
|
$participation->setEndDate($membership->getStartDate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,6 +164,15 @@ class MembersEditor
|
|||||||
return null !== $this->household;
|
return null !== $this->household;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a person leave the household.
|
||||||
|
*
|
||||||
|
* Makes a person leave the household **associated with this editor**.
|
||||||
|
*
|
||||||
|
* @param DateTimeImmutable $date
|
||||||
|
* @param Person $person
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function leaveMovement(
|
public function leaveMovement(
|
||||||
DateTimeImmutable $date,
|
DateTimeImmutable $date,
|
||||||
Person $person
|
Person $person
|
||||||
@ -167,8 +182,9 @@ class MembersEditor
|
|||||||
|
|
||||||
$criteria->where(
|
$criteria->where(
|
||||||
$expr->andX(
|
$expr->andX(
|
||||||
$expr->lt('startDate', $date),
|
$expr->lte('startDate', $date),
|
||||||
$expr->isNull('endDate')
|
$expr->isNull('endDate'),
|
||||||
|
$expr->eq('shareHousehold', true)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -207,10 +207,11 @@ div.banner {
|
|||||||
span.badge-member {
|
span.badge-member {
|
||||||
flex-shrink: 0; flex-grow: 0; flex-basis: auto;
|
flex-shrink: 0; flex-grow: 0; flex-basis: auto;
|
||||||
color: $white;
|
color: $white;
|
||||||
|
background-color: transparentize($white, 0.85);
|
||||||
border: 1px solid transparentize($white, 0.75);
|
border: 1px solid transparentize($white, 0.75);
|
||||||
border-bottom: 3px solid transparentize( shade-color( $chill-green, 20%), 0.3);
|
border-bottom: 3px solid transparentize( shade-color( $chill-green, 20%), 0.3);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0.2em 0.7em;
|
padding: 0.0em 0.5em;
|
||||||
margin-bottom: 0.2em;
|
margin-bottom: 0.2em;
|
||||||
margin-right: 0.3em;
|
margin-right: 0.3em;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<ckeditor
|
<ckeditor
|
||||||
name="content"
|
name="content"
|
||||||
v-bind:placeholder="$t('comment.content')"
|
v-bind:placeholder="$t('household_members_editor.positioning.comment_placeholder')"
|
||||||
:editor="editor"
|
:editor="editor"
|
||||||
v-model="content"
|
v-model="content"
|
||||||
tag-name="textarea">
|
tag-name="textarea">
|
||||||
|
@ -53,6 +53,7 @@ const appMessages = {
|
|||||||
persons_to_positionnate: 'Usagers à positionner',
|
persons_to_positionnate: 'Usagers à positionner',
|
||||||
holder: "Titulaire",
|
holder: "Titulaire",
|
||||||
comment: "Commentaire",
|
comment: "Commentaire",
|
||||||
|
comment_placeholder: "Associer un commentaire",
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
next: 'Suivant',
|
next: 'Suivant',
|
||||||
|
@ -74,6 +74,55 @@ final class MembersEditorTest extends TestCase
|
|||||||
$this->assertContains(null, $endDates);
|
$this->assertContains(null, $endDates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We test that a leave move is possible when member startdate is same as current date
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function testLeaveMovementInSameHouseholdFromShareHouseholdToNotShareHouseholdOnSameDate()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$household = new Household();
|
||||||
|
|
||||||
|
$factory = $this->buildMembersEditorFactory();
|
||||||
|
|
||||||
|
$positionSharing = (new Position())->setShareHousehold(true);
|
||||||
|
$positionNotSharing = (new Position())->setShareHousehold(false);
|
||||||
|
|
||||||
|
// create add move
|
||||||
|
$editor = $factory->createEditor($household);
|
||||||
|
$editor->addMovement(new DateTimeImmutable('today'), $person, $positionSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
|
self::assertContains($person, $household->getCurrentPersons());
|
||||||
|
self::assertSame($household, $person->getCurrentHousehold());
|
||||||
|
self::assertCount(1, $household->getMembers());
|
||||||
|
|
||||||
|
// create leave move
|
||||||
|
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
|
||||||
|
$eventDispatcher
|
||||||
|
->dispatch(Argument::type(PersonAddressMoveEvent::class))
|
||||||
|
->shouldBeCalled();
|
||||||
|
$factory = $this->buildMembersEditorFactory(
|
||||||
|
$eventDispatcher->reveal(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$editor = $factory->createEditor($household);
|
||||||
|
$editor->addMovement(new DateTimeImmutable('today'), $person, $positionNotSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
|
$participations = $household->getMembers();
|
||||||
|
self::assertCount(2, $participations);
|
||||||
|
|
||||||
|
$sharing = $participations->filter(fn (HouseholdMember $hm) => $hm->getShareHousehold());
|
||||||
|
self::assertCount(1, $sharing);
|
||||||
|
|
||||||
|
$notSharing = $participations->filter(fn (HouseholdMember $hm) => !$hm->getShareHousehold());
|
||||||
|
self::assertCount(1, $notSharing);
|
||||||
|
|
||||||
|
self::assertNotNull($sharing[0]->getEndDate());
|
||||||
|
self::assertEquals(new DateTimeImmutable('today'), $sharing[0]->getEndDate());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We test here a move for a person:.
|
* We test here a move for a person:.
|
||||||
*
|
*
|
||||||
@ -98,8 +147,17 @@ final class MembersEditorTest extends TestCase
|
|||||||
$this->assertContains($person, $household->getCurrentPersons());
|
$this->assertContains($person, $household->getCurrentPersons());
|
||||||
|
|
||||||
// we do the move to the position not sharing household
|
// we do the move to the position not sharing household
|
||||||
|
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
|
||||||
|
$eventDispatcher
|
||||||
|
->dispatch(Argument::type(PersonAddressMoveEvent::class))
|
||||||
|
->shouldNotBeCalled();
|
||||||
|
$factory = $this->buildMembersEditorFactory(
|
||||||
|
$eventDispatcher->reveal(),
|
||||||
|
null
|
||||||
|
);
|
||||||
$editor = $factory->createEditor($household2 = new Household());
|
$editor = $factory->createEditor($household2 = new Household());
|
||||||
$editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
|
$editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
$sharings = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => $m->getShareHousehold());
|
$sharings = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => $m->getShareHousehold());
|
||||||
$notSharing = $household2->getCurrentMembers()->filter(static fn (HouseholdMember $m) => !$m->getShareHousehold());
|
$notSharing = $household2->getCurrentMembers()->filter(static fn (HouseholdMember $m) => !$m->getShareHousehold());
|
||||||
@ -118,7 +176,7 @@ final class MembersEditorTest extends TestCase
|
|||||||
* * which was in a position "sharing household"
|
* * which was in a position "sharing household"
|
||||||
* * which move to the same household, in a position "not sharing household"
|
* * which move to the same household, in a position "not sharing household"
|
||||||
*/
|
*/
|
||||||
public function testMoveFromSharingHouseholdToNotSharingHousehouldInSamehousehold()
|
public function testMoveFromSharingHouseholdToNotSharingHousehouldInSamehouseholdOnDifferentDate()
|
||||||
{
|
{
|
||||||
$person = new Person();
|
$person = new Person();
|
||||||
$household = new Household();
|
$household = new Household();
|
||||||
@ -134,8 +192,17 @@ final class MembersEditorTest extends TestCase
|
|||||||
$this->assertContains($person, $household->getCurrentPersons());
|
$this->assertContains($person, $household->getCurrentPersons());
|
||||||
|
|
||||||
// we do the move to the position not sharing household
|
// we do the move to the position not sharing household
|
||||||
|
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
|
||||||
|
$eventDispatcher
|
||||||
|
->dispatch(Argument::type(PersonAddressMoveEvent::class))
|
||||||
|
->shouldBeCalled();
|
||||||
|
$factory = $this->buildMembersEditorFactory(
|
||||||
|
$eventDispatcher->reveal(),
|
||||||
|
null
|
||||||
|
);
|
||||||
$editor = $factory->createEditor($household);
|
$editor = $factory->createEditor($household);
|
||||||
$editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
|
$editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
$sharings = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => $m->getShareHousehold());
|
$sharings = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => $m->getShareHousehold());
|
||||||
$notSharing = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => !$m->getShareHousehold());
|
$notSharing = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => !$m->getShareHousehold());
|
||||||
@ -148,6 +215,84 @@ final class MembersEditorTest extends TestCase
|
|||||||
$this->assertContains($person, $notSharing->map($getPerson));
|
$this->assertContains($person, $notSharing->map($getPerson));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We test here a move for a person:.
|
||||||
|
*
|
||||||
|
* * which was in a position "not sharing household"
|
||||||
|
* * which move to the same household, in a position "sharing household"
|
||||||
|
*/
|
||||||
|
public function testMoveFromNotSharingHouseholdToSharingHousehouldInSamehousehold()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$household = new Household();
|
||||||
|
$positionSharing = (new Position())->setShareHousehold(true);
|
||||||
|
$positionNotSharing = (new Position())->setShareHousehold(false);
|
||||||
|
$factory = $this->buildMembersEditorFactory();
|
||||||
|
$editor = $factory->createEditor($household);
|
||||||
|
|
||||||
|
// we add the member to the household, at the position "not sharing"
|
||||||
|
$editor->addMovement(new DateTimeImmutable('1 month ago'), $person, $positionNotSharing);
|
||||||
|
|
||||||
|
// double check that the person is in the household
|
||||||
|
$this->assertContains($person, $household->getCurrentPersons());
|
||||||
|
|
||||||
|
// we do the move to the position sharing household
|
||||||
|
$editor = $factory->createEditor($household);
|
||||||
|
$editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionSharing);
|
||||||
|
|
||||||
|
self::assertCount(2, $household->getMembers());
|
||||||
|
|
||||||
|
$sharings = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => $m->getShareHousehold());
|
||||||
|
$notSharing = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => !$m->getShareHousehold());
|
||||||
|
|
||||||
|
$this->assertCount(0, $notSharing);
|
||||||
|
$this->assertCount(1, $sharings);
|
||||||
|
|
||||||
|
$getPerson = static fn (HouseholdMember $m) => $m->getPerson();
|
||||||
|
|
||||||
|
$this->assertContains($person, $sharings->map($getPerson));
|
||||||
|
$this->assertNotContains($person, $notSharing->map($getPerson));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We test here a move for a person:.
|
||||||
|
*
|
||||||
|
* * which was in a position "not sharing household"
|
||||||
|
* * which move to the same household, in a position "sharing household"
|
||||||
|
*/
|
||||||
|
public function testMoveFromNotSharingHouseholdToSharingHousehouldInSamehouseholdOnSameDate()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$household = new Household();
|
||||||
|
$positionSharing = (new Position())->setShareHousehold(true);
|
||||||
|
$positionNotSharing = (new Position())->setShareHousehold(false);
|
||||||
|
$factory = $this->buildMembersEditorFactory();
|
||||||
|
$editor = $factory->createEditor($household);
|
||||||
|
|
||||||
|
// we add the member to the household, at the position "not sharing"
|
||||||
|
$editor->addMovement(new DateTimeImmutable('today'), $person, $positionNotSharing);
|
||||||
|
|
||||||
|
// double check that the person is in the household
|
||||||
|
$this->assertContains($person, $household->getCurrentPersons());
|
||||||
|
|
||||||
|
// we do the move to the position sharing household
|
||||||
|
$editor = $factory->createEditor($household);
|
||||||
|
$editor->addMovement(new DateTimeImmutable('today'), $person, $positionSharing);
|
||||||
|
|
||||||
|
self::assertCount(2, $household->getMembers());
|
||||||
|
|
||||||
|
$sharings = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => $m->getShareHousehold());
|
||||||
|
$notSharing = $household->getCurrentMembers()->filter(static fn (HouseholdMember $m) => !$m->getShareHousehold());
|
||||||
|
|
||||||
|
$this->assertCount(0, $notSharing);
|
||||||
|
$this->assertCount(1, $sharings);
|
||||||
|
|
||||||
|
$getPerson = static fn (HouseholdMember $m) => $m->getPerson();
|
||||||
|
|
||||||
|
$this->assertContains($person, $sharings->map($getPerson));
|
||||||
|
$this->assertNotContains($person, $notSharing->map($getPerson));
|
||||||
|
}
|
||||||
|
|
||||||
public function testMovePersonWithoutSharedHousehold()
|
public function testMovePersonWithoutSharedHousehold()
|
||||||
{
|
{
|
||||||
$person = new Person();
|
$person = new Person();
|
||||||
@ -235,13 +380,26 @@ final class MembersEditorTest extends TestCase
|
|||||||
$this->assertEquals($date, $membership1->getEndDate());
|
$this->assertEquals($date, $membership1->getEndDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPostMoveToAPositionNotSharingHousehold()
|
public function testPostMoveToAPositionNotSharingHouseholdOnSameDay()
|
||||||
{
|
{
|
||||||
$person = new Person();
|
$person = new Person();
|
||||||
$position = (new Position())
|
$positionNotSharing = (new Position())
|
||||||
->setShareHousehold(false);
|
->setShareHousehold(false);
|
||||||
|
$positionSharing = (new Position())->setShareHousehold(true);
|
||||||
$household1 = new Household();
|
$household1 = new Household();
|
||||||
$household2 = new Household();
|
$household2 = new Household();
|
||||||
|
|
||||||
|
$factory = $this->buildMembersEditorFactory();
|
||||||
|
$editor = $factory->createEditor($household1);
|
||||||
|
$editor->addMovement(new DateTimeImmutable('today'), $person, $positionSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
|
self::assertContains($person, $household1->getCurrentPersons());
|
||||||
|
self::assertContains($person, $household1->getCurrentMembers()
|
||||||
|
->filter(fn (HouseholdMember $m) => $m->getShareHousehold())
|
||||||
|
->map(fn (HouseholdMember $m) => $m->getPerson()));
|
||||||
|
self::assertSame($household1, $person->getCurrentHousehold());
|
||||||
|
|
||||||
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
|
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
|
||||||
$eventDispatcher
|
$eventDispatcher
|
||||||
->dispatch(Argument::type(PersonAddressMoveEvent::class))
|
->dispatch(Argument::type(PersonAddressMoveEvent::class))
|
||||||
@ -250,11 +408,78 @@ final class MembersEditorTest extends TestCase
|
|||||||
$eventDispatcher->reveal(),
|
$eventDispatcher->reveal(),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$editor = $factory->createEditor($household1);
|
$editor = $factory->createEditor($household2);
|
||||||
|
|
||||||
$editor->addMovement(new DateTimeImmutable('now'), $person, $position);
|
|
||||||
|
|
||||||
|
$editor->addMovement(new DateTimeImmutable('today'), $person, $positionNotSharing);
|
||||||
$editor->postMove();
|
$editor->postMove();
|
||||||
|
|
||||||
|
// $household1 still contains $person
|
||||||
|
self::assertContains($person, $household1->getCurrentPersons());
|
||||||
|
self::assertContains($person, $household1->getCurrentMembers()
|
||||||
|
->filter(fn (HouseholdMember $m) => $m->getShareHousehold())
|
||||||
|
->map(fn (HouseholdMember $m) => $m->getPerson()));
|
||||||
|
self::assertSame($household1, $person->getCurrentHousehold());
|
||||||
|
|
||||||
|
// $household2 contains $person at non-sharing position
|
||||||
|
self::assertContains($person, $household2->getCurrentMembers()
|
||||||
|
->filter(fn (HouseholdMember $m) => !$m->getShareHousehold())
|
||||||
|
->map(fn (HouseholdMember $m) => $m->getPerson()));
|
||||||
|
self::assertContains(
|
||||||
|
$household2,
|
||||||
|
$person->getHouseholdParticipationsNotShareHousehold()
|
||||||
|
->map(fn (HouseholdMember $hm) => $hm->getHousehold())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPostMoveToAPositionNotSharingHouseholdOnDifferentDays()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$positionNotSharing = (new Position())
|
||||||
|
->setShareHousehold(false);
|
||||||
|
$positionSharing = (new Position())->setShareHousehold(true);
|
||||||
|
$household1 = new Household();
|
||||||
|
$household2 = new Household();
|
||||||
|
|
||||||
|
$factory = $this->buildMembersEditorFactory();
|
||||||
|
$editor = $factory->createEditor($household1);
|
||||||
|
$editor->addMovement(new DateTimeImmutable('1 year ago'), $person, $positionSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
|
self::assertContains($person, $household1->getCurrentPersons());
|
||||||
|
self::assertContains($person, $household1->getCurrentMembers()
|
||||||
|
->filter(fn (HouseholdMember $m) => $m->getShareHousehold())
|
||||||
|
->map(fn (HouseholdMember $m) => $m->getPerson()));
|
||||||
|
self::assertSame($household1, $person->getCurrentHousehold());
|
||||||
|
|
||||||
|
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
|
||||||
|
$eventDispatcher
|
||||||
|
->dispatch(Argument::type(PersonAddressMoveEvent::class))
|
||||||
|
->shouldNotBeCalled();
|
||||||
|
$factory = $this->buildMembersEditorFactory(
|
||||||
|
$eventDispatcher->reveal(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$editor = $factory->createEditor($household2);
|
||||||
|
|
||||||
|
$editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
|
||||||
|
$editor->postMove();
|
||||||
|
|
||||||
|
// $household1 still contains $person
|
||||||
|
self::assertContains($person, $household1->getCurrentPersons());
|
||||||
|
self::assertContains($person, $household1->getCurrentMembers()
|
||||||
|
->filter(fn (HouseholdMember $m) => $m->getShareHousehold())
|
||||||
|
->map(fn (HouseholdMember $m) => $m->getPerson()));
|
||||||
|
self::assertSame($household1, $person->getCurrentHousehold());
|
||||||
|
|
||||||
|
// $household2 contains $person at non-sharing position
|
||||||
|
self::assertContains($person, $household2->getCurrentMembers()
|
||||||
|
->filter(fn (HouseholdMember $m) => !$m->getShareHousehold())
|
||||||
|
->map(fn (HouseholdMember $m) => $m->getPerson()));
|
||||||
|
self::assertContains(
|
||||||
|
$household2,
|
||||||
|
$person->getHouseholdParticipationsNotShareHousehold()
|
||||||
|
->map(fn (HouseholdMember $hm) => $hm->getHousehold())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPostMoveToAPositionSharingHouseholdAndSameHousehold()
|
public function testPostMoveToAPositionSharingHouseholdAndSameHousehold()
|
||||||
|
@ -108,7 +108,7 @@ class AccompanyingPeriodContextTest extends KernelTestCase
|
|||||||
): void {
|
): void {
|
||||||
$context = $this->buildContext();
|
$context = $this->buildContext();
|
||||||
$template = new DocGeneratorTemplate();
|
$template = new DocGeneratorTemplate();
|
||||||
$template->setName(["fr" =>"test"])->setContext(AccompanyingPeriodContext::class)
|
$template->setName(["fr" => "test"])->setContext(AccompanyingPeriodContext::class)
|
||||||
->setDescription("description")->setActive(true)
|
->setDescription("description")->setActive(true)
|
||||||
->setOptions($options);
|
->setOptions($options);
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ final class PersonContextTest extends KernelTestCase
|
|||||||
self::$container->get(ThirdPartyRepository::class)
|
self::$container->get(ThirdPartyRepository::class)
|
||||||
);
|
);
|
||||||
$template = new DocGeneratorTemplate();
|
$template = new DocGeneratorTemplate();
|
||||||
$template->setName(["fr" =>"test"])->setContext(AccompanyingPeriodContext::class)
|
$template->setName(["fr" => "test"])->setContext(AccompanyingPeriodContext::class)
|
||||||
->setDescription("description")->setActive(true)
|
->setDescription("description")->setActive(true)
|
||||||
->setOptions($options);
|
->setOptions($options);
|
||||||
|
|
||||||
|
@ -47,11 +47,9 @@ class RelationshipNoDuplicateValidator extends ConstraintValidator
|
|||||||
|
|
||||||
foreach ($relationships as $r) {
|
foreach ($relationships as $r) {
|
||||||
if (spl_object_hash($r) !== spl_object_hash($value)
|
if (spl_object_hash($r) !== spl_object_hash($value)
|
||||||
and
|
and (
|
||||||
(
|
|
||||||
($r->getFromPerson() === $fromPerson and $r->getToPerson() === $toPerson)
|
($r->getFromPerson() === $fromPerson and $r->getToPerson() === $toPerson)
|
||||||
||
|
|| ($r->getFromPerson() === $toPerson and $r->getToPerson() === $fromPerson)
|
||||||
($r->getFromPerson() === $toPerson and $r->getToPerson() === $fromPerson)
|
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
$this->context->buildViolation($constraint->message)
|
$this->context->buildViolation($constraint->message)
|
||||||
|
@ -1225,6 +1225,7 @@ export:
|
|||||||
acpw:
|
acpw:
|
||||||
List of accompanying period works: Liste des actions
|
List of accompanying period works: Liste des actions
|
||||||
List description: Génère une liste des actions d'accompagnement, filtrée sur différents paramètres.
|
List description: Génère une liste des actions d'accompagnement, filtrée sur différents paramètres.
|
||||||
|
Date of calculation for associated elements: Date de calcul des éléments associés
|
||||||
help_description: L'agent traitant de l'action sera valide à cette date
|
help_description: L'agent traitant de l'action sera valide à cette date
|
||||||
id: Identifiant de l'action
|
id: Identifiant de l'action
|
||||||
startDate: Date de début
|
startDate: Date de début
|
||||||
|
@ -43,5 +43,4 @@ class SingleTaskStateRepository
|
|||||||
|
|
||||||
return $states;
|
return $states;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user