Merge remote-tracking branch 'origin/master'

This commit is contained in:
Julien Fastré 2022-03-24 20:53:10 +01:00
commit 866bcec114
148 changed files with 1839 additions and 1024 deletions

View File

@ -11,6 +11,9 @@ and this project adheres to
## Unreleased
<!-- write down unreleased development here -->
* [activity] display error messages above the form in creating a new location (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/481)
* [activity] show required field in activity edit/new by an asterix in the vuejs fields (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/494)
* [ACL] fix allow to see the course, event if the scope'course does not contains the scope's user
* [search] enforce limit of results for fetching rsults by search api https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/576
* [activity] Fix delete button for document (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/554)
* [activity] Add return path the document generation (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/553)
@ -35,6 +38,7 @@ and this project adheres to
* [Person/Household list] when listing other simultaneous members of an household, exclude the members on person, not on members (avoid to show two membersship with the same person)
* [draft periods] add a delete button (if acl granted) on each draft period listed on draft period page (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/463)
* [Person] Display suffixText in RenderPerson, PersonText.vue, RenderPersonBox.vue (was made for displaying "enfant confie") (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/441)
* [budget]: budget enabled for persons and households (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/469)
* [person] residential address: show residential address or info in PersonRenderBox, refactor Residential Address (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/439)
* [thirdparty] Add a contact to a thirdparty from within onTheFly (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/345)
* [documents] Improve flex-table item-col placement when long buttons and long metadata
@ -57,6 +61,7 @@ and this project adheres to
* [parcours] List of parcours for a specific user so they can be reassigned in case of absence (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/509)
* [thirdparty] Thirdparty view page, english text translated (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/534)
* [social_action] Translation changed in evaluation section (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/512)
* [filiation] Possible to add person (or create onthefly) to add to filiation graph + add relation (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/519)
* [household] Within parcours listing page of household add create button (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/560)
* [person_resource] bugfix when adding thirdparty or freetext resource (no issue)
* [aside_activity] style correction + sticky-form create button (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/529)

View File

@ -32,7 +32,7 @@ Then, render the pagination using the dedicated twig function.
{% block title 'Item list'|trans %}
{% block personcontent %}
{% block content %}
<table>

View File

@ -156,7 +156,7 @@ This layout extend `ChillMainBundle::layoutWithVerticalMenu.html.twig` add the p
It proposes 1 new block :
* personcontent
* content
* where to display the information of the person

View File

