mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge remote-tracking branch 'origin/master' into rector/rules-symfony
# Conflicts: # src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivity.php # src/Bundle/ChillAsideActivityBundle/src/Export/Export/ListAsideActivity.php
This commit is contained in:
commit
9375d50112
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: ""
|
3
.changes/v2.5.3.md
Normal file
3
.changes/v2.5.3.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## v2.5.3 - 2023-07-20
|
||||||
|
### Fixed
|
||||||
|
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
|
@ -6,6 +6,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|||||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||||
|
|
||||||
|
|
||||||
|
## v2.5.3 - 2023-07-20
|
||||||
|
### Fixed
|
||||||
|
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
|
||||||
|
|
||||||
## v2.5.2 - 2023-07-15
|
## v2.5.2 - 2023-07-15
|
||||||
### Fixed
|
### Fixed
|
||||||
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
|
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
|
||||||
|
80
CONTRIBUTING.md
Normal file
80
CONTRIBUTING.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
Chill is an open source, community-driven project.
|
||||||
|
|
||||||
|
If you'd like to contribute, please read the following.
|
||||||
|
|
||||||
|
## What can you do ?
|
||||||
|
|
||||||
|
Chill is an open-source project driven by a community of developers, users and social workers. If you don't feel ready to contribute code or patches, reviewing issues and pull requests (PRs) can be a great start to get involved and give back.
|
||||||
|
|
||||||
|
If you don't have your own instance or don't want to use it, you can try to reproduce bugs using the instance https://demo.chill.social
|
||||||
|
|
||||||
|
## Core team
|
||||||
|
|
||||||
|
The core team is the group of developers that determine the direction and evolution of the Chill project. Their votes rule if the features and patches proposed by the community are approved or rejected.
|
||||||
|
|
||||||
|
All the Chill Core members are long-time contributors with solid technical expertise and they have demonstrated a strong commitment to drive the project forward.
|
||||||
|
|
||||||
|
The core team:
|
||||||
|
|
||||||
|
- elects his own members;
|
||||||
|
- merge pull requests;
|
||||||
|
|
||||||
|
### members
|
||||||
|
|
||||||
|
Project leader: [julienfastre](https://gitlab.com/julienfastre)
|
||||||
|
|
||||||
|
Core members:
|
||||||
|
|
||||||
|
- [tchama](https://gitlab.com/tchama)
|
||||||
|
- [LenaertsJ](https://gitlab.com/LenaertsJ)
|
||||||
|
- [nobohan](https://gitlab.com/nobohan)
|
||||||
|
|
||||||
|
### Becoming a project member
|
||||||
|
|
||||||
|
About once a year, the core team discusses the opportunity to invite new members. To become a core team member, you must:
|
||||||
|
|
||||||
|
- take part on the development for at least 6 month: propose multiple merge requests and participate to the peer review process;
|
||||||
|
- through this participation, demonstrate your technical skills and your knowledge of the software and any of their dependencies;
|
||||||
|
|
||||||
|
### Core Membership Revocation
|
||||||
|
|
||||||
|
A Symfony Core membership can be revoked for any of the following reasons:
|
||||||
|
|
||||||
|
- Refusal to follow the rules and policies stated in this document;
|
||||||
|
- Lack of activity for the past six months;
|
||||||
|
- Willful negligence or intent to harm the Chill project;
|
||||||
|
|
||||||
|
The decision is taken by the majority of project members.
|
||||||
|
|
||||||
|
## Code development rules
|
||||||
|
|
||||||
|
### Merge requests
|
||||||
|
|
||||||
|
Every merge request must contains:
|
||||||
|
|
||||||
|
- one more entries suitable for generating a changelog. This is done using the [changie utility](https://changie.dev);
|
||||||
|
- a comprehensible description of the changes;
|
||||||
|
- if applicable, automated tests should be adapted or created;
|
||||||
|
- the code style must pass the project's rules, and non phpstan errors must be raised nor rector refactoring suggestion.
|
||||||
|
|
||||||
|
The pipelines must pass.
|
||||||
|
|
||||||
|
In case of emergency, some rules may be temporarily ignored.
|
||||||
|
|
||||||
|
### Merge Request Voting Policy
|
||||||
|
|
||||||
|
- -1 votes must always be justified by technical and objective reasons;
|
||||||
|
- +1 (technically: approbation on the merge request) votes do not require justification, unless there is at least one -1 vote;
|
||||||
|
- Core members can change their votes as many times as they desire during the course of a merge request discussion;
|
||||||
|
- Core members are not allowed to vote on their own merge requests.
|
||||||
|
|
||||||
|
### Merge Request Merging Process
|
||||||
|
|
||||||
|
All code must be committed to the repository through merge requests, except for minor changes which can be committed directly to the repository.
|
||||||
|
|
||||||
|
### Release Policy
|
||||||
|
|
||||||
|
The Core members are also the release manager for every Chill version.
|
||||||
|
|
@ -85,7 +85,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();
|
||||||
|
|
||||||
|
@ -49,7 +49,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;
|
||||||
|
@ -313,7 +313,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';
|
||||||
|
|
||||||
public function __construct(private readonly TranslatorInterface $translator)
|
public function __construct(private readonly TranslatorInterface $translator)
|
||||||
{
|
{
|
||||||
|
@ -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"];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,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;
|
||||||
@ -34,7 +35,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime")
|
* @ORM\Column(type="datetime")
|
||||||
*/
|
*/
|
||||||
private ?\DateTimeInterface $createdAt = null;
|
private $createdAt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=User::class)
|
* @ORM\ManyToOne(targetEntity=User::class)
|
||||||
@ -45,7 +46,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime")
|
* @ORM\Column(type="datetime")
|
||||||
*/
|
*/
|
||||||
private ?\DateTimeInterface $date = null;
|
private $date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="time", nullable=true)
|
* @ORM\Column(type="time", nullable=true)
|
||||||
@ -60,25 +61,26 @@ 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 ?string $location = null;
|
private ?Location $location = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="text", nullable=true)
|
* @ORM\Column(type="text", nullable=true)
|
||||||
*/
|
*/
|
||||||
private ?string $note = null;
|
private $note;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="asideActivities")
|
* @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="asideActivities")
|
||||||
* @ORM\JoinColumn(nullable=false)
|
* @ORM\JoinColumn(nullable=false)
|
||||||
*/
|
*/
|
||||||
private ?\Chill\AsideActivityBundle\Entity\AsideActivityCategory $type = null;
|
private $type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime", nullable=true)
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
*/
|
*/
|
||||||
private ?\DateTimeInterface $updatedAt = null;
|
private $updatedAt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=User::class)
|
* @ORM\ManyToOne(targetEntity=User::class)
|
||||||
@ -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;
|
||||||
@ -32,23 +33,49 @@ use Doctrine\ORM\QueryBuilder;
|
|||||||
use LogicException;
|
use LogicException;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
final readonly class ListAsideActivity implements ListInterface, GroupedExportInterface
|
final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
||||||
{
|
{
|
||||||
|
private AsideActivityCategoryRepository $asideActivityCategoryRepository;
|
||||||
|
|
||||||
|
private CategoryRender $categoryRender;
|
||||||
|
|
||||||
|
private CenterRepositoryInterface $centerRepository;
|
||||||
|
|
||||||
|
private DateTimeHelper $dateTimeHelper;
|
||||||
|
|
||||||
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
|
private ScopeRepositoryInterface $scopeRepository;
|
||||||
|
|
||||||
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
|
private UserHelper $userHelper;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private EntityManagerInterface $em,
|
EntityManagerInterface $em,
|
||||||
private DateTimeHelper $dateTimeHelper,
|
DateTimeHelper $dateTimeHelper,
|
||||||
private UserHelper $userHelper,
|
UserHelper $userHelper,
|
||||||
private ScopeRepositoryInterface $scopeRepository,
|
ScopeRepositoryInterface $scopeRepository,
|
||||||
private CenterRepositoryInterface $centerRepository,
|
CenterRepositoryInterface $centerRepository,
|
||||||
private AsideActivityCategoryRepository $asideActivityCategoryRepository,
|
AsideActivityCategoryRepository $asideActivityCategoryRepository,
|
||||||
private CategoryRender $categoryRender,
|
CategoryRender $categoryRender,
|
||||||
private TranslatableStringHelperInterface $translatableStringHelper
|
private LocationRepository $locationRepository,
|
||||||
|
TranslatableStringHelperInterface $translatableStringHelper
|
||||||
) {
|
) {
|
||||||
|
$this->em = $em;
|
||||||
|
$this->dateTimeHelper = $dateTimeHelper;
|
||||||
|
$this->userHelper = $userHelper;
|
||||||
|
$this->scopeRepository = $scopeRepository;
|
||||||
|
$this->centerRepository = $centerRepository;
|
||||||
|
$this->asideActivityCategoryRepository = $asideActivityCategoryRepository;
|
||||||
|
$this->categoryRender = $categoryRender;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder)
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormDefaultData(): array
|
public function getFormDefaultData(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
@ -71,15 +98,19 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
|
|
||||||
public function getLabels($key, array $values, $data)
|
public function getLabels($key, array $values, $data)
|
||||||
{
|
{
|
||||||
return match ($key) {
|
switch ($key) {
|
||||||
'id', 'note' => static function ($value) use ($key) {
|
case 'id':
|
||||||
|
case 'note':
|
||||||
|
return static function ($value) use ($key) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'export.aside_activity.' . $key;
|
return 'export.aside_activity.' . $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value ?? '';
|
return $value ?? '';
|
||||||
},
|
};
|
||||||
'duration' => static function ($value) use ($key) {
|
|
||||||
|
case 'duration':
|
||||||
|
return static function ($value) use ($key) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'export.aside_activity.' . $key;
|
return 'export.aside_activity.' . $key;
|
||||||
}
|
}
|
||||||
@ -93,10 +124,19 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
},
|
};
|
||||||
'createdAt', 'updatedAt', 'date' => $this->dateTimeHelper->getLabel('export.aside_activity.' . $key),
|
|
||||||
'agent_id', 'creator_id' => $this->userHelper->getLabel($key, $values, 'export.aside_activity.' . $key),
|
case 'createdAt':
|
||||||
'aside_activity_type' => function ($value) {
|
case 'updatedAt':
|
||||||
|
case 'date':
|
||||||
|
return $this->dateTimeHelper->getLabel('export.aside_activity.' . $key);
|
||||||
|
|
||||||
|
case 'agent_id':
|
||||||
|
case 'creator_id':
|
||||||
|
return $this->userHelper->getLabel($key, $values, 'export.aside_activity.' . $key);
|
||||||
|
|
||||||
|
case 'aside_activity_type':
|
||||||
|
return function ($value) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'export.aside_activity.aside_activity_type';
|
return 'export.aside_activity.aside_activity_type';
|
||||||
}
|
}
|
||||||
@ -106,8 +146,23 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->categoryRender->renderString($c, []);
|
return $this->categoryRender->renderString($c, []);
|
||||||
},
|
};
|
||||||
'main_scope' => function ($value) {
|
|
||||||
|
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':
|
||||||
|
return function ($value) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'export.aside_activity.main_scope';
|
return 'export.aside_activity.main_scope';
|
||||||
}
|
}
|
||||||
@ -117,8 +172,10 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize($c->getName());
|
return $this->translatableStringHelper->localize($c->getName());
|
||||||
},
|
};
|
||||||
'main_center' => function ($value) {
|
|
||||||
|
case 'main_center':
|
||||||
|
return function ($value) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'export.aside_activity.main_center';
|
return 'export.aside_activity.main_center';
|
||||||
}
|
}
|
||||||
@ -129,9 +186,11 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $c->getName();
|
return $c->getName();
|
||||||
},
|
|
||||||
default => throw new LogicException('this key is not supported : ' . $key),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new LogicException('this key is not supported : ' . $key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryKeys($data)
|
public function getQueryKeys($data)
|
||||||
@ -148,6 +207,7 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
'date',
|
'date',
|
||||||
'duration',
|
'duration',
|
||||||
'note',
|
'note',
|
||||||
|
'location',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +243,7 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
|
|||||||
->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">
|
||||||
|
@ -23,6 +23,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>
|
||||||
|
|
||||||
<dt class="inline">{{ 'Date'|trans }}</dt>
|
<dt class="inline">{{ 'Date'|trans }}</dt>
|
||||||
|
@ -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';
|
||||||
|
|
||||||
public function __construct(private readonly TranslatorInterface $translator)
|
public function __construct(private readonly 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")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,9 @@ final readonly class AccompanyingPeriodCalendarGenericDocProvider implements Gen
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$query->addWhereClause(implode(" OR ", $or), $orParams, $orTypes);
|
||||||
|
|
||||||
return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content);
|
return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,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"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,5 +92,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'];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,8 @@ class CenterController extends AbstractController
|
|||||||
|
|
||||||
$entities = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->findAll();
|
$entities = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->findAll();
|
||||||
|
|
||||||
|
usort($entities, fn (Center $a, Center $b) => $a->getName() <=> $b->getName());
|
||||||
|
|
||||||
return $this->render('@ChillMain/Center/index.html.twig', [
|
return $this->render('@ChillMain/Center/index.html.twig', [
|
||||||
'entities' => $entities,
|
'entities' => $entities,
|
||||||
]);
|
]);
|
||||||
|
@ -73,7 +73,6 @@ final readonly 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
|
||||||
|
@ -31,13 +31,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();
|
||||||
|
@ -76,7 +76,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,14 @@ class MembersEditor
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
@ -60,8 +68,7 @@ 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);
|
||||||
@ -106,14 +113,8 @@ class MembersEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if a members is moved to the same household than the one he belongs to,
|
|
||||||
// we should make it leave the household
|
|
||||||
if ($person->getCurrentHousehold($date) === $this->household) {
|
|
||||||
$this->leaveMovement($date, $person);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there are multiple belongings not sharing household, close the others
|
// if there are multiple belongings not sharing household, close the others
|
||||||
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
|
foreach ($person->getHouseholdParticipations() as $participation) {
|
||||||
if ($participation === $membership) {
|
if ($participation === $membership) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -122,6 +123,11 @@ class MembersEditor
|
|||||||
&& ($participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate())
|
&& ($participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate())
|
||||||
&& $participation->getStartDate() <= $membership->getStartDate()
|
&& $participation->getStartDate() <= $membership->getStartDate()
|
||||||
) {
|
) {
|
||||||
|
if ($participation->getShareHousehold()) {
|
||||||
|
// if a members is moved to the same household than the one he belongs to,
|
||||||
|
// we should make it leave the household
|
||||||
|
$this->leaveMovement($date, $person);
|
||||||
|
} else {
|
||||||
$participation->setEndDate($membership->getStartDate());
|
$participation->setEndDate($membership->getStartDate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,6 +155,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
|
||||||
@ -158,8 +173,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()
|
||||||
|
@ -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