diff --git a/CHANGELOG.md b/CHANGELOG.md index 91e0083c4..0ab0e3192 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,8 @@ 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) -* [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) +* [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 * [thirdparty] Fix display of multiple contact badges so they wrap onto next line (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/482) diff --git a/docs/source/development/pagination.rst b/docs/source/development/pagination.rst index 1a2c91ff0..a9df72805 100644 --- a/docs/source/development/pagination.rst +++ b/docs/source/development/pagination.rst @@ -32,7 +32,7 @@ Then, render the pagination using the dedicated twig function. {% block title 'Item list'|trans %} - {% block personcontent %} + {% block content %} diff --git a/docs/source/development/user-interface/layout-template-usage.rst b/docs/source/development/user-interface/layout-template-usage.rst index 69848c650..1ddbacafd 100644 --- a/docs/source/development/user-interface/layout-template-usage.rst +++ b/docs/source/development/user-interface/layout-template-usage.rst @@ -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 diff --git a/phpstan-deprecations.neon b/phpstan-deprecations.neon index 1e80ab775..2de8b8bc8 100644 --- a/phpstan-deprecations.neon +++ b/phpstan-deprecations.neon @@ -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: """ diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig index 9f8172bb4..43c2157fa 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig @@ -5,7 +5,7 @@ {% block title 'Remove activity'|trans %} -{% block personcontent %} +{% block content %} {{ include('@ChillMain/Util/confirmation_template.html.twig', { 'title' : 'Remove activity'|trans, diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig index 82c7403c6..91b3867c1 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig @@ -20,7 +20,7 @@ {% block title 'Update activity'|trans %} -{% block personcontent %} +{% block content %}
{# <=== vue component #} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig index 8b30bc6c7..f55c68fcc 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig @@ -30,7 +30,7 @@ {{ encore_entry_link_tags('mod_notification_toggle_read_status') }} {% endblock %} -{% block personcontent %} +{% block content %} {% set person_id = null %} {% if person %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig index 962aee806..d57fc3412 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig @@ -4,7 +4,7 @@ {% block title 'Activity creation' |trans %} -{% block personcontent %} +{% block content %}
{# <=== vue component #} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig index da9b561d0..f616012e4 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig @@ -4,6 +4,6 @@ {% block title 'Activity creation'|trans %} -{% block personcontent %} +{% block content %} {% include 'ChillActivityBundle:Activity:selectType.html.twig' %} {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig index e593b0131..5776eddb5 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig @@ -18,11 +18,11 @@ {% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} -{% block personcontent -%} +{% block content -%}
{% include 'ChillActivityBundle:Activity:show.html.twig' with {'context': 'person'} %}
-{% endblock personcontent %} +{% endblock %} {% block block_post_menu %}
diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Admin/layout_activity.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Admin/layout_activity.html.twig index bf658e505..940389ca1 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Admin/layout_activity.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Admin/layout_activity.html.twig @@ -25,7 +25,7 @@ {% endblock %} {% block layout_wvm_content %} - {% block admin_content %} + {% block admin_content %}

{{ 'Activity configuration' |trans }}

{% endblock %} {% endblock %} \ No newline at end of file diff --git a/src/Bundle/ChillAsideActivityBundle/src/Resources/views/Admin/layout_asideactivity.html.twig b/src/Bundle/ChillAsideActivityBundle/src/Resources/views/Admin/layout_asideactivity.html.twig index 3f44e432d..c328d2030 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Resources/views/Admin/layout_asideactivity.html.twig +++ b/src/Bundle/ChillAsideActivityBundle/src/Resources/views/Admin/layout_asideactivity.html.twig @@ -6,7 +6,7 @@ {% block layout_wvm_content %} {% block admin_content %} - +

{{ 'Aside activity configuration'|trans }}

{% endblock %} {% endblock %} diff --git a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php index 707ae0221..88bd5cf23 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php @@ -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 { diff --git a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php index 0916b703c..21c9e18ca 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php @@ -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; diff --git a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php index 7de147ffb..c3cc40008 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php @@ -9,7 +9,7 @@ declare(strict_types=1); -namespace Chill\AMLI\BudgetBundle\Calculator; +namespace Chill\BudgetBundle\Calculator; class CalculatorResult { diff --git a/src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php b/src/Bundle/ChillBudgetBundle/ChillBudgetBundle.php similarity index 75% rename from src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php rename to src/Bundle/ChillBudgetBundle/ChillBudgetBundle.php index add60c5df..ce8214604 100644 --- a/src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php +++ b/src/Bundle/ChillBudgetBundle/ChillBudgetBundle.php @@ -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) { diff --git a/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php b/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php index dc3ffe20d..73f6fb355 100644 --- a/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php +++ b/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php @@ -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 */ diff --git a/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php b/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php index c8652e2e9..94cb9255a 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php @@ -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) diff --git a/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php b/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php index b06773609..ec556ffed 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php @@ -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() diff --git a/src/Bundle/ChillBudgetBundle/Controller/ElementController.php b/src/Bundle/ChillBudgetBundle/Controller/ElementController.php index 3a22e321f..0230f53b9 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ElementController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ElementController.php @@ -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 ?? [], + ]); + } } diff --git a/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php b/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php index 4ee8bd082..3ecd53097 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php @@ -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() diff --git a/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php b/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillBudgetExtension.php similarity index 86% rename from src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php rename to src/Bundle/ChillBudgetBundle/DependencyInjection/ChillBudgetExtension.php index bea107131..cf7e4fad2 100644 --- a/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php +++ b/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillBudgetExtension.php @@ -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], ], ]); } diff --git a/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php b/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php index 0a53e5160..ec47d5faa 100644 --- a/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php +++ b/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php @@ -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) { diff --git a/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php index 407be6bff..a18e17ae6 100644 --- a/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php @@ -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() diff --git a/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php b/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php index 5f43c4262..747e6f4b4 100644 --- a/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php +++ b/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php @@ -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; diff --git a/src/Bundle/ChillBudgetBundle/Entity/Charge.php b/src/Bundle/ChillBudgetBundle/Entity/Charge.php index e893f99af..4acc6e855 100644 --- a/src/Bundle/ChillBudgetBundle/Entity/Charge.php +++ b/src/Bundle/ChillBudgetBundle/Entity/Charge.php @@ -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(); } diff --git a/src/Bundle/ChillBudgetBundle/Entity/Resource.php b/src/Bundle/ChillBudgetBundle/Entity/Resource.php index bd13e0dd0..6100e90a0 100644 --- a/src/Bundle/ChillBudgetBundle/Entity/Resource.php +++ b/src/Bundle/ChillBudgetBundle/Entity/Resource.php @@ -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(); } diff --git a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php index 96aea3ea4..1e054d86b 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php @@ -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() diff --git a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php index 9f772648d..51e3f6799 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php @@ -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() diff --git a/src/Bundle/ChillBudgetBundle/Menu/HouseholdMenuBuilder.php b/src/Bundle/ChillBudgetBundle/Menu/HouseholdMenuBuilder.php new file mode 100644 index 000000000..e983ddebb --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Menu/HouseholdMenuBuilder.php @@ -0,0 +1,53 @@ +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']; + } +} diff --git a/src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillBudgetBundle/Menu/PersonMenuBuilder.php similarity index 72% rename from src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php rename to src/Bundle/ChillBudgetBundle/Menu/PersonMenuBuilder.php index f5dc02266..047185b18 100644 --- a/src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillBudgetBundle/Menu/PersonMenuBuilder.php @@ -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); } } diff --git a/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php b/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php index 56f21b6fb..62aa9eea6 100644 --- a/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php +++ b/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php @@ -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, ]); diff --git a/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php b/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php index f7440a281..23cc5ca54 100644 --- a/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php +++ b/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php @@ -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(); diff --git a/src/Bundle/ChillBudgetBundle/Resources/public/page/chillbudget.scss b/src/Bundle/ChillBudgetBundle/Resources/public/page/chillbudget.scss new file mode 100644 index 000000000..20a87cce2 --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/public/page/chillbudget.scss @@ -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; } \ No newline at end of file diff --git a/src/Bundle/ChillBudgetBundle/Resources/public/page/index.js b/src/Bundle/ChillBudgetBundle/Resources/public/page/index.js new file mode 100644 index 000000000..ad7eba2d9 --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/public/page/index.js @@ -0,0 +1 @@ +require('./chillbudget.scss'); \ No newline at end of file diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_budget.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_budget.html.twig new file mode 100644 index 000000000..6e248bf0c --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_budget.html.twig @@ -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 %} + + +

{{ 'Actual budget'|trans }}

+ +{% 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 %} +
+
+

{{ "There isn't any element recorded"|trans }}

+
+
+{% endif %} + +{% if pastCharges|length > 0 or pastResources|length > 0 %} +

{{ 'Past budget'|trans }}

+ + {% include 'ChillBudgetBundle:Budget:_past_budget.html.twig' with { + 'pastCharges': pastCharges, + 'pastResources': pastResources, + 'entity': entity + } %} +{% endif %} + +{% if futureCharges|length > 0 or futureResources|length > 0 %} +

{{ 'Future budget'|trans }}

+ + {% include 'ChillBudgetBundle:Budget:_future_budget.html.twig' with { + 'futureResources': futureResources, + 'futureCharges': futureCharges, + 'entity': entity + } %} +{% endif %} + + + diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_current_budget.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_current_budget.html.twig new file mode 100644 index 000000000..b996da211 --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_current_budget.html.twig @@ -0,0 +1,30 @@ +{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %} + +{#

{{ 'Actual budget'|trans }}

#} + +
+

{{ 'Actual resources'|trans }}

+ + {% if actualResources|length > 0 %} +
+ {{ table_elements(actualResources, 'resource') }} +
+ {% else %} +
+ {{ 'No resources registered'|trans }} +
+ {% endif %} +
+ +
+

{{ 'Actual charges'|trans }}

+ {% if actualCharges|length > 0 %} +
+ {{ table_elements(actualCharges, 'charge') }} +
+ {% else %} +
+ {{ 'No charges registered'|trans }} +
+ {% endif %} +
diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_future_budget.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_future_budget.html.twig new file mode 100644 index 000000000..1547d8749 --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_future_budget.html.twig @@ -0,0 +1,51 @@ +{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %} + +
+
+

+ +

+ +
+ +
+

{{ 'Future resources'|trans }}

+ + {% if futureResources|length > 0 %} +
+ {{ table_elements(futureResources, 'resource') }} +
+ {% else %} +
+ {{ 'No future resources registered'|trans }} +
+ {% endif %} +
+
+

{{ 'Future charges'|trans }}

+ + {% if futureCharges|length > 0 %} +
+ {{ table_elements(futureCharges, 'charge') }} +
+ {% else %} +
+ {{ 'No future charges registered'|trans }} +
+ {% endif %} +
+
+
+
\ No newline at end of file diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig new file mode 100644 index 000000000..41b6f36df --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig @@ -0,0 +1,97 @@ +{% macro table_elements(elements, family) %} +
+ + + + + + + + + + {% set total = 0 %} + {% for f in elements %} + {% set total = total + f.amount %} + + + + + + + {% endfor %} + + + + + + + +
{{ 'Budget element type'|trans }}{{ 'Amount'|trans }}{{ 'Validity period'|trans }} 
+ + + {{ f.type|budget_element_type_display(family) }} + + {{ f.amount|format_currency('EUR') }} + {% if f.endDate is not null %} + {{ f.startDate|format_date('short') ~ ' - ' ~ f.endDate|format_date('short') }} + {% else %} + {{ f.startDate|format_date('short') ~ ' - ...' }} + {% endif %} + +
    + {% if is_granted('CHILL_BUDGET_ELEMENT_SEE', f) %} +
  • + +
  • + {% endif %} + {% if is_granted('CHILL_BUDGET_ELEMENT_UPDATE', f) %} +
  • + +
  • + {% endif %} + {% if is_granted('CHILL_BUDGET_ELEMENT_DELETE', f) %} +
  • + +
  • + {% endif %} +
+
+ {{ 'Total'|trans }} + + {{ total|format_currency('EUR') }} +   
+{% 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) %} + + + + + + + + + + + + + + + + +
  {{ 'Budget calculator result'|trans }}
{{ 'The balance'|trans }}  + {{ result|format_currency('EUR') }} +
+{% endmacro %} diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_past_budget.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_past_budget.html.twig new file mode 100644 index 000000000..14573048e --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_past_budget.html.twig @@ -0,0 +1,53 @@ +{% from 'ChillBudgetBundle:Budget:_macros.html.twig' import table_elements, table_results %} + +
+
+

+ +

+ +
+ +
+

{{ 'Past resources'|trans }}

+ + {% if pastResources|length > 0 %} +
+ {{ table_elements(pastResources, 'resource') }} +
+ {% else %} +
+ {{ 'No past resources registered'|trans }} +
+ {% endif %} +
+ +
+

{{ 'Past charges'|trans }}

+ + {% if pastCharges|length > 0 %} +
+ {{ table_elements(pastCharges, 'charge') }} +
+ {% else %} +
+ {{ 'No past charges registered'|trans }} +
+ {% endif %} +
+
+ +
+
\ No newline at end of file diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/confirm_delete.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/confirm_delete.html.twig index 1f191eafd..f64184d6f 100644 --- a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/confirm_delete.html.twig +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/confirm_delete.html.twig @@ -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 } ) }} diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/edit.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/edit.html.twig index 5b1bc538a..fed80a5c0 100644 --- a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/edit.html.twig +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/edit.html.twig @@ -1,31 +1,43 @@ -{% 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 %}

{{ title }}

{{ form_start(form) }} {{ form_row(form.type) }} {{ form_row(form.amount) }} -{{ form_row(form.help) }} +{{ form_row(form.help) }} {{ form_row(form.comment) }} {{ form_row(form.startDate) }} {{ form_row(form.endDate) }} - + {{ form_end(form) }} {% endblock %} diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/new.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/new.html.twig index e784b5bf7..817d501ca 100644 --- a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/new.html.twig +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/new.html.twig @@ -1,31 +1,42 @@ -{% 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 %}

{{ title }}

{{ form_start(form) }} {{ form_row(form.type) }} {{ form_row(form.amount) }} -{{ form_row(form.help) }} +{{ form_row(form.help) }} {{ form_row(form.comment) }} {{ form_row(form.startDate) }} {{ form_row(form.endDate) }} - + {{ form_end(form) }} {% endblock %} diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/view.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/view.html.twig index d939fe81a..d3b9ef71b 100644 --- a/src/Bundle/ChillBudgetBundle/Resources/views/Charge/view.html.twig +++ b/src/Bundle/ChillBudgetBundle/Resources/views/Charge/view.html.twig @@ -1,49 +1,68 @@ -{% 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 %} -

{{ title }}

+{% block content %} +
+

{{ title }}

-
-
{{ 'Type'|trans }}
-
{{ element.type|budget_element_type_display('charge') }}
- -
{{ 'Amount'|trans }}
-
{{ element.amount|localizedcurrency('EUR') }}
- -
{{ 'Validity period'|trans }}
-
- {% if element.endDate is not null %} - {{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': element.startDate|localizeddate('long', 'none'), '%endDate%': familyMember.endDate|localizeddate('long', 'none') } ) }} - {% else %} - {{ 'Valid since %startDate%'|trans( { '%startDate%': element.startDate|localizeddate('long', 'none') } ) }} - {% endif %} -
- -
{{ 'Comment'|trans }}
-
- {%- if element.comment is not empty -%} -
- {{ element.comment }} -
- {%- else -%} - {{ 'Not given'|trans }} - {%- endif -%} -
-
+
+
+
+

+ + {{ element.type|budget_element_type_display('charge') }} +

+
+
+
+
{{ 'Amount'|trans }}
+
{{ element.amount|format_currency('EUR') }}
+
{{ 'Validity period'|trans }}
+
+ {% if element.endDate is not null %} + {{ '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 %} +
+
{{ 'Comment'|trans }}
+
+ {%- if element.comment is not empty -%} +
+ {{ element.comment }} +
+ {%- else -%} + {{ 'Not given'|trans }} + {%- endif -%} +
+
+
+
+
+