@ -222,33 +222,6 @@ parameters:
count: 1
path: src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php
-
message:
"""
#^Class Chill\\\\AMLI\\\\BudgetBundle\\\\Controller\\\\AbstractElementController extends deprecated class Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\:
since Symfony 4\\.2, use "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\AbstractController" instead\\.$#
"""
count: 1
path: src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php
-
message:
"""
#^Class Chill\\\\AMLI\\\\BudgetBundle\\\\Controller\\\\ElementController extends deprecated class Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\:
since Symfony 4\\.2, use "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\AbstractController" instead\\.$#
"""
count: 1
path: src/Bundle/ChillBudgetBundle/Controller/ElementController.php
-
message:
"""
#^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\:
since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$#
"""
count: 1
path: src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php
-
message:
"""

View File

@ -125,7 +125,9 @@ class ActivityType extends AbstractType
}
if ($activityType->isVisible('socialIssues') && $accompanyingPeriod) {
$builder->add('socialIssues', HiddenType::class);
$builder->add('socialIssues', HiddenType::class, [
'required' => $activityType->getSocialIssuesVisible() === 2
]);
$builder->get('socialIssues')
->addModelTransformer(new CallbackTransformer(
static function (iterable $socialIssuesAsIterable): string {
@ -151,7 +153,9 @@ class ActivityType extends AbstractType
}
if ($activityType->isVisible('socialActions') && $accompanyingPeriod) {
$builder->add('socialActions', HiddenType::class);
$builder->add('socialActions', HiddenType::class, [
'required' => $activityType->getSocialActionsVisible() === 2
]);
$builder->get('socialActions')
->addModelTransformer(new CallbackTransformer(
static function (iterable $socialActionsAsIterable): string {
@ -339,7 +343,9 @@ class ActivityType extends AbstractType
}
if ($activityType->isVisible('location')) {
$builder->add('location', HiddenType::class)
$builder->add('location', HiddenType::class, [
'required' => $activityType->getLocationVisible() === 2
])
->get('location')
->addModelTransformer(new CallbackTransformer(
static function (?Location $location): string {

View File

@ -1,7 +1,7 @@
<template>
<teleport to="#location">
<div class="mb-3 row">
<label class="col-form-label col-sm-4">
<label :class="locationClassList">
{{ $t("activity.location") }}
</label>
<div class="col-sm-8">
@ -41,6 +41,12 @@ export default {
NewLocation,
VueMultiselect,
},
data() {
return {
locationClassList:
`col-form-label col-sm-4 ${document.querySelector('input#chill_activitybundle_activity_location').getAttribute('required') ? 'required' : ''}`,
}
},
computed: {
...mapState(["activity", "availableLocations"]),
...mapGetters(["suggestedEntities"]),

View File

@ -18,6 +18,12 @@
</template>
<template v-slot:body>
<form>
<div class="alert alert-warning" v-if="errors.length">
<ul>
<li v-for="(e, i) in errors" :key="i">{{ e }}</li>
</ul>
</div>
<div class="form-floating mb-3">
<select class="form-select form-select-lg" id="type" required v-model="selectType">
<option selected disabled value="">{{ $t('activity.choose_location_type') }}</option>
@ -54,11 +60,6 @@
<label for="email">{{ $t('activity.location_fields.email') }}</label>
</div>
<div class="alert alert-warning" v-if="errors.length">
<ul>
<li v-for="(e, i) in errors" :key="i">{{ e }}</li>
</ul>
</div>
</form>
</template>
<template v-slot:footer>

View File

@ -3,7 +3,7 @@
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_issues') }}</label>
<label :class="socialIssuesClassList">{{ $t('activity.social_issues') }}</label>
</div>
<div class="col-8">
@ -42,7 +42,7 @@
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_actions') }}</label>
<label :class="socialActionsClassList">{{ $t('activity.social_actions') }}</label>
</div>
<div class="col-8">
@ -94,6 +94,10 @@ export default {
issueIsLoading: false,
actionIsLoading: false,
actionAreLoaded: false,
socialIssuesClassList:
`col-form-label ${document.querySelector('input#chill_activitybundle_activity_socialIssues').getAttribute('required') ? 'required' : ''}`,
socialActionsClassList:
`col-form-label ${document.querySelector('input#chill_activitybundle_activity_socialActions').getAttribute('required') ? 'required' : ''}`,
}
},
computed: {

View File

@ -5,7 +5,7 @@
{% block title 'Remove activity'|trans %}
{% block personcontent %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove activity'|trans,

View File

@ -35,7 +35,7 @@
{{ form_row(edit_form.socialActions) }}
{% endif %}
{%- if edit_form.socialIssues is defined or edit_form.socialIssues is defined -%}
{%- if edit_form.socialIssues is defined or edit_form.socialActions is defined -%}
<div id="social-issues-acc"></div>
{% endif %}

View File

@ -20,7 +20,7 @@
{% block title 'Update activity'|trans %}
{% block personcontent %}
{% block content %}
<div class="activity-edit">
<div id="activity"></div> {# <=== vue component #}

View File

@ -30,7 +30,7 @@
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{% endblock %}
{% block personcontent %}
{% block content %}
{% set person_id = null %}
{% if person %}

View File

@ -35,7 +35,7 @@
{{ form_row(form.socialActions) }}
{% endif %}
{%- if form.socialIssues is defined or form.socialIssues is defined -%}
{%- if form.socialIssues is defined or form.socialActions is defined -%}
<div id="social-issues-acc"></div>
{% endif %}

View File

@ -4,7 +4,7 @@
{% block title 'Activity creation' |trans %}
{% block personcontent %}
{% block content %}
<div class="activity-new">
<div id="activity"></div> {# <=== vue component #}

View File

@ -4,6 +4,6 @@
{% block title 'Activity creation'|trans %}
{% block personcontent %}
{% block content %}
{% include 'ChillActivityBundle:Activity:selectType.html.twig' %}
{% endblock %}

View File

@ -18,11 +18,11 @@
{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %}
{% block personcontent -%}
{% block content -%}
<div class="activity-show">
{% include 'ChillActivityBundle:Activity:show.html.twig' with {'context': 'person'} %}
</div>
{% endblock personcontent %}
{% endblock %}
{% block block_post_menu %}
<div class="post-menu pt-4">

View File

@ -25,7 +25,7 @@
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}<!-- block personcontent empty -->
{% block admin_content %}<!-- block content empty -->
<h1>{{ 'Activity configuration' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@ -6,7 +6,7 @@
{% block layout_wvm_content %}
{% block admin_content %}
<!-- block personcontent empty -->
<!-- block content empty -->
<h1>{{ 'Aside activity configuration'|trans }}</h1>
{% endblock %}
{% endblock %}

View File

@ -9,9 +9,9 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Calculator;
namespace Chill\BudgetBundle\Calculator;
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
use Chill\BudgetBundle\Entity\AbstractElement;
interface CalculatorInterface
{

View File

@ -9,9 +9,9 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Calculator;
namespace Chill\BudgetBundle\Calculator;
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
use Chill\BudgetBundle\Entity\AbstractElement;
use OutOfBoundsException;
use function array_key_exists;

View File

@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Calculator;
namespace Chill\BudgetBundle\Calculator;
class CalculatorResult
{

View File

@ -9,12 +9,12 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle;
namespace Chill\BudgetBundle;
use Chill\AMLI\BudgetBundle\DependencyInjection\Compiler\CalculatorCompilerPass;
use Chill\BudgetBundle\DependencyInjection\Compiler\CalculatorCompilerPass;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillAMLIBudgetBundle extends Bundle
class ChillBudgetBundle extends Bundle
{
public function build(\Symfony\Component\DependencyInjection\ContainerBuilder $container)
{

View File

@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Config;
namespace Chill\BudgetBundle\Config;
class ConfigRepository
{
@ -29,6 +29,11 @@ class ConfigRepository
$this->charges = $charges;
}
public function getChargesKeys(): array
{
return array_map(static function ($element) { return $element['key']; }, $this->charges);
}
/**
* @return array where keys are the resource'key and label the ressource label
*/
@ -43,6 +48,11 @@ class ConfigRepository
return $charges;
}
public function getResourcesKeys(): array
{
return array_map(static function ($element) { return $element['key']; }, $this->resources);
}
/**
* @return array where keys are the resource'key and label the ressource label
*/

View File

@ -9,37 +9,29 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Controller;
namespace Chill\BudgetBundle\Controller;
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\BudgetBundle\Entity\AbstractElement;
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;
use function get_class;
abstract class AbstractElementController extends Controller
abstract class AbstractElementController extends AbstractController
{
/**
* @var LoggerInterface
*/
protected $chillMainLogger;
protected LoggerInterface $chillMainLogger;
/**
* @var EntityManagerInterface
*/
protected $em;
protected EntityManagerInterface $em;
/**
* @var TranslatorInterface
*/
protected $translator;
protected TranslatorInterface $translator;
public function __construct(
EntityManagerInterface $em,
@ -59,16 +51,22 @@ abstract class AbstractElementController extends Controller
*
* @param mixed $template
* @param mixed $flashMessage
*
* @return \Symfony\Component\BrowserKit\Response
*/
protected function _delete(AbstractElement $element, Request $request, $template, $flashMessage)
protected function _delete(AbstractElement $element, Request $request, $template, $flashMessage): Response
{
$this->denyAccessUnlessGranted(BudgetElementVoter::DELETE, $element, 'You are not '
. 'allowed to delete this family membership');
. 'allowed to delete this item');
$form = $this->createDeleteForm();
if (null !== $element->getPerson()) {
$entity = $element->getPerson();
$indexPage = 'chill_budget_elements_index';
} else {
$entity = $element->getHousehold();
$indexPage = 'chill_budget_elements_household_index';
}
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
@ -88,8 +86,8 @@ abstract class AbstractElementController extends Controller
$this->addFlash('success', $this->translator
->trans($flashMessage));
return $this->redirectToRoute('chill_budget_elements_index', [
'id' => $element->getPerson()->getId(),
return $this->redirectToRoute($indexPage, [
'id' => $entity->getId(),
]);
}
}
@ -103,13 +101,23 @@ abstract class AbstractElementController extends Controller
/**
* @param string $template
* @param string $flashOnSuccess
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function _edit(AbstractElement $element, Request $request, $template, $flashOnSuccess)
protected function _edit(AbstractElement $element, Request $request, $template, $flashOnSuccess): Response
{
$this->denyAccessUnlessGranted(BudgetElementVoter::UPDATE, $element);
if (null !== $element->getPerson()) {
$entity = $element->getPerson();
$entityStr = 'person';
$indexPage = 'chill_budget_elements_index';
} else {
$entity = $element->getHousehold();
$entityStr = 'household';
$indexPage = 'chill_budget_elements_household_index';
}
$entity = null !== $element->getPerson() ? $element->getPerson() : $element->getHousehold();
$form = $this->createForm($this->getType(), $element);
$form->add('submit', SubmitType::class);
@ -121,29 +129,39 @@ abstract class AbstractElementController extends Controller
$this->addFlash('success', $this->translator->trans($flashOnSuccess));
return $this->redirectToRoute('chill_budget_elements_index', [
'id' => $element->getPerson()->getId(),
return $this->redirectToRoute($indexPage, [
'id' => $entity->getId(),
]);
}
return $this->render($template, [
'element' => $element,
'form' => $form->createView(),
'person' => $element->getPerson(),
$entityStr => $entity,
]);
}
/**
* @param mixed $template
* @param mixed $flashMessageOnSuccess
* @param mixed $entity
*/
protected function _new(Person $person, Request $request, $template, $flashMessageOnSuccess)
protected function _new($entity, Request $request, $template, $flashMessageOnSuccess)
{
/** @var \Chill\AMLI\BudgetBundle\Entity\AbstractElement $element */
$element = $this->createNewElement()
->setPerson($person);
/** @var AbstractElement $element */
$element = $this->createNewElement();
$this->denyAccessUnlessGranted(BudgetElementVoter::CREATE, $element);
if ($entity instanceof Person) {
$element->setPerson($entity);
$entityStr = 'person';
$indexPage = 'chill_budget_elements_index';
} else {
$element->setHousehold($entity);
$entityStr = 'household';
$indexPage = 'chill_budget_elements_household_index';
}
// $this->denyAccessUnlessGranted(BudgetElementVoter::CREATE, $entity);
$form = $this->createForm($this->getType(), $element);
$form->add('submit', SubmitType::class);
@ -157,8 +175,8 @@ abstract class AbstractElementController extends Controller
$this->addFlash('success', $this->translator->trans($flashMessageOnSuccess));
return $this->redirectToRoute('chill_budget_elements_index', [
'id' => $person->getId(),
return $this->redirectToRoute($indexPage, [
'id' => $entity->getId(),
]);
}
@ -168,7 +186,7 @@ abstract class AbstractElementController extends Controller
return $this->render($template, [
'form' => $form->createView(),
'person' => $person,
$entityStr => $entity,
'element' => $element,
]);
}
@ -183,7 +201,7 @@ abstract class AbstractElementController extends Controller
*/
protected function _view(AbstractElement $element, $template)
{
$this->denyAccessUnlessGranted(BudgetElementVoter::SHOW, $element);
$this->denyAccessUnlessGranted(BudgetElementVoter::SEE, $element);
return $this->render($template, [
'element' => $element,
@ -199,10 +217,8 @@ abstract class AbstractElementController extends Controller
/**
* Creates a form to delete a help request entity by id.
*
* @return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm()
private function createDeleteForm(): Form
{
return $this->createFormBuilder()
->setMethod(Request::METHOD_DELETE)

View File

@ -9,10 +9,11 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Controller;
namespace Chill\BudgetBundle\Controller;
use Chill\AMLI\BudgetBundle\Entity\Charge;
use Chill\AMLI\BudgetBundle\Form\ChargeType;
use Chill\BudgetBundle\Entity\Charge;
use Chill\BudgetBundle\Form\ChargeType;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
@ -32,7 +33,7 @@ class ChargeController extends AbstractElementController
return $this->_delete(
$charge,
$request,
'@ChillAMLIBudget/Charge/confirm_delete.html.twig',
'@ChillBudget/Charge/confirm_delete.html.twig',
'Charge deleted'
);
}
@ -50,7 +51,7 @@ class ChargeController extends AbstractElementController
return $this->_edit(
$charge,
$request,
'@ChillAMLIBudget/Charge/edit.html.twig',
'@ChillBudget/Charge/edit.html.twig',
'Charge updated'
);
}
@ -68,7 +69,25 @@ class ChargeController extends AbstractElementController
return $this->_new(
$person,
$request,
'@ChillAMLIBudget/Charge/new.html.twig',
'@ChillBudget/Charge/new.html.twig',
'Charge created'
);
}
/**
* @Route(
* "{_locale}/budget/charge/by-household/{id}/new",
* name="chill_budget_charge_household_new"
* )
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function newHouseholdAction(Request $request, Household $household)
{
return $this->_new(
$household,
$request,
'@ChillBudget/Charge/new.html.twig',
'Charge created'
);
}
@ -83,7 +102,7 @@ class ChargeController extends AbstractElementController
*/
public function viewAction(Charge $charge)
{
return $this->_view($charge, '@ChillAMLIBudget/Charge/view.html.twig');
return $this->_view($charge, '@ChillBudget/Charge/view.html.twig');
}
protected function createNewElement()

View File

@ -9,44 +9,33 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Controller;
namespace Chill\BudgetBundle\Controller;
use Chill\AMLI\BudgetBundle\Calculator\CalculatorManager;
use Chill\AMLI\BudgetBundle\Entity\Charge;
use Chill\AMLI\BudgetBundle\Entity\Resource;
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\BudgetBundle\Calculator\CalculatorManager;
use Chill\BudgetBundle\Entity\Charge;
use Chill\BudgetBundle\Entity\Resource;
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_merge;
use function count;
class ElementController extends Controller
class ElementController extends AbstractController
{
/**
* @var CalculatorManager
*/
protected $calculator;
protected CalculatorManager $calculator;
/**
* @var LoggerInterface
*/
protected $chillMainLogger;
protected LoggerInterface $chillMainLogger;
/**
* @var EntityManagerInterface
*/
protected $em;
protected EntityManagerInterface $em;
/**
* @var TranslatorInterface
*/
protected $translator;
protected TranslatorInterface $translator;
public function __construct(
EntityManagerInterface $em,
@ -68,11 +57,12 @@ class ElementController extends Controller
*/
public function indexAction(Person $person)
{
$this->denyAccessUnlessGranted(BudgetElementVoter::SHOW, $person);
$this->denyAccessUnlessGranted(BudgetElementVoter::SEE, $person);
$charges = $this->em
->getRepository(Charge::class)
->findByPerson($person);
$ressources = $this->em
->getRepository(Resource::class)
->findByPerson($person);
@ -81,10 +71,10 @@ class ElementController extends Controller
$actualCharges = $this->em
->getRepository(Charge::class)
->findByPersonAndDate($person, $now);
->findByEntityAndDate($person, $now);
$actualResources = $this->em
->getRepository(Resource::class)
->findByPersonAndDate($person, $now);
->findByEntityAndDate($person, $now);
$elements = array_merge($actualCharges, $actualResources);
@ -92,11 +82,79 @@ class ElementController extends Controller
$results = $this->calculator->calculateDefault($elements);
}
return $this->render('ChillAMLIBudgetBundle:Element:index.html.twig', [
return $this->render('ChillBudgetBundle:Person:index.html.twig', [
'person' => $person,
'charges' => $charges,
'resources' => $ressources,
'results' => $results ?? [],
]);
}
/**
* @Route(
* "{_locale}/budget/elements/by-household/{id}",
* name="chill_budget_elements_household_index"
* )
*/
public function indexHouseholdAction(Household $household)
{
$this->denyAccessUnlessGranted(BudgetElementVoter::SEE, $household);
$charges = $this->em
->getRepository(Charge::class)
->findByHousehold($household);
$ressources = $this->em
->getRepository(Resource::class)
->findByHousehold($household);
$now = new DateTime('now');
$actualCharges = $this->em
->getRepository(Charge::class)
->findByEntityAndDate($household, $now);
$actualResources = $this->em
->getRepository(Resource::class)
->findByEntityAndDate($household, $now);
$elements = array_merge($actualCharges, $actualResources);
if (count($elements) > 0) {
$results = $this->calculator->calculateDefault($elements);
}
// quick solution to calculate the sum, difference and amount from
// controller. This should be done from the calculators
// TODO replace this by calculators
$wholeCharges = $actualCharges;
$wholeResources = $actualResources;
foreach ($household->getCurrentPersons() as $person) {
$wholeCharges = array_merge(
$wholeCharges,
$this->em
->getRepository(Charge::class)
->findByEntityAndDate($person, $now)
);
$wholeResources = array_merge(
$wholeResources,
$this->em
->getRepository(Resource::class)
->findByEntityAndDate($person, $now)
);
}
return $this->render('ChillBudgetBundle:Household:index.html.twig', [
'household' => $household,
'charges' => $charges,
'resources' => $ressources,
'wholeResources' => array_filter($wholeResources, static function (Resource $r) use ($now) {
return $r->getStartDate() <= $now && ($r->getEndDate() === null || $r->getEndDate() >= $now);
}),
'wholeCharges' => array_filter($wholeCharges, static function (Charge $c) use ($now) {
return $c->getStartDate() <= $now && ($c->getEndDate() === null || $c->getEndDate() >= $now);
}),
'results' => $results ?? [],
]);
}
}

View File

@ -9,13 +9,15 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Controller;
namespace Chill\BudgetBundle\Controller;
use Chill\AMLI\BudgetBundle\Entity\Resource;
use Chill\AMLI\BudgetBundle\Form\ResourceType;
use Chill\BudgetBundle\Entity\Resource;
use Chill\BudgetBundle\Form\ResourceType;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ResourceController extends AbstractElementController
{
@ -24,15 +26,13 @@ class ResourceController extends AbstractElementController
* "{_locale}/budget/resource/{id}/delete",
* name="chill_budget_resource_delete"
* )
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function deleteAction(Request $request, Resource $resource)
{
return $this->_delete(
$resource,
$request,
'@ChillAMLIBudget/Resource/confirm_delete.html.twig',
'@ChillBudget/Resource/confirm_delete.html.twig',
'Resource deleted'
);
}
@ -42,33 +42,49 @@ class ResourceController extends AbstractElementController
* "{_locale}/budget/resource/{id}/edit",
* name="chill_budget_resource_edit"
* )
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function editAction(Request $request, Resource $resource)
public function editAction(Request $request, Resource $resource): Response
{
return $this->_edit(
$resource,
$request,
'@ChillAMLIBudget/Resource/edit.html.twig',
'@ChillBudget/Resource/edit.html.twig',
'Resource updated'
);
}
/**
* Create a new budget element for a person.
*
* @Route(
* "{_locale}/budget/resource/by-person/{id}/new",
* name="chill_budget_resource_new"
* )
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function newAction(Request $request, Person $person)
public function newAction(Request $request, Person $person): Response
{
return $this->_new(
$person,
$request,
'@ChillAMLIBudget/Resource/new.html.twig',
'@ChillBudget/Resource/new.html.twig',
'Resource created'
);
}
/**
* Create new budget element for a household.
*
* @Route(
* "{_locale}/budget/resource/by-household/{id}/new",
* name="chill_budget_resource_household_new"
* )
*/
public function newHouseholdAction(Request $request, Household $household): Response
{
return $this->_new(
$household,
$request,
'@ChillBudget/Resource/new.html.twig',
'Resource created'
);
}
@ -78,12 +94,10 @@ class ResourceController extends AbstractElementController
* "{_locale}/budget/resource/{id}/view",
* name="chill_budget_resource_view"
* )
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function viewAction(Resource $resource)
public function viewAction(Resource $resource): Response
{
return $this->_view($resource, '@ChillAMLIBudget/Resource/view.html.twig');
return $this->_view($resource, '@ChillBudget/Resource/view.html.twig');
}
protected function createNewElement()

View File

@ -9,9 +9,9 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\DependencyInjection;
namespace Chill\BudgetBundle\DependencyInjection;
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
@ -23,11 +23,11 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
*
* @see http://symfony.com/doc/current/cookbook/bundles/extension.html
*/
class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInterface
class ChillBudgetExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
@ -38,6 +38,7 @@ class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInte
$loader->load('services/templating.yaml');
$loader->load('services/menu.yaml');
$loader->load('services/calculator.yaml');
$loader->load('services/services.yaml');
$this->storeConfig('resources', $config, $container);
$this->storeConfig('charges', $config, $container);
@ -58,7 +59,7 @@ class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInte
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
'@ChillAMLIBudgetBundle/config/routing.yaml',
'@ChillBudgetBundle/config/routing.yaml',
],
],
]);
@ -68,8 +69,8 @@ class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInte
{
$container->prependExtensionConfig('security', [
'role_hierarchy' => [
BudgetElementVoter::UPDATE => [BudgetElementVoter::SHOW],
BudgetElementVoter::CREATE => [BudgetElementVoter::SHOW],
BudgetElementVoter::UPDATE => [BudgetElementVoter::SEE],
BudgetElementVoter::CREATE => [BudgetElementVoter::SEE],
],
]);
}

View File

@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\DependencyInjection\Compiler;
namespace Chill\BudgetBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -19,7 +19,7 @@ class CalculatorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$manager = $container->getDefinition('Chill\AMLI\BudgetBundle\Calculator\CalculatorManager');
$manager = $container->getDefinition('Chill\BudgetBundle\Calculator\CalculatorManager');
foreach ($container->findTaggedServiceIds('chill_budget.calculator') as $id => $tags) {
foreach ($tags as $tag) {

View File

@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\DependencyInjection;
namespace Chill\BudgetBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
@ -23,14 +23,14 @@ class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_amli_budget');
$rootNode = $treeBuilder->getRootNode('chill_amli_budget');
$treeBuilder = new TreeBuilder('chill_budget');
$rootNode = $treeBuilder->getRootNode('chill_budget');
$rootNode
->children()
// ressources
->arrayNode('resources')->isRequired()->requiresAtLeastOneElement()
->arrayNode('resources')->defaultValue([])
->arrayPrototype()
->children()
->scalarNode('key')->isRequired()->cannotBeEmpty()
@ -52,7 +52,7 @@ class Configuration implements ConfigurationInterface
->end()
->end()
->end()
->arrayNode('charges')->isRequired()->requiresAtLeastOneElement()
->arrayNode('charges')->defaultValue([])
->arrayPrototype()
->children()
->scalarNode('key')->isRequired()->cannotBeEmpty()

View File

@ -9,13 +9,15 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Entity;
namespace Chill\BudgetBundle\Entity;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Type\Decimal;
use Symfony\Component\Validator\Constraints as Assert;
/**
@ -26,8 +28,6 @@ use Symfony\Component\Validator\Constraints as Assert;
abstract class AbstractElement
{
/**
* @var decimal
*
* @ORM\Column(name="amount", type="decimal", precision=10, scale=2)
* @Assert\GreaterThan(
* value=0
@ -36,100 +36,80 @@ abstract class AbstractElement
* message="The amount cannot be empty"
* )
*/
private $amount;
private string $amount;
/**
* @var string|null
*
* @ORM\Column(name="comment", type="text", nullable=true)
*/
private $comment;
private ?string $comment;
/**
* @var DateTimeImmutable|null
*
* @ORM\Column(name="endDate", type="datetime_immutable", nullable=true)
* @Assert\GreaterThan(
* propertyPath="startDate",
* message="The budget element's end date must be after the start date"
* )
*/
private $endDate;
private ?DateTimeImmutable $endDate;
/**
* @ORM\ManyToOne(
* targetEntity="\Chill\PersonBundle\Entity\Household\Household"
* )
*/
private ?Household $household = null;
/**
* @var Person
* @ORM\ManyToOne(
* targetEntity="\Chill\PersonBundle\Entity\Person"
* )
*/
private $person;
private ?Person $person = null;
/**
* @var DateTimeImmutable
*
* @ORM\Column(name="startDate", type="datetime_immutable")
* @Assert\Date
*/
private $startDate;
private DateTimeImmutable $startDate;
/**
* @var string
*
* @ORM\Column(name="type", type="string", length=255)
*/
private $type;
private string $type;
/**
* Get amount.
*
* @return float
*/
public function getAmount()
/*Getters and Setters */
public function getAmount(): float
{
return (float) $this->amount;
}
/**
* Get comment.
*
* @return string|null
*/
public function getComment()
public function getComment(): ?string
{
return $this->comment;
}
/**
* Get endDate.
*
* @return DateTimeImmutable|null
*/
public function getEndDate()
public function getEndDate(): ?DateTimeImmutable
{
return $this->endDate;
}
public function getPerson(): Person
public function getHousehold(): ?Household
{
return $this->household;
}
public function getPerson(): ?Person
{
return $this->person;
}
/**
* Get startDate.
*
* @return DateTimeImmutable
*/
public function getStartDate()
public function getStartDate(): DateTimeImmutable
{
return $this->startDate;
}
/**
* Get type.
*
* @return string
*/
public function getType()
public function getType(): string
{
return $this->type;
}
@ -143,40 +123,21 @@ abstract class AbstractElement
abstract public function isResource(): bool;
/**
* Set amount.
*
* @param string $amount
*
* @return AbstractElement
*/
public function setAmount($amount)
public function setAmount(string $amount): self
{
$this->amount = $amount;
return $this;
}
/**
* Set comment.
*
* @param string|null $comment
*
* @return AbstractElement
*/
public function setComment($comment = null)
public function setComment(?string $comment = null): self
{
$this->comment = $comment;
return $this;
}
/**
* Set endDate.
*
* @return AbstractElement
*/
public function setEndDate(?DateTimeInterface $endDate = null)
public function setEndDate(?DateTimeInterface $endDate = null): self
{
if ($endDate instanceof DateTime) {
$this->endDate = DateTimeImmutable::createFromMutable($endDate);
@ -189,19 +150,21 @@ abstract class AbstractElement
return $this;
}
public function setPerson(Person $person)
public function setHousehold(Household $household): self
{
$this->household = $household;
return $this;
}
public function setPerson(Person $person): self
{
$this->person = $person;
return $this;
}
/**
* Set startDate.
*
* @return AbstractElement
*/
public function setStartDate(DateTimeInterface $startDate)
public function setStartDate(DateTimeInterface $startDate): self
{
if ($startDate instanceof DateTime) {
$this->startDate = DateTimeImmutable::createFromMutable($startDate);
@ -214,14 +177,7 @@ abstract class AbstractElement
return $this;
}
/**
* Set type.
*
* @param string $type
*
* @return AbstractElement
*/
public function setType($type)
public function setType(string $type): self
{
$this->type = $type;

View File

@ -9,8 +9,9 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Entity;
namespace Chill\BudgetBundle\Entity;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\HasCenterInterface;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
@ -19,7 +20,7 @@ use Doctrine\ORM\Mapping as ORM;
* Charge.
*
* @ORM\Table(name="chill_budget.charge")
* @ORM\Entity(repositoryClass="Chill\AMLI\BudgetBundle\Repository\ChargeRepository")
* @ORM\Entity(repositoryClass="Chill\BudgetBundle\Repository\ChargeRepository")
*/
class Charge extends AbstractElement implements HasCenterInterface
{
@ -58,7 +59,7 @@ class Charge extends AbstractElement implements HasCenterInterface
$this->setStartDate(new DateTimeImmutable('today'));
}
public function getCenter(): \Chill\MainBundle\Entity\Center
public function getCenter(): ?Center
{
return $this->getPerson()->getCenter();
}

View File

@ -9,8 +9,9 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Entity;
namespace Chill\BudgetBundle\Entity;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\HasCenterInterface;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
@ -19,7 +20,7 @@ use Doctrine\ORM\Mapping as ORM;
* Resource.
*
* @ORM\Table(name="chill_budget.resource")
* @ORM\Entity(repositoryClass="Chill\AMLI\BudgetBundle\Repository\ResourceRepository")
* @ORM\Entity(repositoryClass="Chill\BudgetBundle\Repository\ResourceRepository")
*/
class Resource extends AbstractElement implements HasCenterInterface
{
@ -37,7 +38,7 @@ class Resource extends AbstractElement implements HasCenterInterface
$this->setStartDate(new DateTimeImmutable('today'));
}
public function getCenter(): \Chill\MainBundle\Entity\Center
public function getCenter(): ?Center
{
return $this->getPerson()->getCenter();
}

View File

@ -9,10 +9,10 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Form;
namespace Chill\BudgetBundle\Form;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\AMLI\BudgetBundle\Entity\Charge;
use Chill\BudgetBundle\Config\ConfigRepository;
use Chill\BudgetBundle\Entity\Charge;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType;
@ -45,6 +45,7 @@ class ChargeType extends AbstractType
->add('type', ChoiceType::class, [
'choices' => $this->getTypes(),
'placeholder' => 'Choose a charge type',
'attr' => ['class' => ' select2 '],
])
->add('amount', MoneyType::class)
->add('comment', TextareaType::class, [
@ -96,7 +97,7 @@ class ChargeType extends AbstractType
public function getBlockPrefix()
{
return 'chill_amli_budgetbundle_charge';
return 'chill_budgetbundle_charge';
}
private function getTypes()

View File

@ -9,10 +9,10 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Form;
namespace Chill\BudgetBundle\Form;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\AMLI\BudgetBundle\Entity\Resource;
use Chill\BudgetBundle\Config\ConfigRepository;
use Chill\BudgetBundle\Entity\Resource;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType;
@ -45,6 +45,7 @@ class ResourceType extends AbstractType
'choices' => $this->getTypes(),
'placeholder' => 'Choose a resource type',
'label' => 'Resource element type',
'attr' => ['class' => ' select2 '],
])
->add('amount', MoneyType::class)
->add('comment', TextareaType::class, [
@ -80,7 +81,7 @@ class ResourceType extends AbstractType
public function getBlockPrefix()
{
return 'chill_amli_budgetbundle_resource';
return 'chill_budgetbundle_resource';
}
private function getTypes()

View File

@ -0,0 +1,53 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\BudgetBundle\Menu;
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class HouseholdMenuBuilder implements LocalMenuBuilderInterface
{
protected AuthorizationCheckerInterface $authorizationChecker;
protected TranslatorInterface $translator;
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
TranslatorInterface $translator
) {
$this->authorizationChecker = $authorizationChecker;
$this->translator = $translator;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var Household $household */
$household = $parameters['household'];
// if ($this->authorizationChecker->isGranted(BudgetElementVoter::SHOW, $household)) {
$menu->addChild($this->translator->trans('household.Budget'), [
'route' => 'chill_budget_elements_household_index',
'routeParameters' => [
'id' => $household->getId(),
], ])
->setExtras(['order' => 50]);
// }
}
public static function getMenuIds(): array
{
return ['household'];
}
}

View File

@ -9,25 +9,19 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Menu;
namespace Chill\BudgetBundle\Menu;
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class UserMenuBuilder implements LocalMenuBuilderInterface
class PersonMenuBuilder implements LocalMenuBuilderInterface
{
/**
* @var AuthorizationCheckerInterface
*/
protected $authorizationChecker;
protected AuthorizationCheckerInterface $authorizationChecker;
/**
* @var TranslatorInterface
*/
protected $translator;
protected TranslatorInterface $translator;
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
@ -39,10 +33,10 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var \Chill\PersonBundle\Entity\Person $person */
/** @var Person $person */
$person = $parameters['person'];
if ($this->authorizationChecker->isGranted(BudgetElementVoter::SHOW, $person)) {
if ($this->authorizationChecker->isGranted(BudgetElementVoter::SEE, $person)) {
$menu->addChild(
$this->translator->trans('Budget'),
[
@ -50,7 +44,7 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
'routeParameters' => ['id' => $person->getId()],
]
)
->setExtra('order', 460);
->setExtra('order', 4000);
}
}

View File

@ -9,10 +9,11 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Repository;
namespace Chill\BudgetBundle\Repository;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\ORM\EntityRepository;
/**
* ChargeRepository.
@ -20,13 +21,15 @@ use DateTime;
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ChargeRepository extends \Doctrine\ORM\EntityRepository
class ChargeRepository extends EntityRepository
{
public function findByPersonAndDate(Person $person, DateTime $date, $sort = null)
public function findByEntityAndDate($entity, DateTime $date, $sort = null)
{
$qb = $this->createQueryBuilder('c');
$qb->where('c.person = :person')
$entityStr = $entity instanceof Person ? 'person' : 'household';
$qb->where("c.{$entityStr} = :{$entityStr}")
->andWhere('c.startDate < :date')
->andWhere('c.startDate < :date OR c.startDate IS NULL');
@ -35,7 +38,7 @@ class ChargeRepository extends \Doctrine\ORM\EntityRepository
}
$qb->setParameters([
'person' => $person,
$entityStr => $entity,
'date' => $date,
]);

View File

@ -9,10 +9,11 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Repository;
namespace Chill\BudgetBundle\Repository;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\ORM\EntityRepository;
/**
* ResourceRepository.
@ -20,23 +21,28 @@ use DateTime;
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ResourceRepository extends \Doctrine\ORM\EntityRepository
class ResourceRepository extends EntityRepository
{
public function findByPersonAndDate(Person $person, DateTime $date, $sort = null)
public function findByEntityAndDate($entity, DateTime $date, $sort = null)
{
$qb = $this->createQueryBuilder('c');
$qb->where('c.person = :person')
->andWhere('c.startDate < :date')
->andWhere('c.startDate < :date OR c.startDate IS NULL');
$entityStr = $entity instanceof Person ? 'person' : 'household';
$qb->where("c.{$entityStr} = :{$entityStr}")
// TODO: in controller, the budget and charges asked are also for future and actual
//->andWhere('c.startDate < :date')
// TODO: there is a misconception here, the end date must be lower or null. startDate are never null
//->andWhere('c.startDate < :date OR c.startDate IS NULL');
;
if (null !== $sort) {
$qb->orderBy($sort);
}
$qb->setParameters([
'person' => $person,
'date' => $date,
$entityStr => $entity,
//'date' => $date,
]);
return $qb->getQuery()->getResult();

View File

@ -0,0 +1,61 @@
.subtitle {
margin-top: 1rem;
margin-bottom: 1rem;
padding: 1rem;
}
.family-title {
margin-bottom: 1rem !important;
}
.budget-table th {
th {
color: white;
}
}
.budget-table {
th.charge {
background-color: #e03851d7;
}
}
.budget-table {
th.resource {
background-color: #6d9e63d8;
}
}
.budget-table {
th, td {
padding: 10px;
text-align: right;
}
td.column-wide {
width: 20%;
}
td.column-small {
width: 15%;
&.right {
align-items: right;
}
}
}
.btn-budget {
margin-right: 1rem !important;
}
.el-type {
font-weight: 600;
text-align: left !important;
}
.total {
margin-top: 1rem;
border-top: 1px dashed black;
}
.accordion-item {
margin-bottom: 1rem;
}
button[aria-expanded="true"] > span.folded,
button[aria-expanded="false"] > span.unfolded { display: none; }
button[aria-expanded="false"] > span.folded,
button[aria-expanded="true"] > span.unfolded { display: inline; }

View File

@ -0,0 +1 @@
require('./chillbudget.scss');

View File

@ -0,0 +1,74 @@
{% set entity = person is defined ? person : household %}
{% set actualResources = [] %}
{% set futureResources = [] %}
{% set pastResources = [] %}
{% for r in resources %}
{% if r.startDate|date('U') <= 'now'|date('U') %}
{% if r.endDate is null or r.endDate|date('U') >= 'now'|date('U') %}
{% set actualResources = actualResources|merge([ r ]) %}
{% else %}
{% set pastResources = pastResources|merge([ r ]) %}
{% endif %}
{% else %}
{% set futureResources = futureResources|merge([ r ]) %}
{% endif %}
{% endfor %}
{% set actualCharges = [] %}
{% set futureCharges = [] %}
{% set pastCharges = [] %}
{% for c in charges %}
{% if c.startDate|date('U') <= 'now'|date('U') %}
{% if c.endDate is null or c.endDate|date('U') >= 'now'|date('U') %}
{% set actualCharges = actualCharges|merge([ c ]) %}
{% else %}
{% set pastCharges = pastCharges|merge([ c ]) %}
{% endif %}
{% else %}
{% set futureCharges = futureCharges|merge([ c ]) %}
{% endif %}
{% endfor %}
<h3 class="subtitle">{{ 'Actual budget'|trans }}</h3>
{% if actualCharges|length > 0 or actualResources|length > 0 %}
{% include 'ChillBudgetBundle:Budget:_current_budget.html.twig' with {
'actualResources': actualResources,
'actualCharges': actualCharges,
'results': results,
'entity': entity
} %}
{% else %}
<div class="flex-table">
<div class="item-bloc">
<p><span class="chill-no-data-statement">{{ "There isn't any element recorded"|trans }}</span></p>
</div>
</div>
{% endif %}
{% if pastCharges|length > 0 or pastResources|length > 0 %}
<h2 class="subtitle">{{ 'Past budget'|trans }}</h2>
{% include 'ChillBudgetBundle:Budget:_past_budget.html.twig' with {
'pastCharges': pastCharges,
'pastResources': pastResources,
'entity': entity
} %}
{% endif %}
{% if futureCharges|length > 0 or futureResources|length > 0 %}
<h2 class="subtitle">{{ 'Future budget'|trans }}</h2>
{% include 'ChillBudgetBundle:Budget:_future_budget.html.twig' with {
'futureResources': futureResources,
'futureCharges': futureCharges,
'entity': entity
} %}
{% endif %}

View File

@ -0,0 +1,30 @@
{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %}
{# <h2 class="subtitle">{{ 'Actual budget'|trans }}</h2> #}
<div class="flex-table">
<h4 class="family-title">{{ 'Actual resources'|trans }}</h4>
{% if actualResources|length > 0 %}
<div class="item-bloc">
{{ table_elements(actualResources, 'resource') }}
</div>
{% else %}
<div class="item-bloc">
<span class="chill-no-data-statement">{{ 'No resources registered'|trans }}</span>
</div>
{% endif %}
</div>
<div class="flex-table">
<h4 class="family-title">{{ 'Actual charges'|trans }}</h4>
{% if actualCharges|length > 0 %}
<div class="item-bloc">
{{ table_elements(actualCharges, 'charge') }}
</div>
{% else %}
<div class="item-bloc">
<span class="chill-no-data-statement">{{ 'No charges registered'|trans }}</span>
</div>
{% endif %}
</div>

View File

@ -0,0 +1,51 @@
{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %}
<div class="accordion" id="future_{{ entity.id }}">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_future_{{ entity.id }}">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse_future_{{ entity.id }}"
aria-expanded="false"
aria-controls="collapse_future_{{ entity.id }}">
<span class="folded">{{ 'Show future budget'|trans }}</span>
<span class="unfolded text-secondary">{{ 'Hide budget'|trans }}</span>
</button>
</h2>
<div id="collapse_future_{{ entity.id }}"
class="accordion-collapse collapse"
aria-labelledby="heading_future_{{ entity.id }}"
data-bs-parent="#future_{{ entity.id }}">
<div class="flex-table">
<h3 class="family-title">{{ 'Future resources'|trans }}</h3>
{% if futureResources|length > 0 %}
<div class="item-bloc">
{{ table_elements(futureResources, 'resource') }}
</div>
{% else %}
<div class="item-bloc">
<span class="chill-no-data-statement">{{ 'No future resources registered'|trans }}</span>
</div>
{% endif %}
</div>
<div class="flex-table">
<h3 class="family-title">{{ 'Future charges'|trans }}</h3>
{% if futureCharges|length > 0 %}
<div class="item-bloc">
{{ table_elements(futureCharges, 'charge') }}
</div>
{% else %}
<div class="item-bloc">
<span class="chill-no-data-statement">{{ 'No future charges registered'|trans }}</span>
</div>
{% endif %}
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,97 @@
{% macro table_elements(elements, family) %}
<table class="budget-table">
<thead>
<tr>
<th class="{{ family }} el-type">{{ 'Budget element type'|trans }}</th>
<th class="{{ family }}">{{ 'Amount'|trans }}</th>
<th class="{{ family }}">{{ 'Validity period'|trans }}</th>
<th class="{{ family }}">&nbsp;</th>
</tr>
</thead>
<tbody>
{% set total = 0 %}
{% for f in elements %}
{% set total = total + f.amount %}
<tr>
<td class="column-wide el-type">
<span class="badge-title">
<span class="title_label title_label_{{ family }}"></span>
<span class="title_action">{{ f.type|budget_element_type_display(family) }}<span>
</span>
</td>
<td class="column-small">{{ f.amount|format_currency('EUR') }}</td>
<td class="column-wide">
{% if f.endDate is not null %}
{{ f.startDate|format_date('short') ~ ' - ' ~ f.endDate|format_date('short') }}
{% else %}
{{ f.startDate|format_date('short') ~ ' - ...' }}
{% endif %}
</td>
<td class="column-small">
<ul class="record_actions">
{% if is_granted('CHILL_BUDGET_ELEMENT_SEE', f) %}
<li>
<a href="{{ path('chill_budget_' ~ family ~ '_view', { 'id': f.id } ) }}" class="btn btn-sm btn-show"></a>
</li>
{% endif %}
{% if is_granted('CHILL_BUDGET_ELEMENT_UPDATE', f) %}
<li>
<a href="{{ path('chill_budget_' ~ family ~'_edit', { 'id': f.id } ) }}" class="btn btn-sm btn-edit"></a>
</li>
{% endif %}
{% if is_granted('CHILL_BUDGET_ELEMENT_DELETE', f) %}
<li>
<a href="{{ path('chill_budget_' ~ family ~ '_delete', { 'id': f.id } ) }}" class="btn btn-sm btn-delete"></a>
</li>
{% endif %}
</ul>
</td>
</tr>
{% endfor %}
<tr class="total">
<td class="el-type">
{{ 'Total'|trans }}
</td>
<td>
{{ total|format_currency('EUR') }}
</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
{% endmacro %}
{% macro table_results(actualCharges, actualResources) %}
{% set totalCharges = 0 %}
{% for c in actualCharges %}
{% set totalCharges = totalCharges + c.amount %}
{% endfor %}
{% set totalResources = 0 %}
{% for r in actualResources %}
{% set totalResources = totalResources + r.amount %}
{% endfor %}
{% set result = (totalResources - totalCharges) %}
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>{{ 'Budget calculator result'|trans }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ 'The balance'|trans }}</td>
<td>&nbsp;</td>
<td>
{{ result|format_currency('EUR') }}
</td>
</tr>
</tbody>
</table>
{% endmacro %}

View File

@ -0,0 +1,53 @@
{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %}
<div class="accordion" id="past_{{ entity.id }}">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_past_{{ entity.id }}">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse_past_{{ entity.id }}"
aria-expanded="false"
aria-controls="collapse_past_{{ entity.id }}">
<span class="folded">{{ 'Show past budget'|trans }}</span>
<span class="unfolded text-secondary">{{ 'Hide budget'|trans }}</span>
</button>
</h2>
<div id="collapse_past_{{ entity.id }}"
class="accordion-collapse collapse"
aria-labelledby="heading_past_{{ entity.id }}"
data-bs-parent="#past_{{ entity.id }}">
<div class="flex-table">
<h3 class="family-title">{{ 'Past resources'|trans }}</h3>
{% if pastResources|length > 0 %}
<div class="item-bloc">
{{ table_elements(pastResources, 'resource') }}
</div>
{% else %}
<div class="item-bloc">
<span class="chill-no-data-statement">{{ 'No past resources registered'|trans }}</span>
</div>
{% endif %}
</div>
<div class="flex-table">
<h3 class="family-title">{{ 'Past charges'|trans }}</h3>
{% if pastCharges|length > 0 %}
<div class="item-bloc">
{{ table_elements(pastCharges, 'charge') }}
</div>
{% else %}
<div class="item-bloc">
<span class="chill-no-data-statement">{{ 'No past charges registered'|trans }}</span>
</div>
{% endif %}
</div>
</div>
</div>
</div>

View File

@ -1,18 +1,29 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% set confirm_question = 'Are you sure you want to remove the charge "%type%" associated to "%name%" ?'|trans({ '%name%' : person.firstname ~ ' ' ~ person.lastname, '%type%': element.type|budget_element_type_display('charge') } ) %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% set confirm_question = 'Are you sure you want to remove the charge "%type%" associated to household "%household%" ?'|trans({ '%household%' : household.id, '%type%': element.type|budget_element_type_display('charge') } ) %}
{% endif %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% extends template %}
{% block title 'Remove resource'|trans %}
{% block title 'Remove charge'|trans %}
{% block personcontent %}
{% block content %}
{{ include('ChillMainBundle:Util:confirmation_template.html.twig',
{
'title' : 'Remove charge'|trans,
'confirm_question' : 'Are you sure you want to remove the charge "%type%" associated to "%name%" ?'|trans({ '%name%' : person.firstname ~ ' ' ~ person.lastname, '%type%': element.type|budget_element_type_display('charge') } ),
'cancel_route' : 'chill_budget_elements_index',
'cancel_parameters' : { 'id' : element.person.id },
'confirm_question' : confirm_question,
'cancel_route' : indexPage,
'cancel_parameters' : { 'id': person is defined ? person.id : household.id },
'form' : delete_form
} ) }}

View File

@ -1,10 +1,22 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% endif %}
{% set title = 'Edit charge'|trans %}
{% extends template %}
{% set activeRouteKey = '' %}
{% set title = 'Edit Charge for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{{ form_start(form) }}
@ -18,12 +30,12 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="btn btn-cancel">
<a href="{{ path(indexPage, { 'id': person is defined ? person.id : household.id } ) }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>
<li>
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-create' }, 'label': 'Edit' } ) }}
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-edit' }, 'label': 'Edit' } ) }}
</li>
</ul>

View File

@ -1,10 +1,21 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% endif %}
{% set activeRouteKey = '' %}
{% set title = 'New Charge for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% set title = 'New charge'|trans %}
{% extends template %}
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{{ form_start(form) }}
@ -18,7 +29,7 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="btn btn-cancel">
<a href="{{ path(indexPage, { 'id': person is defined ? person.id : household.id } ) }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>

View File

@ -1,30 +1,45 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% endif %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% set title = 'Charge for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% set title = 'Charge' %}
{% extends template %}
{% block title title %}
{% block personcontent %}
<h1>{{ title }}</h1>
<dl class="chill_view_data">
<dt>{{ 'Type'|trans }}</dt>
<dd>{{ element.type|budget_element_type_display('charge') }}</dd>
{% block content %}
<div class="budget-show">
<h1>{{ title }}</h1>
<div class="flex-table">
<div class="item-bloc">
<div class="item-row">
<h2 class="badge-title">
<span class="title_label title_label_charge"></span>
<span class="title_action">{{ element.type|budget_element_type_display('charge') }}</span>
</h2>
</div>
<div class="item-row separator">
<dl class="chill_view_data">
<dt>{{ 'Amount'|trans }}</dt>
<dd>{{ element.amount|localizedcurrency('EUR') }}</dd>
<dd>{{ element.amount|format_currency('EUR') }}</dd>
<dt>{{ 'Validity period'|trans }}</dt>
<dd>
{% if element.endDate is not null %}
{{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': element.startDate|localizeddate('long', 'none'), '%endDate%': familyMember.endDate|localizeddate('long', 'none') } ) }}
{{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': element.startDate|format_date('long'), '%endDate%': element.endDate|format_date('long') } ) }}
{% else %}
{{ 'Valid since %startDate%'|trans( { '%startDate%': element.startDate|localizeddate('long', 'none') } ) }}
{{ 'Valid since %startDate%'|trans( { '%startDate%': element.startDate|format_date('long') } ) }}
{% endif %}
</dd>
<dt>{{ 'Comment'|trans }}</dt>
<dd>
{%- if element.comment is not empty -%}
@ -35,15 +50,19 @@
<span class="chill-no-data-statement">{{ 'Not given'|trans }}</span>
{%- endif -%}
</dd>
</dl>
</dl>
</div>
</div>
</div>
</div>
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="btn btn-cancel">
<a href="{{ path(indexPage, { 'id': person is defined ? person.id : household.id } ) }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::UPDATE'), element) %}
{% if is_granted('CHILL_BUDGET_ELEMENT_UPDATE', element) %}
<li>
<a href="{{ path('chill_budget_charge_edit', { 'id': element.id } ) }}" class="btn btn-edit">{{ 'Edit'|trans }}</a>
</li>

View File

@ -1,228 +0,0 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = '' %}
{% set title = 'Budget for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% set actualResources = [] %}
{% set futureResources = [] %}
{% set pastResources = [] %}
{% for r in resources %}
{% if r.startDate|date('U') <= 'now'|date('U') %}
{% if r.endDate is null or r.endDate|date('U') >= 'now'|date('U') %}
{% set actualResources = actualResources|merge([ r ]) %}
{% else %}
{% set pastResources = pastResources|merge([ r ]) %}
{% endif %}
{% else %}
{% set futureResources = futureResources|merge([ r ]) %}
{% endif %}
{% endfor %}
{% set actualCharges = [] %}
{% set futureCharges = [] %}
{% set pastCharges = [] %}
{% for c in charges %}
{% if c.startDate|date('U') <= 'now'|date('U') %}
{% if c.endDate is null or c.endDate|date('U') >= 'now'|date('U') %}
{% set actualCharges = actualCharges|merge([ c ]) %}
{% else %}
{% set pastCharges = pastCharges|merge([ c ]) %}
{% endif %}
{% else %}
{% set futureCharges = futureCharges|merge([ c ]) %}
{% endif %}
{% endfor %}
{% macro table_elements(elements, family) %}
<table>
<thead>
<tr>
<th>{{ 'Budget element type'|trans }}</th>
<th>{{ 'Amount'|trans }}</th>
<th>{{ 'Validity period'|trans }}</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% set total = 0 %}
{% for f in elements %}
{% set total = total + f.amount %}
<tr>
<td>
{{ f.type|budget_element_type_display(family) }}
</td>
<td>{{ f.amount|format_currency('EUR') }}</td>
<td>
{% if f.endDate is not null %}
{{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': f.startDate|format_date('long'), '%endDate%': f.endDate|format_date('long') } ) }}
{% else %}
{{ 'Valid since %startDate%'|trans( { '%startDate%': f.startDate|format_date('long') } ) }}
{% endif %}
</td>
<td>
<ul class="record_actions">
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::SHOW'), f) %}
<li>
<a href="{{ path('chill_budget_' ~ family ~ '_view', { 'id': f.id } ) }}" class="btn btn-show"></a>
</li>
{% endif %}
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::UPDATE'), f) %}
<li>
<a href="{{ path('chill_budget_' ~ family ~'_edit', { 'id': f.id } ) }}" class="btn btn-edit"></a>
</li>
{% endif %}
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::DELETE'), f) %}
<li>
<a href="{{ path('chill_budget_' ~ family ~ '_delete', { 'id': f.id } ) }}" class="btn btn-delete"></a>
</li>
{% endif %}
</ul>
</td>
</tr>
{% endfor %}
<tr>
<td>
{{ 'Total'|trans }}
</td>
<td>
{{ total|format_currency('EUR') }}
</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
{% endmacro %}
{% macro table_results(results) %}
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th>{{ 'Budget calculator result'|trans }}</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td>{{ result.label }}</td>
<td>
{% if result.type == constant('CHILL\\AMLI\\BudgetBundle\\Calculator\\CalculatorResult::TYPE_CURRENCY') %}
{{ result.result|format_currency('EUR') }}
{% elseif result.type == constant('CHILL\\AMLI\\BudgetBundle\\Calculator\\CalculatorResult::TYPE_PERCENTAGE') %}
{{ result.result|round(2, 'ceil') ~ '%' }}
{% else %}
{{ result.result|round(2, 'common') }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endmacro %}
{% import _self as m %}
{% block personcontent %}
<h1>{{ title }}</h1>
<h2>{{ 'Actual budget'|trans }}</h2>
{% if resources|length == 0 and charges|length == 0 %}
<p><span class="chill-no-data-statement">{{ "There isn't any element recorded"|trans }}</span></p>
{% else %}
<h3>{{ 'Actual resources'|trans }}</h3>
{% if actualResources|length > 0 %}
{{ m.table_elements(actualResources, 'resource') }}
{% else %}
<span class="chill-no-data-statement">{{ 'No resources registered'|trans }}</span>
{% endif %}
<h3>{{ 'Actual charges'|trans }}</h3>
{% if actualCharges|length > 0 %}
{{ m.table_elements(actualCharges, 'charge') }}
{% else %}
<span class="chill-no-data-statement">{{ 'No charges registered'|trans }}</span>
{% endif %}
{% if results|length > 0 %}
<h2>{{ 'Budget calculator'|trans }}</h2>
{{ m.table_results(results) }}
{% endif %}
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::CREATE'), person) %}
<ul class="record_actions">
<li>
<a class="btn btn-create" href="{{ path('chill_budget_resource_new', { 'id': person.id} ) }}">{{ 'Create new resource'|trans }}</a>
</li>
<li>
<a class="btn btn-create" href="{{ path('chill_budget_charge_new', { 'id': person.id} ) }}">{{ 'Create new charge'|trans }}</a>
</li>
</ul>
{% endif %}
{% endif %}
{% if pastCharges|length > 0 or pastResources|length > 0 %}
<h2>{{ 'Past budget'|trans }}</h2>
<h3>{{ 'Past resources'|trans }}</h3>
{% if pastResources|length > 0 %}
{{ m.table_elements(pastResources, 'resource') }}
{% else %}
<span class="chill-no-data-statement">{{ 'No past resources registered'|trans }}</span>
{% endif %}
<h3>{{ 'Past charges'|trans }}</h3>
{% if pastCharges|length > 0 %}
{{ m.table_elements(pastCharges, 'charge') }}
{% else %}
<span class="chill-no-data-statement">{{ 'No past charges registered'|trans }}</span>
{% endif %}
{% endif %}
{% if futureCharges|length > 0 or futureResources|length > 0 %}
<h2>{{ 'Future budget'|trans }}</h2>
<h3>{{ 'Future resources'|trans }}</h3>
{% if futureResources|length > 0 %}
{{ m.table_elements(futureResources, 'resource') }}
{% else %}
<span class="chill-no-data-statement">{{ 'No future resources registered'|trans }}</span>
{% endif %}
<h3>{{ 'Future charges'|trans }}</h3>
{% if futureCharges|length > 0 %}
{{ m.table_elements(futureCharges, 'charge') }}
{% else %}
<span class="chill-no-data-statement">{{ 'No future charges registered'|trans }}</span>
{% endif %}
{% endif %}
{% if (resources|length + charges|length) == 0 or futureCharges|length > 0 or futureResources|length > 0 or pastCharges|length > 0 or pastResources|length > 0 %}
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::CREATE'), person) %}
<ul class="record_actions">
<li>
<a class="btn btn-create" href="{{ path('chill_budget_resource_new', { 'id': person.id} ) }}">{{ 'Create new resource'|trans }}</a>
</li>
<li>
<a class="btn btn-create" href="{{ path('chill_budget_charge_new', { 'id': person.id} ) }}">{{ 'Create new charge'|trans }}</a>
</li>
</ul>
{% endif %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,92 @@
{% extends "@ChillPerson/Household/layout.html.twig" %}
{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %}
{% set activeRouteKey = '' %}
{% set title = 'Budget for household %household%'|trans({ '%household%' : household.id } ) %}
{% block title title %}
{% block js %}
{{ encore_entry_script_tags('page_budget') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('page_budget') }}
{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
{% include 'ChillBudgetBundle:Budget:_budget.html.twig' with {
'resources': resources,
'charges': charges,
'household': household
} %}
{#
<div class="flex-table">
<h3 class="family-title">{{ 'Budget calculator'|trans }}</h3>
<div class="item-bloc">
{{ table_results(wholeCharges, wholeResources) }}
</div>
</div>
#}
{% if household.getCurrentMembers|length > 0 %}
<h2 class="subtitle">{{ 'Current budget household members'|trans }}</h2>
{% for hm in household.getCurrentMembers %}
{% set member = hm.person %}
<div class="accordion" id="member_{{ member.id }}">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_{{ member.id }}">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse_{{ member.id }}"
aria-expanded="false"
aria-controls="collapse_{{ member.id }}">
<span class="folded">{{ 'Show budget of %name%'|trans({'%name%': member.firstName ~ " " ~ member.lastName }) }} ({{ 'budget.number of elements'|trans({ 'nb_items': member.getBudgetResources|length + member.getBudgetResources|length }) }})</span>
<span class="unfolded text-secondary">{{ 'Hide budget of %name%'|trans({'%name%': member.firstName ~ " " ~ member.lastName }) }}</span>
</button>
</h2>
<div id="collapse_{{ member.id }}"
class="accordion-collapse collapse"
aria-labelledby="heading_{{ member.id }}"
data-bs-parent="#nonCurrent">
{% include 'ChillBudgetBundle:Budget:_budget.html.twig' with {
'resources': member.getBudgetResources,
'charges': member.getBudgetCharges,
'person': member
} %}
<ul class="record_actions">
{% if is_granted('CHILL_BUDGET_ELEMENT_SEE', member) %}
<li class="btn-budget">
<a class="btn btn-edit" title={{ 'Edit budget'|trans }} href="{{ path('chill_budget_elements_index', { 'id': member.id } ) }}"></a>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
{% endfor %}
{% endif %}
{% if is_granted('CHILL_BUDGET_ELEMENT_CREATE', household) %}
<ul class="record_actions sticky-form-buttons">
<li>
<a class="btn btn-create" href="{{ path('chill_budget_resource_household_new', { 'id': household.id} ) }}">{{ 'Create new resource'|trans }}</a>
</li>
<li>
<a class="btn btn-create" href="{{ path('chill_budget_charge_household_new', { 'id': household.id} ) }}">{{ 'Create new charge'|trans }}</a>
</li>
</ul>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,46 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_results %}
{% set activeRouteKey = '' %}
{% set title = 'Budget for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% block js %}
{{ encore_entry_script_tags('page_budget') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('page_budget') }}
{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
{% include 'ChillBudgetBundle:Budget:_budget.html.twig' with {
'resources': resources,
'charges': charges,
'person': person
} %}
<div class="flex-table">
<h3 class="family-title">{{ 'Budget calculator'|trans }}</h2>
<div class="item-bloc">
{{ table_results(charges, resources) }}
</div>
</div>
{% if is_granted('CHILL_BUDGET_ELEMENT_CREATE', person) %}
<ul class="record_actions sticky-form-buttons">
<li>
<a class="btn btn-create" href="{{ path('chill_budget_resource_new', { 'id': person.id} ) }}">{{ 'Create new resource'|trans }}</a>
</li>
<li>
<a class="btn btn-create" href="{{ path('chill_budget_charge_new', { 'id': person.id} ) }}">{{ 'Create new charge'|trans }}</a>
</li>
</ul>
{% endif %}
{% endblock %}

View File

@ -1,18 +1,29 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% set confirm_question = 'Are you sure you want to remove the ressource "%type%" associated to "%name%" ?'|trans({ '%name%' : person.firstname ~ ' ' ~ person.lastname, '%type%': element.type|budget_element_type_display('resource') } ) %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% set confirm_question = 'Are you sure you want to remove the ressource "%type%" associated to household "%household%" ?'|trans({ '%household%' : household.id, '%type%': element.type|budget_element_type_display('resource') } ) %}
{% endif %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% extends template %}
{% block title 'Remove resource'|trans %}
{% block personcontent %}
{% block content %}
{{ include('ChillMainBundle:Util:confirmation_template.html.twig',
{
'title' : 'Remove resource'|trans,
'confirm_question' : 'Are you sure you want to remove the ressource "%type%" associated to "%name%" ?'|trans({ '%name%' : person.firstname ~ ' ' ~ person.lastname, '%type%': element.type|budget_element_type_display('resource') } ),
'cancel_route' : 'chill_budget_elements_index',
'cancel_parameters' : { 'id' : element.person.id },
'confirm_question' : confirm_question,
'cancel_route' : indexPage,
'cancel_parameters' : { 'id': person is defined ? person.id : household.id },
'form' : delete_form
} ) }}

View File

@ -1,10 +1,24 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% set title = 'Edit resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% set title = 'Edit resource for household %household%'|trans({ '%household%' : household.id } ) %}
{% endif %}
{% set title = 'Edit resource'|trans %}
{% extends template %}
{% set activeRouteKey = '' %}
{% set title = 'Edit Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{{ form_start(form) }}
@ -17,12 +31,12 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="btn btn-cancel">
<a href="{{ path(indexPage, { 'id': person is defined ? person.id : household.id } ) }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>
<li>
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-create' }, 'label': 'Edit' } ) }}
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-edit' }, 'label': 'Edit' } ) }}
</li>
</ul>

View File

@ -1,10 +1,24 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% set title = 'New Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% set title = 'New Resource for household %household%'|trans({ '%household%' : household.id } ) %}
{% endif %}
{% set title = 'New resource'|trans %}
{% extends template %}
{% set activeRouteKey = '' %}
{% set title = 'New Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{{ form_start(form) }}
@ -17,7 +31,7 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="btn btn-cancel">
<a href="{{ path(indexPage, { 'id': person is defined ? person.id : household.id } ) }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>

View File

@ -1,31 +1,46 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% if element.person is not null %}
{% set template = '@ChillPerson/Person/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_index' %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% else %}
{% set template = '@ChillPerson/Household/layout.html.twig' %}
{% set indexPage = 'chill_budget_elements_household_index' %}
{% set activeRouteKey = '' %}
{% set household = element.household %}
{% endif %}
{% set activeRouteKey = '' %}
{% set person = element.person %}
{% set title = 'Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% set title = 'Resource' %}
{% extends template %}
{% block title title %}
{% block personcontent %}
<h1>{{ title }}</h1>
{% block content %}
<div class="budget-show">
<h1>{{ title }}</h1>
<dl class="chill_view_data">
<dt>{{ 'Type'|trans }}</dt>
<dd>{{ element.type|budget_element_type_display('resource') }}</dd>
<dt>{{ 'Amount'|trans }}</dt>
<div class="flex-table">
<div class="item-bloc">
<div class="item-row">
<h2 class="badge-title">
<span class="title_label title_label_resource"></span>
<span class="title_action title_action">{{ element.type|budget_element_type_display('resource') }}</span>
</h2>
</div>
<div class="item-row separator">
<dl class="chill_view_data">
<dt class="inline">{{ 'Amount'|trans }}</dt>
<dd>{{ element.amount|format_currency('EUR') }}</dd>
<dt>{{ 'Validity period'|trans }}</dt>
<dt class="inline">{{ 'Validity period'|trans }}</dt>
<dd>
{% if element.endDate is not null %}
{{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': element.startDate|format_date('long'), '%endDate%': familyMember.endDate|format_date('long') } ) }}
{{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': element.startDate|format_date('long'), '%endDate%': element.endDate|format_date('long') } ) }}
{% else %}
{{ 'Valid since %startDate%'|trans( { '%startDate%': element.startDate|format_date('long') } ) }}
{% endif %}
</dd>
<dt>{{ 'Comment'|trans }}</dt>
<dt class="inline">{{ 'Comment'|trans }}</dt>
<dd>
{%- if element.comment is not empty -%}
<blockquote class="chill-user-quote">
@ -35,15 +50,19 @@
<span class="chill-no-data-statement">{{ 'Not given'|trans }}</span>
{%- endif -%}
</dd>
</dl>
</dl>
</div>
</div>
</div>
</div>
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="btn btn-cancel">
<a href="{{ path(indexPage, { 'id': person is defined ? person.id : household.id } ) }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::UPDATE'), element) %}
{% if is_granted('CHILL_BUDGET_ELEMENT_UPDATE', element) %}
<li>
<a href="{{ path('chill_budget_resource_edit', { 'id': element.id } ) }}" class="btn btn-edit">{{ 'Edit'|trans }}</a>
</li>

View File

@ -9,15 +9,16 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Security\Authorization;
namespace Chill\BudgetBundle\Security\Authorization;
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
use Chill\MainBundle\Entity\User;
use Chill\BudgetBundle\Entity\AbstractElement;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use function in_array;
@ -30,22 +31,24 @@ class BudgetElementVoter extends AbstractChillVoter implements ProvideRoleHierar
public const ROLES = [
self::CREATE,
self::DELETE,
self::SHOW,
self::SEE,
self::UPDATE,
];
public const SHOW = 'CHILL_BUDGET_ELEMENT_SHOW';
public const SEE = 'CHILL_BUDGET_ELEMENT_SEE';
public const UPDATE = 'CHILL_BUDGET_ELEMENT_UPDATE';
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected VoterHelperInterface $voter;
public function __construct(AuthorizationHelper $authorizationHelper)
public function __construct(VoterHelperFactoryInterface $voterFactory)
{
$this->authorizationHelper = $authorizationHelper;
$this->voter = $voterFactory
->generate(self::class)
->addCheckFor(AbstractElement::class, self::ROLES)
->addCheckFor(Person::class, [self::CREATE, self::SEE])
->addCheckFor(Household::class, [self::CREATE, self::SEE])
->build();
}
public function getRoles(): array
@ -66,18 +69,11 @@ class BudgetElementVoter extends AbstractChillVoter implements ProvideRoleHierar
protected function supports($attribute, $subject)
{
return (in_array($attribute, self::ROLES, true) && $subject instanceof AbstractElement)
|| ($subject instanceof Person && in_array($attribute, [self::SHOW, self::CREATE], true));
|| (($subject instanceof Person || $subject instanceof Household) && in_array($attribute, [self::SEE, self::CREATE], true));
}
protected function voteOnAttribute($attribute, $subject, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token)
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
if (false === $user instanceof User) {
return false;
}
return $this->authorizationHelper
->userHasAccess($user, $subject, new Role($attribute));
return $this->voter->voteOnAttribute($attribute, $subject, $token);
}
}

View File

@ -0,0 +1,159 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\BudgetBundle\Service\Summary;
use Chill\BudgetBundle\Config\ConfigRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMapping;
use LogicException;
use function count;
/**
* Helps to find a summary of the budget: the sum of resources and charges.
*/
class SummaryBudget
{
private const QUERY_CHARGE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, type FROM chill_budget.charge WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type';
private const QUERY_CHARGE_BY_PERSON = 'select SUM(amount) AS sum, type FROM chill_budget.charge WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type';
private const QUERY_RESOURCE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, type FROM chill_budget.resource WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type';
private const QUERY_RESOURCE_BY_PERSON = 'select SUM(amount) AS sum, type FROM chill_budget.resource WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type';
private array $chargeLabels;
private ConfigRepository $configRepository;
private EntityManagerInterface $em;
private array $resourcesLabels;
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(EntityManagerInterface $em, ConfigRepository $configRepository, TranslatableStringHelperInterface $translatableStringHelper)
{
$this->em = $em;
$this->configRepository = $configRepository;
$this->chargeLabels = $configRepository->getChargesLabels();
$this->resourcesLabels = $configRepository->getResourcesLabels();
$this->translatableStringHelper = $translatableStringHelper;
}
public function getEmptyChargeArray(): array
{
$keys = $this->configRepository->getChargesKeys();
$labels = $this->chargeLabels;
return array_combine($keys, array_map(function ($i) use ($labels) {
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])];
}, $keys));
}
public function getEmptyResourceArray(): array
{
$keys = $this->configRepository->getResourcesKeys();
$labels = $this->resourcesLabels;
return array_combine($keys, array_map(function ($i) use ($labels) {
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])];
}, $keys));
}
public function getSummaryForHousehold(?Household $household): array
{
if (null === $household) {
return [
'resources' => $this->getEmptyResourceArray(),
'charges' => $this->getEmptyChargeArray(),
];
}
$personIds = $household->getCurrentPersons()->map(static function (Person $p) { return $p->getId(); });
$ids = implode(', ', array_fill(0, count($personIds), '?'));
$parameters = [...$personIds, $household->getId()];
$rsm = $this->buildRsm();
$resources = $this->em->createNativeQuery(strtr(self::QUERY_RESOURCE_BY_HOUSEHOLD, ['_ids_' => $ids]), $rsm)
->setParameters($parameters)
->getResult();
$charges = $this->em->createNativeQuery(strtr(self::QUERY_CHARGE_BY_HOUSEHOLD, ['_ids_' => $ids]), $rsm)
->setParameters($parameters)
->getResult();
return [
'resources' => array_merge($this->getEmptyResourceArray(), $this->rowToArray($resources, 'resource')),
'charges' => array_merge($this->getEmptyChargeArray(), $this->rowToArray($charges, 'charge')),
];
}
public function getSummaryForPerson(Person $person): array
{
$rsm = $this->buildRsm();
$resources = $this->em->createNativeQuery(self::QUERY_RESOURCE_BY_PERSON, $rsm)
->setParameters([$person->getId()])
->getResult();
$charges = $this->em->createNativeQuery(self::QUERY_CHARGE_BY_PERSON, $rsm)
->setParameters([$person->getId()])
->getResult();
return [
'resources' => array_merge($this->getEmptyResourceArray(), $this->rowToArray($resources, 'resource')),
'charges' => array_merge($this->getEmptyChargeArray(), $this->rowToArray($charges, 'charge')),
];
}
private function buildRsm(): ResultSetMapping
{
$rsm = new ResultSetMapping();
$rsm
->addScalarResult('sum', 'sum')
->addScalarResult('type', 'type');
return $rsm;
}
private function rowToArray(array $rows, string $kind): array
{
switch ($kind) {
case 'charge':
$label = $this->chargeLabels;
break;
case 'resource':
$label = $this->resourcesLabels;
break;
default:
throw new LogicException();
}
$result = [];
foreach ($rows as $row) {
$result[$row['type']] = [
'sum' => (float) $row['sum'],
'label' => $this->translatableStringHelper->localize($label[$row['type']]),
];
}
return $result;
}
}

View File

@ -9,9 +9,9 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Templating;
namespace Chill\BudgetBundle\Templating;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\BudgetBundle\Config\ConfigRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

View File

@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Tests\Controller;
namespace Chill\BudgetBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

View File

@ -0,0 +1,9 @@
// this file loads all assets from the Chill budget bundle
module.exports = function(encore, entries)
{
encore.addAliases({
ChillBudgetAssets: __dirname + '/Resources/public'
});
encore.addEntry('page_budget', __dirname + '/Resources/public/page/index.js');
};

View File

@ -6,7 +6,7 @@
"keywords" : ["chill", "social work"],
"homepage" : "https://framagit.org/Chill-project/BudgetBundle",
"autoload": {
"psr-4": { "Chill\\AMLI\\BudgetBundle\\": "" }
"psr-4": { "Chill\\BudgetBundle\\": "" }
},
"autoload-dev": {
"classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]

View File

@ -1,3 +1,3 @@
chill_amli_budget_controllers:
resource: "@ChillAMLIBudgetBundle/Controller"
chill_budget_controllers:
resource: "@ChillBudgetBundle/Controller"
type: annotation

View File

@ -1,2 +1,2 @@
services:
Chill\AMLI\BudgetBundle\Calculator\CalculatorManager: ~
Chill\BudgetBundle\Calculator\CalculatorManager: ~

View File

@ -1,5 +1,5 @@
services:
Chill\AMLI\BudgetBundle\Config\ConfigRepository:
Chill\BudgetBundle\Config\ConfigRepository:
arguments:
$resources: '%chill_budget.resources%'
$charges: '%chill_budget.charges%'

View File

@ -1,5 +1,5 @@
services:
Chill\AMLI\BudgetBundle\Controller\:
Chill\BudgetBundle\Controller\:
autowire: true
resource: '../../Controller'
tags: ['controller.service_arguments']

View File

@ -1,14 +1,14 @@
services:
Chill\AMLI\BudgetBundle\Form\ResourceType:
Chill\BudgetBundle\Form\ResourceType:
arguments:
$configRepository: '@Chill\AMLI\BudgetBundle\Config\ConfigRepository'
$configRepository: '@Chill\BudgetBundle\Config\ConfigRepository'
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
tags:
- { name: 'form.type' }
Chill\AMLI\BudgetBundle\Form\ChargeType:
Chill\BudgetBundle\Form\ChargeType:
arguments:
$configRepository: '@Chill\AMLI\BudgetBundle\Config\ConfigRepository'
$configRepository: '@Chill\BudgetBundle\Config\ConfigRepository'
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
tags:
- { name: 'form.type' }

View File

@ -1,7 +1,8 @@
services:
Chill\AMLI\BudgetBundle\Menu\UserMenuBuilder:
arguments:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
$translator: '@Symfony\Contracts\Translation\TranslatorInterface'
tags:
- { name: 'chill.menu_builder' }
Chill\BudgetBundle\Menu\PersonMenuBuilder:
autowire: true
autoconfigure: true
Chill\BudgetBundle\Menu\HouseholdMenuBuilder:
autowire: true
autoconfigure: true

View File

@ -1,7 +1,6 @@
services:
Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter:
arguments:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
Chill\BudgetBundle\Security\Authorization\BudgetElementVoter:
autowire: true
tags:
- { name: chill.role }
- { name: security.voter }

View File

@ -0,0 +1,6 @@
services:
Chill\BudgetBundle\Service\:
resource: './../Service'
autowire: true
autoconfigure: true

View File

@ -1,7 +1,7 @@
services:
Chill\AMLI\BudgetBundle\Templating\Twig:
Chill\BudgetBundle\Templating\Twig:
arguments:
$configRepository: '@Chill\AMLI\BudgetBundle\Config\ConfigRepository'
$configRepository: '@Chill\BudgetBundle\Config\ConfigRepository'
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
tags:
- { name: 'twig.extension' }

View File

@ -9,29 +9,29 @@
declare(strict_types=1);
namespace Application\Migrations;
namespace Chill\Migrations\Budget;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* create schema for chill budget.
*/
final class Version20180522080432 extends AbstractMigration
{
public function down(Schema $schema)
public function down(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('CREATE SCHEMA chill_budget CASCADE');
$this->addSql('DROP SCHEMA chill_budget CASCADE');
}
public function up(Schema $schema)
public function getDescription(): string
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
return 'Creation of necessary tables for budget bundle';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE SCHEMA chill_budget');
$this->addSql('DROP SEQUENCE report_id_seq CASCADE');
$this->addSql('CREATE SEQUENCE chill_budget.resource_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE chill_budget.charge_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_budget.resource (id INT NOT NULL, person_id INT DEFAULT NULL, type VARCHAR(255) NOT NULL, amount NUMERIC(10, 2) NOT NULL, comment TEXT DEFAULT NULL, startDate TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, endDate TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))');

View File

@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Application\Migrations;
namespace Chill\Migrations\Budget;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
@ -21,15 +21,11 @@ final class Version20181219145631 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE chill_budget.charge ALTER help SET NOT NULL');
}
public function up(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE chill_budget.charge ALTER help DROP NOT NULL');
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\Migrations\Budget;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20220224090319 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_budget.charge DROP CONSTRAINT FK_5C99D2C3E79FF843');
$this->addSql('ALTER TABLE chill_budget.charge DROP household_id');
$this->addSql('ALTER TABLE chill_budget.resource DROP CONSTRAINT FK_5E0A5E97E79FF843');
$this->addSql('ALTER TABLE chill_budget.resource DROP household_id');
}
public function getDescription(): string
{
return 'Add household to budget AbstractElement';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_budget.charge ADD household_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_budget.charge ADD CONSTRAINT FK_5C99D2C3E79FF843 FOREIGN KEY (household_id) REFERENCES chill_person_household (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_5C99D2C3E79FF843 ON chill_budget.charge (household_id)');
$this->addSql('ALTER TABLE chill_budget.resource ADD household_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_budget.resource ADD CONSTRAINT FK_5E0A5E97E79FF843 FOREIGN KEY (household_id) REFERENCES chill_person_household (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_5E0A5E97E79FF843 ON chill_budget.resource (household_id)');
}
}

View File

@ -0,0 +1,8 @@
budget:
number of elements: >-
{nb_items, plural,
=0 {Aucun élément}
one {Un élément}
many {# éléments}
other {# éléments}
}

View File

@ -1,12 +1,24 @@
Budget: Budget
Resource: Ressource
Charge: Charge
Budget for %name%: Budget de %name%
Budget for household %household%: Budget du ménage
Current budget household members: Budget actuel des membres du ménage
Show budget of %name%: Montrer budget de %name%
See complete budget: Voir budget complet
Hide budget: Masquer
Hide budget of %name%: Masquer budget de %name%
Resource element type: Nature de la ressource
Actual budget: Budget actuel
Actual budget: Éléments actuels du budget
Actual resources: Ressources actuelles
Actual resources for %name%: Ressources actuelles de %name%
Actual charges for %name%: Charges actuelles de %name%
Actual charges: Charges actuelles
Past budget: Éléments du budget passé
Show past budget: Montrer budget passé
Show future budget: Montrer budget future
Past resources: Ressources passées
Past charges: Chargées passées
Past charges: Charges passées
Future budget: Futurs éléments du budget
Future resources: Ressources futures
Future charges: Charges futures
@ -17,6 +29,7 @@ End of validity period: Fin de la période de validité
Total: Total
Create new resource: Créer une nouvelle ressource
Create new charge: Créer une nouvelle charge
See person: Voir personne
There isn't any element recorded: Aucun élément enregistré
No resources registered: Aucune ressource enregistrée
@ -25,11 +38,13 @@ No past resources registered: Aucune ressource passée
No past charges registered: Aucune charge passée
No future resources registered: Aucune ressource future enregistrée
No future charges registered: Aucune ressource future enregistrée
No current budget element registered: Pas des éléments de budget actuelles enregistrés
New Resource for %name%: Nouvelle ressource pour %name%
New Charge for %name%: Nouvelle charge pour %name%
Edit Resource for %name%: Modifier une ressource de %name%
Edit Charge for %name%: Modifier une charge de %name%
New resource: Nouvelle ressource
New charge: Nouvelle charge
Edit resource: Modifier une ressource
Edit: Modifier
Edit charge: Modifier une charge
Remove resource: Supprimer la ressource
Remove charge: Supprimer la charge
Are you sure you want to remove the ressource "%type%" associated to "%name%" ?: Êtes-vous sûr·e de vouloir supprimer la ressource de nature "%type%" associée à %name% ?
@ -55,6 +70,7 @@ charge.help.not-concerned: Non concerné
Budget calculator: Calculs et indices sur le budget
Budget calculator result: Résultats
The balance: Différence entre ressources et charges
'Valid since %startDate% until %endDate%': Valide depuis le %startDate% jusqu'au %endDate%
'Valid since %startDate%': Valide depuis le %startDate%
Valid since %startDate% until %endDate%: Valide depuis le %startDate% jusqu'au %endDate%
Valid since %startDate%: Valide depuis le %startDate%

View File

@ -25,7 +25,7 @@
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}<!-- block personcontent empty -->
{% block admin_content %}<!-- block content empty -->
<h1>{{ 'CustomFields configuration' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@ -28,6 +28,7 @@ use GuzzleHttp\Client;
use GuzzleHttp\Exception\TransferException;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\RedirectResponse;
@ -211,14 +212,14 @@ final class DocGeneratorTemplateController extends AbstractController
$builder = $this->createFormBuilder(
array_merge(
$context->getFormData($template, $entity),
$isTest ? ['test_file' => null] : []
$isTest ? ['test_file' => null, 'show_data' => false] : []
)
);
$context->buildPublicForm($builder, $template, $entity);
} else {
$builder = $this->createFormBuilder(
['test_file' => null]
['test_file' => null, 'show_data' => false]
);
}
@ -227,6 +228,10 @@ final class DocGeneratorTemplateController extends AbstractController
'label' => 'Template file',
'required' => false,
]);
$builder->add('show_data', CheckboxType::class, [
'label' => 'Show data instead of generating',
'required' => false,
]);
}
$form = $builder->getForm()->handleRequest($request);
@ -278,6 +283,11 @@ final class DocGeneratorTemplateController extends AbstractController
}
$datas = $context->getData($template, $entity, $contextGenerationData);
if ($isTest && $form['show_data']->getData()) {
// very ugly hack...
dd($datas);
}
try {
$generatedResource = $this->driver->generateFromResource($templateResource, $template->getFile()->getType(), $datas, $template->getFile()->getFilename());
} catch (TemplateException $e) {

View File

@ -24,22 +24,15 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt
{
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
*
* @var Person
*/
private $person;
private Person $person;
public function getCenter()
{
return $this->getPerson()->getCenter();
}
/**
* Get person.
*
* @return \Chill\MainBundle\Entity\Person
*/
public function getPerson()
public function getPerson(): Person
{
return $this->person;
}

View File

@ -25,7 +25,7 @@
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}<!-- block personcontent empty -->
{% block admin_content %}<!-- block content empty -->
<h1>{{ 'Documents configuration' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@ -20,7 +20,7 @@
{% set activeRouteKey = '' %}
{% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %}
{% block personcontent %}
{% block content %}
<h1>{{ 'Edit Document' | trans }}</h1>
{{ form_errors(form) }}

View File

@ -39,7 +39,7 @@
{{ encore_entry_link_tags('mod_entity_workflow_pick') }}
{% endblock %}
{% block personcontent %}
{% block content %}
<div class="col-md-10 col-xxl">
<h1>{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>

View File

@ -22,7 +22,7 @@
{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
{% endblock %}
{% block personcontent %}
{% block content %}
<h1>{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>
{{ form_errors(form) }}

View File

@ -27,7 +27,7 @@
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block personcontent %}
{% block content %}
<h1>{{ 'Document %title%' | trans({ '%title%': document.title }) }}</h1>
{{ mm.mimeIcon(document.object.type) }}

View File

@ -25,7 +25,7 @@
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}<!-- block personcontent empty -->
{% block admin_content %}<!-- block content empty -->
<h1>{{ 'Events configuration' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@ -21,7 +21,7 @@
{% block title %}{{ 'Events participation' |trans }}{% endblock title %}
{% block personcontent %}
{% block content %}
<h2>{{ 'Events participation' |trans }}</h2>
<table class="table table-striped table-bordered mt-3 events">

View File

@ -5,7 +5,7 @@
{% block title 'Remove family membership'|trans %}
{% block personcontent %}
{% block content %}
{{ include('ChillMainBundle:Util:confirmation_template.html.twig',
{

View File

@ -4,7 +4,7 @@
{% set title = 'Edit family members for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{{ form_start(form) }}

View File

@ -88,7 +88,7 @@
{% import _self as m %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{% if familyMembers|length == 0 %}

View File

@ -4,7 +4,7 @@
{% set title = 'New family members for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
{{ form_start(form) }}

View File

@ -6,7 +6,7 @@
{% block title title %}
{% block personcontent %}
{% block content %}
<h1>{{ title }}</h1>
<dl class="chill_view_data">

View File

@ -11,3 +11,7 @@ $chill-household-context: #929d69;
$social-issue-color: #4bafe8;
$social-action-color: $orange;
$activity-color: yellowgreen;
// budget colors
$budget-resource-color: #6d9e63;
$budget-charge-color: #e03851;

View File

@ -8,7 +8,7 @@
{% endblock %}
{% block content %}
{% block admin_content %}<!-- block personcontent empty -->
{% block admin_content %}<!-- block content empty -->
<div class="container-fluid">
<div class="col-10 push-1">
<h2>{{ 'Welcome to the admin section !'|trans }}</h2>

View File

@ -25,7 +25,7 @@
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}<!-- block personcontent empty -->
{% block admin_content %}<!-- block content empty -->
<h1>{{ 'Permissions management of your chill installation' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@ -13,9 +13,8 @@ services:
- { name: 'chill.menu_builder' }
Chill\MainBundle\Routing\MenuBuilder\SectionMenuBuilder:
arguments:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
$translator: '@Symfony\Contracts\Translation\TranslatorInterface'
autowire: true
autoconfigure: true
tags:
- { name: 'chill.menu_builder' }

View File

@ -12,6 +12,8 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Entity;
use ArrayIterator;
use Chill\BudgetBundle\Entity\Charge;
use Chill\BudgetBundle\Entity\Resource;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Entity\Address;
@ -158,6 +160,22 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
*/
private $birthdate;
/**
* @ORM\OneToMany(
* targetEntity=Charge::class,
* mappedBy="person"
* )
*/
private Collection $budgetCharges;
/**
* @ORM\OneToMany(
* targetEntity=Resource::class,
* mappedBy="person"
* )
*/
private Collection $budgetResources;
/**
* The person's center.
*
@ -501,6 +519,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
$this->maritalStatusComment = new CommentEmbeddable();
$this->periodLocatedOn = new ArrayCollection();
$this->accompanyingPeriodRequested = new ArrayCollection();
$this->budgetResources = new ArrayCollection();
$this->budgetCharges = new ArrayCollection();
$this->resources = new ArrayCollection();
}
@ -525,20 +545,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* @return $this
*/
public function addAddress(Address $address)
public function addAddress(Address $address): self
{
$this->addresses[] = $address;
return $this;
}
/**
* @return $this
*/
public function addAltName(PersonAltName $altName)
public function addAltName(PersonAltName $altName): self
{
if (false === $this->altNames->contains($altName)) {
$this->altNames->add($altName);
@ -548,6 +562,20 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
public function addBudgetCharge(Charge $budgetCharge): self
{
$this->budgetCharges[] = $budgetCharge;
return $this;
}
public function addBudgetResource(Resource $budgetResource): self
{
$this->budgetResources[] = $budgetResource;
return $this;
}
public function addHouseholdParticipation(HouseholdMember $member): self
{
$this->householdParticipations[] = $member;
@ -639,8 +667,6 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
*
* Used in template, to find the participation when iterating on a list
* of period.
*
* @return AccompanyingPeriodParticipation
*/
public function findParticipationForPeriod(AccompanyingPeriod $period): ?AccompanyingPeriodParticipation
{
@ -847,32 +873,33 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->altNames;
}
/**
* Get birthdate.
*
* @return DateTime
*/
public function getBirthdate()
public function getBirthdate(): ?DateTime
{
return $this->birthdate;
}
/**
* Get center.
*
* @return Center
* @return Collection|BudgetCharges[]
*/
public function getCenter()
public function getBudgetCharges(): Collection
{
return $this->budgetCharges;
}
/**
* @return Collection|BudgetResources[]
*/
public function getBudgetResources(): Collection
{
return $this->budgetResources;
}
public function getCenter(): ?Center
{
return $this->center;
}
/**
* Get cFData.
*
* @return array
*/
public function getCFData()
public function getCFData(): ?array
{
if (null === $this->cFData) {
$this->cFData = [];
@ -881,32 +908,17 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->cFData;
}
/**
* Get civility.
*
* @return Civility
*/
public function getCivility()
public function getCivility(): ?Civility
{
return $this->civility;
}
/**
* Get contactInfo.
*
* @return string
*/
public function getcontactInfo()
public function getcontactInfo(): ?string
{
return $this->contactInfo;
}
/**
* Get countryOfBirth.
*
* @return Chill\MainBundle\Entity\Country
*/
public function getCountryOfBirth()
public function getCountryOfBirth(): ?Country
{
return $this->countryOfBirth;
}
@ -1050,22 +1062,12 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->deathdate;
}
/**
* Get email.
*
* @return string
*/
public function getEmail()
public function getEmail(): ?string
{
return $this->email;
}
/**
* Get firstName.
*
* @return string
*/
public function getFirstName()
public function getFirstName(): string
{
return $this->firstName;
}
@ -1075,17 +1077,12 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->fullnameCanonical;
}
/**
* Get gender.
*
* @return string
*/
public function getGender()
public function getGender(): ?string
{
return $this->gender;
}
public function getGenderComment(): CommentEmbeddable
public function getGenderComment(): ?CommentEmbeddable
{
return $this->genderComment;
}
@ -1190,22 +1187,12 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->getCurrentPersonAddress();
}
/**
* Get lastName.
*
* @return string
*/
public function getLastName()
public function getLastName(): string
{
return $this->lastName;
}
/**
* Get maritalStatus.
*
* @return MaritalStatus
*/
public function getMaritalStatus()
public function getMaritalStatus(): ?MaritalStatus
{
return $this->maritalStatus;
}
@ -1220,12 +1207,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->maritalStatusDate;
}
/**
* Get memo.
*
* @return string
*/
public function getMemo()
public function getMemo(): ?string
{
return $this->memo;
}
@ -1235,11 +1217,6 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->mobilenumber;
}
/**
* Get nationality.
*
* @return Country
*/
public function getNationality(): ?Country
{
return $this->nationality;
@ -1300,12 +1277,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->phonenumber;
}
/**
* Get placeOfBirth.
*
* @return string
*/
public function getPlaceOfBirth()
public function getPlaceOfBirth(): ?string
{
return $this->placeOfBirth;
}
@ -1464,10 +1436,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
$this->addresses->removeElement($address);
}
/**
* @return $this
*/
public function removeAltName(PersonAltName $altName)
public function removeAltName(PersonAltName $altName): self
{
if ($this->altNames->contains($altName)) {
$altName->setPerson(null);
@ -1477,10 +1446,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* @return $this
*/
public function removeOtherPhoneNumber(PersonPhone $otherPhoneNumber)
public function removeBudgetCharge(Charge $budgetCharge): self
{
$this->budgetCharges->removeElement($budgetCharge);
return $this;
}
public function removeBudgetResource(Resource $budgetResource): self
{
$this->budgetResources->removeElement($budgetResource);
return $this;
}
public function removeOtherPhoneNumber(PersonPhone $otherPhoneNumber): self
{
if ($this->otherPhoneNumbers->contains($otherPhoneNumber)) {
$this->otherPhoneNumbers->removeElement($otherPhoneNumber);
@ -1503,10 +1483,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* @return $this
*/
public function setAltNames(Collection $altNames)
public function setAltNames(Collection $altNames): self
{
$this->altNames = $altNames;
@ -1514,25 +1491,16 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
}
/**
* Set birthdate.
*
* @param DateTime $birthdate
*
* @return Person
*/
public function setBirthdate($birthdate)
public function setBirthdate($birthdate): self
{
$this->birthdate = $birthdate;
return $this;
}
/**
* Set the center.
*
* @return \Chill\PersonBundle\Entity\Person
*/
public function setCenter(Center $center)
public function setCenter(Center $center): self
{
$this->center = $center;
@ -1540,41 +1508,23 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
}
/**
* Set cFData.
*
* @param array $cFData
*
* @return Report
*/
public function setCFData($cFData)
public function setCFData(?array $cFData)
{
$this->cFData = $cFData;
return $this;
}
/**
* Set civility.
*
* @param Civility $civility
*
* @return Person
*/
public function setCivility(?Civility $civility = null)
public function setCivility(?Civility $civility = null): self
{
$this->civility = $civility;
return $this;
}
/**
* Set contactInfo.
*
* @param string $contactInfo
*
* @return Person
*/
public function setcontactInfo($contactInfo)
public function setcontactInfo($contactInfo): self
{
if (null === $contactInfo) {
$contactInfo = '';
@ -1585,14 +1535,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* Set countryOfBirth.
*
* @param Chill\MainBundle\Entity\Country $countryOfBirth
*
* @return Person
*/
public function setCountryOfBirth(?Country $countryOfBirth = null)
public function setCountryOfBirth(?Country $countryOfBirth = null): self
{
$this->countryOfBirth = $countryOfBirth;
@ -1620,14 +1563,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* Set email.
*
* @param string $email
*
* @return Person
*/
public function setEmail($email)
public function setEmail(?string $email): self
{
if (null === $email) {
$email = '';
@ -1638,35 +1574,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* Set firstName.
*
* @param string $firstName
*
* @return Person
*/
public function setFirstName($firstName)
public function setFirstName(string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function setFullnameCanonical($fullnameCanonical): Person
public function setFullnameCanonical($fullnameCanonical): self
{
$this->fullnameCanonical = $fullnameCanonical;
return $this;
}
/**
* Set gender.
*
* @param string $gender
*
* @return Person
*/
public function setGender($gender)
public function setGender(?string $gender): self
{
$this->gender = $gender;
@ -1680,28 +1602,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* Set lastName.
*
* @param string $lastName
*
* @return Person
*/
public function setLastName($lastName)
public function setLastName(string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
/**
* Set maritalStatus.
*
* @param MaritalStatus $maritalStatus
*
* @return Person
*/
public function setMaritalStatus(?MaritalStatus $maritalStatus = null)
public function setMaritalStatus(?MaritalStatus $maritalStatus = null): self
{
$this->maritalStatus = $maritalStatus;
@ -1722,14 +1630,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* Set memo.
*
* @param string $memo
*
* @return Person
*/
public function setMemo($memo)
public function setMemo(?string $memo): self
{
if (null === $memo) {
$memo = '';
@ -1742,21 +1643,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
public function setMobilenumber(?PhoneNumber $mobilenumber)
public function setMobilenumber(?PhoneNumber $mobilenumber): self
{
$this->mobilenumber = $mobilenumber;
return $this;
}
/**
* Set nationality.
*
* @param Chill\MainBundle\Entity\Country $nationality
*
* @return Person
*/
public function setNationality(?Country $nationality = null)
public function setNationality(?Country $nationality = null): self
{
$this->nationality = $nationality;
@ -1770,31 +1664,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* @return $this
*/
public function setOtherPhoneNumbers(Collection $otherPhoneNumbers)
public function setOtherPhoneNumbers(Collection $otherPhoneNumbers): self
{
$this->otherPhoneNumbers = $otherPhoneNumbers;
return $this;
}
public function setPhonenumber(?PhoneNumber $phonenumber)
public function setPhonenumber(?PhoneNumber $phonenumber): self
{
$this->phonenumber = $phonenumber;
return $this;
}
/**
* Set placeOfBirth.
*
* @param string $placeOfBirth
*
* @return Person
*/
public function setPlaceOfBirth($placeOfBirth)
public function setPlaceOfBirth(?string $placeOfBirth): self
{
if (null === $placeOfBirth) {
$placeOfBirth = '';
@ -1806,13 +1690,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
}
/**
* Set spokenLanguages.
*
* @param type $spokenLanguages
*
* @return Person
*/
public function setSpokenLanguages($spokenLanguages)
public function setSpokenLanguages($spokenLanguages): self
{
$this->spokenLanguages = $spokenLanguages;

View File

@ -33,10 +33,7 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface
*/
protected $showAccompanyingPeriod;
/**
* @var TranslatorInterface
*/
protected $translator;
protected TranslatorInterface $translator;
private Security $security;

View File

@ -13,7 +13,6 @@ namespace Chill\PersonBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\Query\Parameter;
use Knp\Menu\MenuItem;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
@ -26,10 +25,10 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
{
protected AuthorizationCheckerInterface $authorizationChecker;
protected TranslatorInterface $translator;
protected ParameterBagInterface $parameterBag;
protected TranslatorInterface $translator;
/**
* SectionMenuBuilder constructor.
*/

Some files were not shown because too many files have changed in this diff Show More