mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-01-14 05:11:23 +00:00
Compare commits
7 Commits
487-addres
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bf461a1211 | |||
| 3f0ad51114 | |||
| a4de8eaab3 | |||
| 2feb137ac2 | |||
| 5ea74d118b | |||
| 8eb7a55ef5 | |||
| 281887355f |
6
.changes/unreleased/Feature-20260105-150817.yaml
Normal file
6
.changes/unreleased/Feature-20260105-150817.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
kind: Feature
|
||||
body: Display version of chill bundles in application footer
|
||||
time: 2026-01-05T15:08:17.317719064+01:00
|
||||
custom:
|
||||
Issue: "473"
|
||||
SchemaChange: No schema change
|
||||
6
.changes/unreleased/Fixed-20260112-103411.yaml
Normal file
6
.changes/unreleased/Fixed-20260112-103411.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
kind: Fixed
|
||||
body: Fix the calculation of budget balance to only take into account resources and charges that are still actual
|
||||
time: 2026-01-12T10:34:11.032115897+01:00
|
||||
custom:
|
||||
Issue: ""
|
||||
SchemaChange: No schema change
|
||||
6
.changes/unreleased/Fixed-20260112-153337.yaml
Normal file
6
.changes/unreleased/Fixed-20260112-153337.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
kind: Fixed
|
||||
body: Fix desactivation date for Goals and results
|
||||
time: 2026-01-12T15:33:37.95108325+01:00
|
||||
custom:
|
||||
Issue: "489"
|
||||
SchemaChange: No schema change
|
||||
7
.changes/unreleased/Fixed-20260113-162130.yaml
Normal file
7
.changes/unreleased/Fixed-20260113-162130.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
kind: Fixed
|
||||
body: |
|
||||
Prevent sending a notification when the user sign the document himself
|
||||
time: 2026-01-13T16:21:30.279454299+01:00
|
||||
custom:
|
||||
Issue: "490"
|
||||
SchemaChange: No schema change
|
||||
@@ -1,6 +0,0 @@
|
||||
kind: UX
|
||||
body: Improve the ux of the address field in the person creation form
|
||||
time: 2026-01-06T14:28:13.033420033+01:00
|
||||
custom:
|
||||
Issue: "487"
|
||||
SchemaChange: No schema change
|
||||
@@ -21,6 +21,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-redis": "*",
|
||||
"ext-zlib": "*",
|
||||
"composer-runtime-api": "*",
|
||||
"champs-libres/wopi-bundle": "dev-symfony-v5@dev",
|
||||
"champs-libres/wopi-lib": "dev-master@dev",
|
||||
"doctrine/data-fixtures": "^1.8",
|
||||
|
||||
@@ -72,14 +72,20 @@
|
||||
|
||||
{% macro table_results(actualCharges, actualResources, results) %}
|
||||
|
||||
{% set now = date() %}
|
||||
|
||||
{% set totalCharges = 0 %}
|
||||
{% for c in actualCharges %}
|
||||
{% set totalCharges = totalCharges + c.amount %}
|
||||
{% if c.startDate <= now and (c.endDate is null or c.endDate >= now) %}
|
||||
{% set totalCharges = totalCharges + c.amount %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% set totalResources = 0 %}
|
||||
{% for r in actualResources %}
|
||||
{% set totalResources = totalResources + r.amount %}
|
||||
{% if r.startDate <= now and (r.endDate is null or r.endDate >= now) %}
|
||||
{% set totalResources = totalResources + r.amount %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% set result = (totalResources - totalCharges) %}
|
||||
|
||||
@@ -45,10 +45,10 @@
|
||||
:class="getClassButton"
|
||||
type="button"
|
||||
name="button"
|
||||
:title="getTextButton"
|
||||
:title="trans(getTextButton)"
|
||||
>
|
||||
<span v-if="displayTextButton">{{
|
||||
getTextButton
|
||||
trans(getTextButton)
|
||||
}}</span>
|
||||
</button>
|
||||
</template>
|
||||
@@ -73,10 +73,10 @@
|
||||
:class="getClassButton"
|
||||
type="button"
|
||||
name="button"
|
||||
:title="getTextButton"
|
||||
:title="trans(getTextButton)"
|
||||
>
|
||||
<span v-if="displayTextButton">{{
|
||||
getTextButton
|
||||
trans(getTextButton)
|
||||
}}</span>
|
||||
</button>
|
||||
</template>
|
||||
@@ -97,9 +97,11 @@
|
||||
:class="getClassButton"
|
||||
type="button"
|
||||
name="button"
|
||||
:title="getTextButton"
|
||||
:title="trans(getTextButton)"
|
||||
>
|
||||
<span v-if="displayTextButton">{{ getTextButton }}</span>
|
||||
<span v-if="displayTextButton">{{
|
||||
trans(getTextButton)
|
||||
}}</span>
|
||||
</button>
|
||||
</template>
|
||||
</action-buttons>
|
||||
@@ -175,18 +177,16 @@ export default {
|
||||
},
|
||||
getTextButton() {
|
||||
if (
|
||||
typeof this.options.button !== "undefined" &&
|
||||
typeof this.options.button.text !== "undefined"
|
||||
typeof this.options.button.text !== "undefined" &&
|
||||
(this.options.button.text.edit !== null ||
|
||||
this.options.button.text.create !== null)
|
||||
) {
|
||||
const customText = this.context.edit
|
||||
? this.options.button.text.edit
|
||||
: this.options.button.text.create;
|
||||
|
||||
if (customText !== null) {
|
||||
return customText;
|
||||
}
|
||||
// console.log('this.options.button.text', this.options.button.text)
|
||||
return this.context.edit
|
||||
? ACTIVITY_CREATE_ADDRESS
|
||||
: ACTIVITY_EDIT_ADDRESS;
|
||||
}
|
||||
|
||||
console.log("defaultz", this.defaultz);
|
||||
return this.context.edit
|
||||
? this.defaultz.button.text.edit
|
||||
: this.defaultz.button.text.create;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
<p>
|
||||
{{ 'This program is free software: you can redistribute it and/or modify it under the terms of the <strong>GNU Affero General Public License</strong>'|trans|raw }}
|
||||
<br/>
|
||||
{% if get_chill_version() %}
|
||||
{{ 'footer.Running chill version %version%'|trans({ '%version%': get_chill_version() }) }}
|
||||
{% endif %}
|
||||
<br/>
|
||||
<a name="bottom" class="btn text-white" href="https://gitea.champs-libres.be/Chill-project/manuals/releases" target="_blank">
|
||||
{{ 'User manual'|trans }}
|
||||
</a>
|
||||
|
||||
45
src/Bundle/ChillMainBundle/Service/VersionProvider.php
Normal file
45
src/Bundle/ChillMainBundle/Service/VersionProvider.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Service;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
|
||||
readonly class VersionProvider
|
||||
{
|
||||
public function __construct(private string $packageName) {}
|
||||
|
||||
public function getVersion(): string
|
||||
{
|
||||
try {
|
||||
$version = InstalledVersions::getPrettyVersion($this->packageName);
|
||||
|
||||
if (null === $version) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
return $version;
|
||||
} catch (\OutOfBoundsException) {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
public function getFormattedVersion(): string
|
||||
{
|
||||
$version = $this->getVersion();
|
||||
|
||||
if ('unknown' === $version) {
|
||||
return 'Version unavailable';
|
||||
}
|
||||
|
||||
return $version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Templating;
|
||||
|
||||
use Chill\MainBundle\Service\VersionProvider;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class VersionRenderExtension extends AbstractExtension
|
||||
{
|
||||
public function __construct(
|
||||
private readonly VersionProvider $versionProvider,
|
||||
) {}
|
||||
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('get_chill_version', $this->getChillVersion(...)),
|
||||
];
|
||||
}
|
||||
|
||||
public function getChillVersion(): string
|
||||
{
|
||||
return $this->versionProvider->getFormattedVersion();
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,9 @@ use Chill\MainBundle\Entity\Notification;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Entity\UserGroup;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature;
|
||||
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
|
||||
use Chill\MainBundle\Workflow\EntityWorkflowManager;
|
||||
use Chill\MainBundle\Workflow\EventSubscriber\NotificationOnTransition;
|
||||
@@ -87,7 +89,7 @@ final class NotificationOnTransitionTest extends TestCase
|
||||
->willReturn([]);
|
||||
|
||||
$registry = $this->prophesize(Registry::class);
|
||||
$registry->get(Argument::type(EntityWorkflow::class), Argument::type('string'))
|
||||
$registry->get(Argument::type(EntityWorkflow::class), Argument::any())
|
||||
->willReturn($workflow);
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
@@ -111,4 +113,74 @@ final class NotificationOnTransitionTest extends TestCase
|
||||
|
||||
$notificationOnTransition->onCompletedSendNotification($event);
|
||||
}
|
||||
|
||||
public function testOnCompleteDoNotSendNotificationIfStepCreatedByPreviousSignature(): void
|
||||
{
|
||||
$dest = new User();
|
||||
$currentUser = new User();
|
||||
$workflowProphecy = $this->prophesize(WorkflowInterface::class);
|
||||
$workflow = $workflowProphecy->reveal();
|
||||
$entityWorkflow = new EntityWorkflow();
|
||||
$entityWorkflow
|
||||
->setWorkflowName('workflow_name')
|
||||
->setRelatedEntityClass(\stdClass::class)
|
||||
->setRelatedEntityId(1);
|
||||
// force an id to entityWorkflow:
|
||||
$reflection = new \ReflectionClass($entityWorkflow);
|
||||
$id = $reflection->getProperty('id');
|
||||
$id->setValue($entityWorkflow, 1);
|
||||
|
||||
$previousStep = new EntityWorkflowStep();
|
||||
$previousStep->addSignature($signature = new EntityWorkflowStepSignature($previousStep, $dest));
|
||||
$signature->setState(EntityWorkflowSignatureStateEnum::SIGNED);
|
||||
|
||||
$currentStep = new EntityWorkflowStep();
|
||||
$currentStep->addDestUser($dest);
|
||||
$currentStep->setCurrentStep('to_state');
|
||||
|
||||
$entityWorkflow->addStep($previousStep);
|
||||
$entityWorkflow->addStep($currentStep);
|
||||
|
||||
$em = $this->prophesize(EntityManagerInterface::class);
|
||||
|
||||
// we check that NO notification has been persisted for $dest
|
||||
$em->persist(Argument::that(
|
||||
fn ($notificationCandidate) => $notificationCandidate instanceof Notification && $notificationCandidate->getAddressees()->contains($dest)
|
||||
))->shouldNotBeCalled();
|
||||
|
||||
$engine = $this->prophesize(\Twig\Environment::class);
|
||||
$engine->render(Argument::type('string'), Argument::type('array'))
|
||||
->willReturn('dummy text');
|
||||
|
||||
$extractor = $this->prophesize(MetadataExtractor::class);
|
||||
$extractor->buildArrayPresentationForPlace(Argument::type(EntityWorkflow::class), Argument::any())
|
||||
->willReturn([]);
|
||||
$extractor->buildArrayPresentationForWorkflow(Argument::any())
|
||||
->willReturn([]);
|
||||
|
||||
$registry = $this->prophesize(Registry::class);
|
||||
$registry->get(Argument::type(EntityWorkflow::class), Argument::any())
|
||||
->willReturn($workflow);
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn(null);
|
||||
|
||||
$entityWorkflowHandler = $this->prophesize(EntityWorkflowHandlerInterface::class);
|
||||
$entityWorkflowHandler->getEntityTitle($entityWorkflow)->willReturn('workflow title');
|
||||
$entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class);
|
||||
$entityWorkflowManager->getHandler($entityWorkflow)->willReturn($entityWorkflowHandler->reveal());
|
||||
|
||||
$notificationOnTransition = new NotificationOnTransition(
|
||||
$em->reveal(),
|
||||
$engine->reveal(),
|
||||
$extractor->reveal(),
|
||||
$security->reveal(),
|
||||
$registry->reveal(),
|
||||
$entityWorkflowManager->reveal(),
|
||||
);
|
||||
|
||||
$event = new Event($entityWorkflow, new Marking(), new Transition('dummy_transition', ['from_state'], ['to_state']), $workflow);
|
||||
|
||||
$notificationOnTransition->onCompletedSendNotification($event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,10 @@ class NotificationOnTransition implements EventSubscriberInterface
|
||||
|
||||
foreach ($dests as $subscriber) {
|
||||
if (
|
||||
// prevent to send a notification to the one who created the step
|
||||
$this->security->getUser() === $subscriber
|
||||
// prevent to send a notification if the user applyied a signature on the previous step
|
||||
|| $this->isStepCreatedByPreviousSignature($entityWorkflow, $subscriber)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -131,4 +134,31 @@ class NotificationOnTransition implements EventSubscriberInterface
|
||||
$this->entityManager->persist($notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current step in the workflow was created by a previous signature of the specified user.
|
||||
*
|
||||
* This method retrieves the current step of the workflow and its preceding step. It iterates through
|
||||
* the signatures of the preceding step to verify if the provided user is the signer of any of those
|
||||
* signatures. Returns true if the user matches any signer; otherwise, returns false.
|
||||
*
|
||||
* @param EntityWorkflow $entityWorkflow the workflow entity containing the current step and its details
|
||||
* @param User $user the user to check against the signatures of the previous step in the workflow
|
||||
*
|
||||
* @return bool true if the specified user created the step via a previous signature, false otherwise
|
||||
*/
|
||||
private function isStepCreatedByPreviousSignature(EntityWorkflow $entityWorkflow, User $user): bool
|
||||
{
|
||||
$step = $entityWorkflow->getCurrentStepChained();
|
||||
$previous = $step->getPrevious();
|
||||
|
||||
|
||||
foreach ($previous->getSignatures() as $signature) {
|
||||
if ($signature->getSigner() === $user) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,3 +115,7 @@ services:
|
||||
$vienEntityInfoProviders: !tagged_iterator chill_main.entity_info_provider
|
||||
|
||||
Chill\MainBundle\Action\User\UpdateProfile\UpdateProfileCommandHandler: ~
|
||||
|
||||
Chill\MainBundle\Service\VersionProvider:
|
||||
arguments:
|
||||
$packageName: 'chill-project/chill-bundles'
|
||||
|
||||
@@ -66,3 +66,7 @@ services:
|
||||
resource: './../../Templating/Listing'
|
||||
|
||||
Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface: '@Chill\MainBundle\Templating\Listing\FilterOrderHelperFactory'
|
||||
|
||||
Chill\MainBundle\Templating\VersionRenderExtension:
|
||||
tags:
|
||||
- { name: twig.extension }
|
||||
|
||||
@@ -48,6 +48,9 @@ See: Voir
|
||||
Name: Nom
|
||||
Label: Nom
|
||||
|
||||
footer:
|
||||
Running chill version %version%: "Version de Chill: %version%"
|
||||
|
||||
user:
|
||||
current_user: Utilisateur courant
|
||||
profile:
|
||||
|
||||
@@ -135,13 +135,15 @@ final class PersonController extends AbstractController
|
||||
$this->lastPostDataReset();
|
||||
|
||||
$address = $form->get('address')->getData();
|
||||
$addressForm = (bool) $form->get('addressForm')->getData();
|
||||
|
||||
if (null !== $address) {
|
||||
if (null !== $address && $addressForm) {
|
||||
$household = new Household();
|
||||
|
||||
$member = new HouseholdMember();
|
||||
$member->setPerson($person);
|
||||
$member->setStartDate(new \DateTimeImmutable());
|
||||
|
||||
$household->addMember($member);
|
||||
$household->setForceAddress($address);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class SocialWorkEvaluationApiController extends AbstractController
|
||||
$pagination->getCurrentPageFirstItemNumber(),
|
||||
$pagination->getItemsPerPage()
|
||||
);
|
||||
$collection = new Collection($evaluations, $pagination);
|
||||
$collection = new Collection(array_values($evaluations), $pagination);
|
||||
|
||||
return $this->json($collection, Response::HTTP_OK, [], ['groups' => ['read']]);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,15 @@ class SocialWorkGoalApiController extends ApiController
|
||||
|
||||
public function listBySocialAction(Request $request, SocialAction $action): Response
|
||||
{
|
||||
$totalItems = $this->goalRepository->countBySocialActionWithDescendants($action);
|
||||
$paginator = $this->getPaginatorFactory()->create($totalItems);
|
||||
$totalItems = $this->goalRepository->countBySocialActionWithDescendants($action, true);
|
||||
$paginator = $this->paginator->create($totalItems);
|
||||
|
||||
$entities = $this->goalRepository->findBySocialActionWithDescendants(
|
||||
$action,
|
||||
['id' => 'ASC'],
|
||||
$paginator->getItemsPerPage(),
|
||||
$paginator->getCurrentPageFirstItemNumber()
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
onlyActive: true
|
||||
);
|
||||
|
||||
$model = new Collection($entities, $paginator);
|
||||
|
||||
@@ -25,14 +25,15 @@ class SocialWorkResultApiController extends ApiController
|
||||
|
||||
public function listByGoal(Request $request, Goal $goal): Response
|
||||
{
|
||||
$totalItems = $this->resultRepository->countByGoal($goal);
|
||||
$totalItems = $this->resultRepository->countByGoal($goal, true);
|
||||
$paginator = $this->getPaginatorFactory()->create($totalItems);
|
||||
|
||||
$entities = $this->resultRepository->findByGoal(
|
||||
$goal,
|
||||
['id' => 'ASC'],
|
||||
$paginator->getItemsPerPage(),
|
||||
$paginator->getCurrentPageFirstItemNumber()
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
onlyActive: true,
|
||||
);
|
||||
|
||||
$model = new Collection($entities, $paginator);
|
||||
@@ -42,14 +43,15 @@ class SocialWorkResultApiController extends ApiController
|
||||
|
||||
public function listBySocialAction(Request $request, SocialAction $action): Response
|
||||
{
|
||||
$totalItems = $this->resultRepository->countBySocialActionWithDescendants($action);
|
||||
$totalItems = $this->resultRepository->countBySocialActionWithDescendants($action, true);
|
||||
$paginator = $this->getPaginatorFactory()->create($totalItems);
|
||||
|
||||
$entities = $this->resultRepository->findBySocialActionWithDescendants(
|
||||
$action,
|
||||
['id' => 'ASC'],
|
||||
$paginator->getItemsPerPage(),
|
||||
$paginator->getCurrentPageFirstItemNumber()
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
onlyActive: true
|
||||
);
|
||||
|
||||
$model = new Collection($entities, $paginator);
|
||||
|
||||
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\PersonBundle\Form;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Form\Event\CustomizeFormEvent;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||
@@ -26,9 +27,12 @@ use libphonenumber\PhoneNumberType;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Callback;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
final class CreationPersonType extends AbstractType
|
||||
{
|
||||
@@ -73,10 +77,16 @@ final class CreationPersonType extends AbstractType
|
||||
->add('email', EmailType::class, [
|
||||
'required' => false,
|
||||
])
|
||||
->add('addressForm', CheckboxType::class, [
|
||||
'label' => 'Create a household and add an address',
|
||||
'required' => false,
|
||||
'mapped' => false,
|
||||
'help' => 'A new household will be created. The person will be member of this household.',
|
||||
])
|
||||
->add('address', PickAddressType::class, [
|
||||
'required' => false,
|
||||
'mapped' => false,
|
||||
'label' => 'Address',
|
||||
'label' => false,
|
||||
]);
|
||||
|
||||
if ($this->askCenters) {
|
||||
@@ -103,6 +113,9 @@ final class CreationPersonType extends AbstractType
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Person::class,
|
||||
'constraints' => [
|
||||
new Callback($this->validateCheckedAddress(...)),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -113,4 +126,18 @@ final class CreationPersonType extends AbstractType
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function validateCheckedAddress($data, ExecutionContextInterface $context, $payload): void
|
||||
{
|
||||
/** @var bool $addressFrom */
|
||||
$addressFrom = $context->getObject()->get('addressForm')->getData();
|
||||
/** @var ?Address $address */
|
||||
$address = $context->getObject()->get('address')->getData();
|
||||
|
||||
if ($addressFrom && null === $address) {
|
||||
$context->buildViolation('person_creation.If you want to create an household, an address is required')
|
||||
->atPath('addressForm')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,23 @@ use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Clock\ClockInterface;
|
||||
|
||||
final readonly class GoalRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private ClockInterface $clock,
|
||||
private RequestStack $requestStack,
|
||||
) {
|
||||
$this->repository = $entityManager->getRepository(Goal::class);
|
||||
}
|
||||
|
||||
public function countBySocialActionWithDescendants(SocialAction $action): int
|
||||
public function countBySocialActionWithDescendants(SocialAction $action, bool $onlyActive = false): int
|
||||
{
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action);
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action, $onlyActive);
|
||||
$qb->select('COUNT(g)');
|
||||
|
||||
return $qb
|
||||
@@ -67,9 +71,9 @@ final readonly class GoalRepository implements ObjectRepository
|
||||
/**
|
||||
* @return Goal[]
|
||||
*/
|
||||
public function findBySocialActionWithDescendants(SocialAction $action, array $orderBy = [], ?int $limit = null, ?int $offset = null): array
|
||||
public function findBySocialActionWithDescendants(SocialAction $action, array $orderBy = [], ?int $limit = null, ?int $offset = null, bool $onlyActive = false): array
|
||||
{
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action);
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action, $onlyActive);
|
||||
$qb->select('g');
|
||||
|
||||
$qb->andWhere(
|
||||
@@ -200,7 +204,7 @@ final readonly class GoalRepository implements ObjectRepository
|
||||
}
|
||||
}
|
||||
|
||||
private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder
|
||||
private function buildQueryBySocialActionWithDescendants(SocialAction $action, bool $onlyActive): QueryBuilder
|
||||
{
|
||||
$actions = $action->getDescendantsWithThis();
|
||||
|
||||
@@ -215,6 +219,11 @@ final readonly class GoalRepository implements ObjectRepository
|
||||
}
|
||||
$qb->where($orx);
|
||||
|
||||
if ($onlyActive) {
|
||||
$qb->andWhere('g.desactivationDate > :now OR g.desactivationDate IS NULL')
|
||||
->setParameter('now', $this->clock->now());
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,19 +21,23 @@ use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Clock\ClockInterface;
|
||||
|
||||
final readonly class ResultRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private ClockInterface $clock,
|
||||
private RequestStack $requestStack,
|
||||
) {
|
||||
$this->repository = $entityManager->getRepository(Result::class);
|
||||
}
|
||||
|
||||
public function countByGoal(Goal $goal): int
|
||||
public function countByGoal(Goal $goal, bool $onlyActive = false): int
|
||||
{
|
||||
$qb = $this->buildQueryByGoal($goal);
|
||||
$qb = $this->buildQueryByGoal($goal, $onlyActive);
|
||||
$qb->select('COUNT(r)');
|
||||
|
||||
return $qb
|
||||
@@ -41,9 +45,9 @@ final readonly class ResultRepository implements ObjectRepository
|
||||
->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function countBySocialActionWithDescendants(SocialAction $action): int
|
||||
public function countBySocialActionWithDescendants(SocialAction $action, bool $onlyActive = false): int
|
||||
{
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action);
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action, $onlyActive);
|
||||
$qb->select('COUNT(r)');
|
||||
|
||||
return $qb
|
||||
@@ -78,9 +82,9 @@ final readonly class ResultRepository implements ObjectRepository
|
||||
/**
|
||||
* @return array<Result>
|
||||
*/
|
||||
public function findByGoal(Goal $goal, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
public function findByGoal(Goal $goal, ?array $orderBy = null, ?int $limit = null, ?int $offset = null, bool $onlyActive = false): array
|
||||
{
|
||||
$qb = $this->buildQueryByGoal($goal);
|
||||
$qb = $this->buildQueryByGoal($goal, $onlyActive);
|
||||
|
||||
if (null !== $orderBy) {
|
||||
foreach ($orderBy as $sort => $order) {
|
||||
@@ -99,9 +103,9 @@ final readonly class ResultRepository implements ObjectRepository
|
||||
/**
|
||||
* @return Result[]
|
||||
*/
|
||||
public function findBySocialActionWithDescendants(SocialAction $action, array $orderBy = [], ?int $limit = null, ?int $offset = null): array
|
||||
public function findBySocialActionWithDescendants(SocialAction $action, array $orderBy = [], ?int $limit = null, ?int $offset = null, bool $onlyActive = false): array
|
||||
{
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action);
|
||||
$qb = $this->buildQueryBySocialActionWithDescendants($action, $onlyActive);
|
||||
$qb->select('r');
|
||||
|
||||
foreach ($orderBy as $sort => $order) {
|
||||
@@ -222,17 +226,22 @@ final readonly class ResultRepository implements ObjectRepository
|
||||
}
|
||||
}
|
||||
|
||||
private function buildQueryByGoal(Goal $goal): QueryBuilder
|
||||
private function buildQueryByGoal(Goal $goal, bool $onlyActive): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('r');
|
||||
|
||||
$qb->where(':goal MEMBER OF r.goals')
|
||||
->setParameter('goal', $goal);
|
||||
|
||||
if ($onlyActive) {
|
||||
$qb->andWhere('r.desactivationDate > :now OR r.desactivationDate IS NULL')
|
||||
->setParameter('now', $this->clock->now());
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder
|
||||
private function buildQueryBySocialActionWithDescendants(SocialAction $action, bool $onlyActive = false): QueryBuilder
|
||||
{
|
||||
$actions = $action->getDescendantsWithThis();
|
||||
|
||||
@@ -247,6 +256,11 @@ final readonly class ResultRepository implements ObjectRepository
|
||||
}
|
||||
$qb->where($orx);
|
||||
|
||||
if ($onlyActive) {
|
||||
$qb->andWhere('r.desactivationDate > :now OR r.desactivationDate IS NULL')
|
||||
->setParameter('now', $this->clock->now());
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,14 +105,11 @@
|
||||
{{ form_row(form.center) }}
|
||||
{% endif %}
|
||||
|
||||
<div id="address" class="row mb-1" style="display:flex;" title="{{ 'A new household will be created. The person will be member of this household.'|trans }}">
|
||||
{{ form_label(form.address, 'Address'|trans) }}
|
||||
<div class="col-sm-8">
|
||||
{{ form_widget(form.address) }}
|
||||
<div class="form-text text-muted">
|
||||
{{ 'A new household will be created. The person will be member of this household.'|trans }}
|
||||
</div>
|
||||
</div>
|
||||
<div id=addressForm>
|
||||
{{ form_row(form.addressForm) }}
|
||||
</div>
|
||||
<div id=address>
|
||||
{{ form_row(form.address) }}
|
||||
</div>
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</td>
|
||||
<td>
|
||||
{% if entity.desactivationDate is not null %}
|
||||
{{ entity.desactivationDate|date('Y-m-d') }}
|
||||
{{ entity.desactivationDate|format_date('medium') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<td>{{ entity.title|localize_translatable_string }}</td>
|
||||
<td>
|
||||
{% if entity.desactivationDate is not null %}
|
||||
{{ entity.desactivationDate|date('Y-m-d') }}
|
||||
{{ entity.desactivationDate|format_date('medium') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user