mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
initial commit
This commit is contained in:
commit
f6b9517e50
22
Calculator/CalculatorInterface.php
Normal file
22
Calculator/CalculatorInterface.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Calculator;
|
||||
|
||||
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
interface CalculatorInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param AbstractElement[] $elements
|
||||
*/
|
||||
public function calculate(array $elements) : ?CalculatorResult;
|
||||
|
||||
public function getAlias();
|
||||
}
|
67
Calculator/CalculatorManager.php
Normal file
67
Calculator/CalculatorManager.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Calculator;
|
||||
|
||||
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class CalculatorManager
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var CalculatorInterface[]
|
||||
*/
|
||||
protected $calculators = [];
|
||||
|
||||
protected $defaultCalculator = [];
|
||||
|
||||
public function addCalculator(CalculatorInterface $calculator, bool $default)
|
||||
{
|
||||
$this->calculators[$calculator::getAlias()] = $calculator;
|
||||
|
||||
if ($default) {
|
||||
$this->defaultCalculator[] = $calculator::getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $alias
|
||||
* @return CalculatorInterface
|
||||
*/
|
||||
public function getCalculator($alias)
|
||||
{
|
||||
if (FALSE === \array_key_exists($alias, $this->calculators)) {
|
||||
throw new \OutOfBoundsException("The calculator with alias '$alias' does "
|
||||
. "not exists. Possible values are ". \implode(", ", \array_keys($this->calculators)));
|
||||
}
|
||||
|
||||
return $this->calculators[$alias];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param AbstractElement[] $elements
|
||||
* @return CalculatorResult[]
|
||||
*/
|
||||
public function calculateDefault(array $elements)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($this->defaultCalculator as $alias) {
|
||||
$calculator = $this->calculators[$alias];
|
||||
$result = $calculator->calculate($elements);
|
||||
|
||||
if ($result !== null) {
|
||||
$results[$calculator::getAlias()] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
23
Calculator/CalculatorResult.php
Normal file
23
Calculator/CalculatorResult.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Calculator;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class CalculatorResult
|
||||
{
|
||||
const TYPE_RATE = 'rate';
|
||||
const TYPE_CURRENCY = 'currency';
|
||||
const TYPE_PERCENTAGE = 'percentage';
|
||||
|
||||
public $type;
|
||||
|
||||
public $result;
|
||||
|
||||
public $label;
|
||||
}
|
16
ChillAMLIBudgetBundle.php
Normal file
16
ChillAMLIBudgetBundle.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Chill\AMLI\BudgetBundle\DependencyInjection\Compiler\CalculatorCompilerPass;
|
||||
|
||||
class ChillAMLIBudgetBundle extends Bundle
|
||||
{
|
||||
public function build(\Symfony\Component\DependencyInjection\ContainerBuilder $container)
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new CalculatorCompilerPass());
|
||||
}
|
||||
}
|
72
Config/ConfigRepository.php
Normal file
72
Config/ConfigRepository.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Config;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class ConfigRepository
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $charges;
|
||||
|
||||
public function __construct($resources, $charges)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
$this->charges = $charges;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array where keys are the resource'key and label the ressource label
|
||||
*/
|
||||
public function getResourcesLabels()
|
||||
{
|
||||
$resources = array();
|
||||
|
||||
foreach ($this->resources as $definition) {
|
||||
$resources[$definition['key']] = $this->normalizeLabel($definition['labels']);
|
||||
}
|
||||
|
||||
return $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array where keys are the resource'key and label the ressource label
|
||||
*/
|
||||
public function getChargesLabels()
|
||||
{
|
||||
$charges = array();
|
||||
|
||||
foreach ($this->charges as $definition) {
|
||||
$charges[$definition['key']] = $this->normalizeLabel($definition['labels']);
|
||||
}
|
||||
|
||||
return $charges;
|
||||
}
|
||||
|
||||
private function normalizeLabel($labels)
|
||||
{
|
||||
$normalizedLabels = array();
|
||||
|
||||
foreach ($labels as $labelDefinition) {
|
||||
$normalizedLabels[$labelDefinition['lang']] = $labelDefinition['label'];
|
||||
}
|
||||
|
||||
return $normalizedLabels;
|
||||
}
|
||||
|
||||
}
|
207
Controller/AbstractElementController.php
Normal file
207
Controller/AbstractElementController.php
Normal file
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
|
||||
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
abstract class AbstractElementController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $chillMainLogger;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
TranslatorInterface $translator,
|
||||
LoggerInterface $chillMainLogger
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->translator = $translator;
|
||||
$this->chillMainLogger = $chillMainLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AbstractElement the newly created element
|
||||
*/
|
||||
abstract protected function createNewElement();
|
||||
|
||||
abstract protected function getType();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function _new(Person $person, Request $request, $template, $flashMessageOnSuccess)
|
||||
{
|
||||
/* @var $element \Chill\AMLI\BudgetBundle\Entity\AbstractElement */
|
||||
$element = $this->createNewElement()
|
||||
->setPerson($person)
|
||||
;
|
||||
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::CREATE, $element);
|
||||
|
||||
$form = $this->createForm($this->getType(), $element);
|
||||
$form->add('submit', SubmitType::class);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() and $form->isValid()) {
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->persist($element);
|
||||
$em->flush();
|
||||
|
||||
$this->addFlash('success', $this->translator->trans($flashMessageOnSuccess));
|
||||
|
||||
return $this->redirectToRoute('chill_budget_elements_index', [
|
||||
'id' => $person->getId()
|
||||
]);
|
||||
} elseif ($form->isSubmitted()) {
|
||||
$this->addFlash('error', $this->translator->trans('This form contains errors'));
|
||||
}
|
||||
|
||||
return $this->render($template, array(
|
||||
'form' => $form->createView(),
|
||||
'person' => $person,
|
||||
'element' => $element
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param AbstractElement $element
|
||||
* @param Request $request
|
||||
* @param string $template
|
||||
* @param string $flashOnSuccess
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
protected function _edit(AbstractElement $element, Request $request, $template, $flashOnSuccess)
|
||||
{
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::UPDATE, $element);
|
||||
|
||||
$form = $this->createForm($this->getType(), $element);
|
||||
$form->add('submit', SubmitType::class);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() and $form->isValid()) {
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->flush();
|
||||
|
||||
$this->addFlash('success', $this->translator->trans($flashOnSuccess));
|
||||
|
||||
return $this->redirectToRoute('chill_budget_elements_index', [
|
||||
'id' => $element->getPerson()->getId()
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render($template, array(
|
||||
'element' => $element,
|
||||
'form' => $form->createView(),
|
||||
'person' => $element->getPerson()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Route(
|
||||
* "{_locale}/family-members/family-members/{id}/delete",
|
||||
* name="chill_family_members_family_members_delete"
|
||||
* )
|
||||
*
|
||||
* @param AbstractElement $element
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\BrowserKit\Response
|
||||
*/
|
||||
protected function _delete(AbstractElement $element, Request $request, $template, $flashMessage)
|
||||
{
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::DELETE, $element, 'You are not '
|
||||
. 'allowed to delete this family membership');
|
||||
|
||||
$form = $this->createDeleteForm();
|
||||
|
||||
if ($request->getMethod() === Request::METHOD_DELETE) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$this->chillMainLogger->notice("A budget element has been removed", array(
|
||||
'family_element' => get_class($element),
|
||||
'by_user' => $this->getUser()->getUsername(),
|
||||
'family_member_id' => $element->getId(),
|
||||
'amount' => $element->getAmount(),
|
||||
'type' => $element->getType()
|
||||
));
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($element);
|
||||
$em->flush();
|
||||
|
||||
$this->addFlash('success', $this->translator
|
||||
->trans($flashMessage));
|
||||
|
||||
return $this->redirectToRoute('chill_budget_elements_index', array(
|
||||
'id' => $element->getPerson()->getId()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $this->render($template, array(
|
||||
'element' => $element,
|
||||
'delete_form' => $form->createView()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Route(
|
||||
* "{_locale}/family-members/family-members/{id}/view",
|
||||
* name="chill_family_members_family_members_view"
|
||||
* )
|
||||
*/
|
||||
protected function _view(AbstractElement $element, $template)
|
||||
{
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::SHOW, $element);
|
||||
|
||||
return $this->render($template, array(
|
||||
'element' => $element
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form to delete a help request entity by id.
|
||||
*
|
||||
* @param mixed $id The entity id
|
||||
*
|
||||
* @return \Symfony\Component\Form\Form The form
|
||||
*/
|
||||
private function createDeleteForm()
|
||||
{
|
||||
return $this->createFormBuilder()
|
||||
->setMethod(Request::METHOD_DELETE)
|
||||
->add('submit', SubmitType::class, array('label' => 'Delete'))
|
||||
->getForm()
|
||||
;
|
||||
}
|
||||
|
||||
}
|
102
Controller/ChargeController.php
Normal file
102
Controller/ChargeController.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Chill\AMLI\BudgetBundle\Controller\AbstractElementController;
|
||||
use Chill\AMLI\BudgetBundle\Entity\Charge;
|
||||
use Chill\AMLI\BudgetBundle\Form\ChargeType;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class ChargeController extends AbstractElementController
|
||||
{
|
||||
protected function getType()
|
||||
{
|
||||
return ChargeType::class;
|
||||
}
|
||||
|
||||
protected function createNewElement()
|
||||
{
|
||||
return new Charge();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Route(
|
||||
* "{_locale}/budget/charge/{id}/view",
|
||||
* name="chill_budget_charge_view"
|
||||
* )
|
||||
* @param Charge $charge
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function viewAction(Charge $charge)
|
||||
{
|
||||
return $this->_view($charge, '@ChillAMLIBudget/Charge/view.html.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "{_locale}/budget/charge/by-person/{id}/new",
|
||||
* name="chill_budget_charge_new"
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Person $person
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function newAction(Request $request, Person $person)
|
||||
{
|
||||
return $this->_new(
|
||||
$person,
|
||||
$request,
|
||||
'@ChillAMLIBudget/Charge/new.html.twig',
|
||||
'Charge created');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "{_locale}/budget/charge/{id}/edit",
|
||||
* name="chill_budget_charge_edit"
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Charge $charge
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function editAction(Request $request, Charge $charge)
|
||||
{
|
||||
return $this->_edit(
|
||||
$charge,
|
||||
$request,
|
||||
'@ChillAMLIBudget/Charge/edit.html.twig',
|
||||
'Charge updated');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Route(
|
||||
* "{_locale}/budget/charge/{id}/delete",
|
||||
* name="chill_budget_charge_delete"
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Charge $charge
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function deleteAction(Request $request, Charge $charge)
|
||||
{
|
||||
return $this->_delete(
|
||||
$charge,
|
||||
$request,
|
||||
'@ChillAMLIBudget/Charge/confirm_delete.html.twig',
|
||||
'Charge deleted');
|
||||
}
|
||||
}
|
96
Controller/ElementController.php
Normal file
96
Controller/ElementController.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Chill\AMLI\BudgetBundle\Entity\Charge;
|
||||
use Chill\AMLI\BudgetBundle\Entity\Resource;
|
||||
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
||||
use Chill\AMLI\BudgetBundle\Calculator\CalculatorManager;
|
||||
|
||||
class ElementController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $chillMainLogger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var CalculatorManager
|
||||
*/
|
||||
protected $calculator;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
TranslatorInterface $translator,
|
||||
LoggerInterface $chillMainLogger,
|
||||
CalculatorManager $calculator
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->translator = $translator;
|
||||
$this->chillMainLogger = $chillMainLogger;
|
||||
$this->calculator = $calculator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "{_locale}/budget/elements/by-person/{id}",
|
||||
* name="chill_budget_elements_index"
|
||||
* )
|
||||
*/
|
||||
public function indexAction(Person $person)
|
||||
{
|
||||
$this->denyAccessUnlessGranted(BudgetElementVoter::SHOW, $person);
|
||||
|
||||
$charges = $this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByPerson($person);
|
||||
$ressources = $this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByPerson($person);
|
||||
|
||||
$now = new \DateTime('now');
|
||||
|
||||
$actualCharges = $this->em
|
||||
->getRepository(Charge::class)
|
||||
->findByPersonAndDate($person, $now);
|
||||
$actualResources = $this->em
|
||||
->getRepository(Resource::class)
|
||||
->findByPersonAndDate($person, $now);
|
||||
|
||||
$elements = \array_merge($actualCharges, $actualResources);
|
||||
|
||||
if (count($elements) > 0) {
|
||||
$results = $this->calculator->calculateDefault($elements);
|
||||
}
|
||||
|
||||
return $this->render('ChillAMLIBudgetBundle:Element:index.html.twig', array(
|
||||
'person' => $person,
|
||||
'charges' => $charges,
|
||||
'resources' => $ressources,
|
||||
'results' => $results ?? []
|
||||
));
|
||||
}
|
||||
|
||||
}
|
103
Controller/ResourceController.php
Normal file
103
Controller/ResourceController.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Chill\AMLI\BudgetBundle\Controller\AbstractElementController;
|
||||
use Chill\AMLI\BudgetBundle\Entity\Resource;
|
||||
use Chill\AMLI\BudgetBundle\Form\ResourceType;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class ResourceController extends AbstractElementController
|
||||
{
|
||||
|
||||
protected function getType()
|
||||
{
|
||||
return ResourceType::class;
|
||||
}
|
||||
|
||||
protected function createNewElement()
|
||||
{
|
||||
return new Resource();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Route(
|
||||
* "{_locale}/budget/resource/{id}/view",
|
||||
* name="chill_budget_resource_view"
|
||||
* )
|
||||
* @param Request $request
|
||||
* @param Resource $resource
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function viewAction(Resource $resource)
|
||||
{
|
||||
return $this->_view($resource, '@ChillAMLIBudget/Resource/view.html.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "{_locale}/budget/resource/by-person/{id}/new",
|
||||
* name="chill_budget_resource_new"
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Person $person
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function newAction(Request $request, Person $person)
|
||||
{
|
||||
return $this->_new(
|
||||
$person,
|
||||
$request,
|
||||
'@ChillAMLIBudget/Resource/new.html.twig',
|
||||
'Resource created');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "{_locale}/budget/resource/{id}/edit",
|
||||
* name="chill_budget_resource_edit"
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Resource $resource
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function editAction(Request $request, Resource $resource)
|
||||
{
|
||||
return $this->_edit(
|
||||
$resource,
|
||||
$request,
|
||||
'@ChillAMLIBudget/Resource/edit.html.twig',
|
||||
'Resource updated');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Route(
|
||||
* "{_locale}/budget/resource/{id}/delete",
|
||||
* name="chill_budget_resource_delete"
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Resource $resource
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function deleteAction(Request $request, Resource $resource)
|
||||
{
|
||||
return $this->_delete($resource,
|
||||
$request,
|
||||
'@ChillAMLIBudget/Resource/confirm_delete.html.twig',
|
||||
'Resource deleted');
|
||||
}
|
||||
}
|
61
DependencyInjection/ChillAMLIBudgetExtension.php
Normal file
61
DependencyInjection/ChillAMLIBudgetExtension.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
||||
|
||||
/**
|
||||
* This is the class that loads and manages your bundle configuration.
|
||||
*
|
||||
* @link http://symfony.com/doc/current/cookbook/bundles/extension.html
|
||||
*/
|
||||
class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services/config.yml');
|
||||
$loader->load('services/form.yml');
|
||||
$loader->load('services/security.yml');
|
||||
$loader->load('services/controller.yml');
|
||||
$loader->load('services/templating.yml');
|
||||
$loader->load('services/menu.yml');
|
||||
$loader->load('services/calculator.yml');
|
||||
|
||||
$this->storeConfig('resources', $config, $container);
|
||||
$this->storeConfig('charges', $config, $container);
|
||||
}
|
||||
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
$this->prependAuthorization($container);
|
||||
}
|
||||
|
||||
protected function storeConfig($position, array $config, ContainerBuilder $container)
|
||||
{
|
||||
$container
|
||||
->setParameter(sprintf('chill_budget.%s', $position), $config[$position])
|
||||
;
|
||||
}
|
||||
|
||||
protected function prependAuthorization(ContainerBuilder $container)
|
||||
{
|
||||
$container->prependExtensionConfig('security', array(
|
||||
'role_hierarchy' => array(
|
||||
BudgetElementVoter::UPDATE => [ BudgetElementVoter::SHOW ],
|
||||
BudgetElementVoter::CREATE => [ BudgetElementVoter::SHOW ]
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
30
DependencyInjection/Compiler/CalculatorCompilerPass.php
Normal file
30
DependencyInjection/Compiler/CalculatorCompilerPass.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class CalculatorCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$manager = $container->getDefinition('Chill\AMLI\BudgetBundle\Calculator\CalculatorManager');
|
||||
|
||||
foreach ($container->findTaggedServiceIds('chill_budget.calculator') as $id => $tags) {
|
||||
foreach($tags as $tag) {
|
||||
$reference = new Reference($id);
|
||||
|
||||
$manager->addMethodCall('addCalculator', [ $reference, $tag['default'] ?? false ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
DependencyInjection/Configuration.php
Normal file
78
DependencyInjection/Configuration.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* This is the class that validates and merges configuration from your app/config files.
|
||||
*
|
||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder();
|
||||
$rootNode = $treeBuilder->root('chill_amli_budget');
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
|
||||
// ressources
|
||||
->arrayNode('resources')->isRequired()->requiresAtLeastOneElement()
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('key')->isRequired()->cannotBeEmpty()
|
||||
->info('the key stored in database')
|
||||
->example('salary')
|
||||
->end()
|
||||
->arrayNode('labels')->isRequired()->requiresAtLeastOneElement()
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('lang')->isRequired()->cannotBeEmpty()
|
||||
->example('fr')
|
||||
->end()
|
||||
->scalarNode('label')->isRequired()->cannotBeEmpty()
|
||||
->example('Salaire')
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
||||
->arrayNode('charges')->isRequired()->requiresAtLeastOneElement()
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('key')->isRequired()->cannotBeEmpty()
|
||||
->info('the key stored in database')
|
||||
->example('salary')
|
||||
->end()
|
||||
->arrayNode('labels')->isRequired()->requiresAtLeastOneElement()
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('lang')->isRequired()->cannotBeEmpty()
|
||||
->example('fr')
|
||||
->end()
|
||||
->scalarNode('label')->isRequired()->cannotBeEmpty()
|
||||
->example('Salaire')
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
||||
->end()
|
||||
;
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
}
|
225
Entity/AbstractElement.php
Normal file
225
Entity/AbstractElement.php
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* AbstractElement
|
||||
*
|
||||
* @ORM\MappedSuperclass()
|
||||
*/
|
||||
abstract class AbstractElement
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Person
|
||||
* @ORM\ManyToOne(
|
||||
* targetEntity="\Chill\PersonBundle\Entity\Person"
|
||||
* )
|
||||
*/
|
||||
private $person;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="type", type="string", length=255)
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @var decimal
|
||||
*
|
||||
* @ORM\Column(name="amount", type="decimal", precision=10, scale=2)
|
||||
* @Assert\GreaterThan(
|
||||
* value=0
|
||||
* )
|
||||
* @Assert\NotNull(
|
||||
* message="The amount cannot be empty"
|
||||
* )
|
||||
*
|
||||
*/
|
||||
private $amount;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(name="comment", type="text", nullable=true)
|
||||
*/
|
||||
private $comment;
|
||||
|
||||
/**
|
||||
* @var \DateTimeImmutable
|
||||
*
|
||||
* @ORM\Column(name="startDate", type="datetime_immutable")
|
||||
* @Assert\Date()
|
||||
*/
|
||||
private $startDate;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
abstract public function isCharge(): bool;
|
||||
|
||||
abstract public function isResource(): bool;
|
||||
|
||||
public function getPerson(): Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function setPerson(Person $person)
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return AbstractElement
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set amount.
|
||||
*
|
||||
* @param string $amount
|
||||
*
|
||||
* @return AbstractElement
|
||||
*/
|
||||
public function setAmount($amount)
|
||||
{
|
||||
$this->amount = $amount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get amount.
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
public function getAmount()
|
||||
{
|
||||
return (double) $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set comment.
|
||||
*
|
||||
* @param string|null $comment
|
||||
*
|
||||
* @return AbstractElement
|
||||
*/
|
||||
public function setComment($comment = null)
|
||||
{
|
||||
$this->comment = $comment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comment.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getComment()
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set startDate.
|
||||
*
|
||||
* @param \DateTimeInterface $startDate
|
||||
*
|
||||
* @return AbstractElement
|
||||
*/
|
||||
public function setStartDate(\DateTimeInterface $startDate)
|
||||
{
|
||||
if ($startDate instanceof \DateTime) {
|
||||
$this->startDate = \DateTimeImmutable::createFromMutable($startDate);
|
||||
} elseif (NULL === $startDate) {
|
||||
$this->startDate = null;
|
||||
} else {
|
||||
$this->startDate = $startDate;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get startDate.
|
||||
*
|
||||
* @return \DateTimeImmutable
|
||||
*/
|
||||
public function getStartDate()
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set endDate.
|
||||
*
|
||||
* @param \DateTimeInterface|null $endDate
|
||||
*
|
||||
* @return AbstractElement
|
||||
*/
|
||||
public function setEndDate(\DateTimeInterface $endDate = null)
|
||||
{
|
||||
if ($endDate instanceof \DateTime) {
|
||||
$this->endDate = \DateTimeImmutable::createFromMutable($endDate);
|
||||
} elseif (NULL === $endDate) {
|
||||
$this->endDate = null;
|
||||
} else {
|
||||
$this->endDate = $endDate;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get endDate.
|
||||
*
|
||||
* @return \DateTimeImmutable|null
|
||||
*/
|
||||
public function getEndDate()
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
return $this->amount == 0;
|
||||
}
|
||||
}
|
86
Entity/Charge.php
Normal file
86
Entity/Charge.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||
|
||||
/**
|
||||
* Charge
|
||||
*
|
||||
* @ORM\Table(name="chill_budget.charge")
|
||||
* @ORM\Entity(repositoryClass="Chill\AMLI\BudgetBundle\Repository\ChargeRepository")
|
||||
*/
|
||||
class Charge extends AbstractElement implements HasCenterInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
* @ORM\Column(name="help", type="string", nullable=true)
|
||||
*/
|
||||
private $help = self::HELP_NOT_RELEVANT;
|
||||
|
||||
const HELP_ASKED = 'running';
|
||||
const HELP_NO = 'no';
|
||||
const HELP_YES = 'yes';
|
||||
const HELP_NOT_RELEVANT = 'not-relevant';
|
||||
|
||||
const HELPS = [
|
||||
self::HELP_ASKED,
|
||||
self::HELP_NO,
|
||||
self::HELP_YES,
|
||||
self::HELP_NOT_RELEVANT
|
||||
];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setStartDate(new \DateTimeImmutable('today'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->help;
|
||||
}
|
||||
|
||||
public function setHelp($help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCenter(): \Chill\MainBundle\Entity\Center
|
||||
{
|
||||
return $this->getPerson()->getCenter();
|
||||
}
|
||||
|
||||
public function isCharge(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isResource(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
55
Entity/Resource.php
Normal file
55
Entity/Resource.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||
|
||||
/**
|
||||
* Resource
|
||||
*
|
||||
* @ORM\Table(name="chill_budget.resource")
|
||||
* @ORM\Entity(repositoryClass="Chill\AMLI\BudgetBundle\Repository\ResourceRepository")
|
||||
*/
|
||||
class Resource extends AbstractElement implements HasCenterInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setStartDate(new \DateTimeImmutable('today'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCenter(): \Chill\MainBundle\Entity\Center
|
||||
{
|
||||
return $this->getPerson()->getCenter();
|
||||
}
|
||||
|
||||
public function isCharge(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isResource(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
124
Form/ChargeType.php
Normal file
124
Form/ChargeType.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Chill\AMLI\BudgetBundle\Entity\Charge;
|
||||
|
||||
class ChargeType extends AbstractType
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var ConfigRepository
|
||||
*/
|
||||
protected $configRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatableStringHelper
|
||||
*/
|
||||
protected $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
ConfigRepository $configRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->configRepository = $configRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('type', ChoiceType::class, [
|
||||
'choices' => $this->getTypes(),
|
||||
'placeholder' => 'Choose a charge type'
|
||||
])
|
||||
->add('amount', MoneyType::class)
|
||||
->add('comment', TextAreaType::class, [
|
||||
'required' => false
|
||||
])
|
||||
;
|
||||
|
||||
if ($options['show_start_date']) {
|
||||
$builder->add('startDate', ChillDateType::class, [
|
||||
'label' => 'Start of validity period'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['show_end_date']) {
|
||||
$builder->add('endDate', ChillDateType::class, [
|
||||
'required' => false,
|
||||
'label' => 'End of validity period'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['show_help']) {
|
||||
$builder->add('help', ChoiceType::class, [
|
||||
'choices' => [
|
||||
'charge.help.running' => Charge::HELP_ASKED,
|
||||
'charge.help.no' => Charge::HELP_NO,
|
||||
'charge.help.yes' => Charge::HELP_YES,
|
||||
'charge.help.not-concerned' => Charge::HELP_NOT_RELEVANT
|
||||
],
|
||||
'placeholder' => 'Choose a status',
|
||||
'required' => false,
|
||||
'label' => 'Help to pay charges'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getTypes()
|
||||
{
|
||||
$charges = $this->configRepository
|
||||
->getChargesLabels();
|
||||
|
||||
// rewrite labels to filter in language
|
||||
foreach ($charges as $key => $labels) {
|
||||
$charges[$key] = $this->translatableStringHelper->localize($labels);
|
||||
}
|
||||
|
||||
\asort($charges);
|
||||
|
||||
return \array_flip($charges);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults(array(
|
||||
'data_class' => 'Chill\AMLI\BudgetBundle\Entity\Charge',
|
||||
'show_start_date' => true,
|
||||
'show_end_date' => true,
|
||||
'show_help' => true
|
||||
));
|
||||
|
||||
$resolver
|
||||
->setAllowedTypes('show_start_date', 'boolean')
|
||||
->setAllowedTypes('show_end_date', 'boolean')
|
||||
->setAllowedTypes('show_help', 'boolean')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'chill_amli_budgetbundle_charge';
|
||||
}
|
||||
|
||||
|
||||
}
|
108
Form/ResourceType.php
Normal file
108
Form/ResourceType.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Chill\AMLI\BudgetBundle\Entity\Resource;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
|
||||
class ResourceType extends AbstractType
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var ConfigRepository
|
||||
*/
|
||||
protected $configRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatableStringHelper
|
||||
*/
|
||||
protected $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
ConfigRepository $configRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->configRepository = $configRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('type', ChoiceType::class, [
|
||||
'choices' => $this->getTypes(),
|
||||
'placeholder' => 'Choose a resource type',
|
||||
'label' => 'Resource element type'
|
||||
])
|
||||
->add('amount', MoneyType::class)
|
||||
->add('comment', TextAreaType::class, [
|
||||
'required' => false
|
||||
])
|
||||
;
|
||||
|
||||
if ($options['show_start_date']) {
|
||||
$builder->add('startDate', ChillDateType::class, [
|
||||
'label' => 'Start of validity period'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['show_end_date']) {
|
||||
$builder->add('endDate', ChillDateType::class, [
|
||||
'required' => false,
|
||||
'label' => 'End of validity period'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getTypes()
|
||||
{
|
||||
$resources = $this->configRepository
|
||||
->getResourcesLabels();
|
||||
|
||||
// rewrite labels to filter in language
|
||||
foreach ($resources as $key => $labels) {
|
||||
$resources[$key] = $this->translatableStringHelper->localize($labels);
|
||||
}
|
||||
|
||||
asort($resources);
|
||||
|
||||
return \array_flip($resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults(array(
|
||||
'data_class' => Resource::class,
|
||||
'show_start_date' => true,
|
||||
'show_end_date' => true
|
||||
));
|
||||
|
||||
$resolver
|
||||
->setAllowedTypes('show_start_date', 'boolean')
|
||||
->setAllowedTypes('show_end_date', 'boolean')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'chill_amli_budgetbundle_resource';
|
||||
}
|
||||
|
||||
|
||||
}
|
60
Menu/UserMenuBuilder.php
Normal file
60
Menu/UserMenuBuilder.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Menu;
|
||||
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class UserMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var AuthorizationCheckerInterface
|
||||
*/
|
||||
protected $authorizationChecker;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
public function __construct(
|
||||
AuthorizationCheckerInterface $authorizationChecker,
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->authorizationChecker = $authorizationChecker;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
{
|
||||
/* @var $person \Chill\PersonBundle\Entity\Person */
|
||||
$person = $parameters['person'];
|
||||
|
||||
if ($this->authorizationChecker->isGranted(BudgetElementVoter::SHOW, $person)) {
|
||||
$menu->addChild(
|
||||
$this->translator->trans('Budget'), [
|
||||
'route' => 'chill_budget_elements_index',
|
||||
'routeParameters' => [ 'id' => $person->getId() ],
|
||||
])
|
||||
->setExtra('order', 460)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getMenuIds(): array
|
||||
{
|
||||
return [ 'person' ];
|
||||
}
|
||||
}
|
5
README.md
Normal file
5
README.md
Normal file
@ -0,0 +1,5 @@
|
||||
Budget Bundle
|
||||
=============
|
||||
|
||||
Add the possibility to register budget element (charges and resources) for people.
|
||||
|
35
Repository/ChargeRepository.php
Normal file
35
Repository/ChargeRepository.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Repository;
|
||||
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
/**
|
||||
* ChargeRepository
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class ChargeRepository extends \Doctrine\ORM\EntityRepository
|
||||
{
|
||||
public function findByPersonAndDate(Person $person, \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')
|
||||
;
|
||||
|
||||
if ($sort !== null) {
|
||||
$qb->orderBy($sort);
|
||||
}
|
||||
|
||||
$qb->setParameters([
|
||||
'person' => $person,
|
||||
'date' => $date
|
||||
]);
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
}
|
35
Repository/ResourceRepository.php
Normal file
35
Repository/ResourceRepository.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Repository;
|
||||
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
/**
|
||||
* ResourceRepository
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class ResourceRepository extends \Doctrine\ORM\EntityRepository
|
||||
{
|
||||
public function findByPersonAndDate(Person $person, \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')
|
||||
;
|
||||
|
||||
if ($sort !== null) {
|
||||
$qb->orderBy($sort);
|
||||
}
|
||||
|
||||
$qb->setParameters([
|
||||
'person' => $person,
|
||||
'date' => $date
|
||||
]);
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
}
|
3
Resources/config/routing.yml
Normal file
3
Resources/config/routing.yml
Normal file
@ -0,0 +1,3 @@
|
||||
chill_amli_budget_controllers:
|
||||
resource: "@ChillAMLIBudgetBundle/Controller"
|
||||
type: annotation
|
2
Resources/config/services/calculator.yml
Normal file
2
Resources/config/services/calculator.yml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Calculator\CalculatorManager: ~
|
5
Resources/config/services/config.yml
Normal file
5
Resources/config/services/config.yml
Normal file
@ -0,0 +1,5 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Config\ConfigRepository:
|
||||
arguments:
|
||||
$resources: '%chill_budget.resources%'
|
||||
$charges: '%chill_budget.charges%'
|
5
Resources/config/services/controller.yml
Normal file
5
Resources/config/services/controller.yml
Normal file
@ -0,0 +1,5 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Controller\:
|
||||
autowire: true
|
||||
resource: '../../../Controller'
|
||||
tags: ['controller.service_arguments']
|
14
Resources/config/services/form.yml
Normal file
14
Resources/config/services/form.yml
Normal file
@ -0,0 +1,14 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Form\ResourceType:
|
||||
arguments:
|
||||
$configRepository: '@Chill\AMLI\BudgetBundle\Config\ConfigRepository'
|
||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||
tags:
|
||||
- { name: 'form.type' }
|
||||
|
||||
Chill\AMLI\BudgetBundle\Form\ChargeType:
|
||||
arguments:
|
||||
$configRepository: '@Chill\AMLI\BudgetBundle\Config\ConfigRepository'
|
||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||
tags:
|
||||
- { name: 'form.type' }
|
7
Resources/config/services/menu.yml
Normal file
7
Resources/config/services/menu.yml
Normal file
@ -0,0 +1,7 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Menu\UserMenuBuilder:
|
||||
arguments:
|
||||
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
|
||||
$translator: '@Symfony\Component\Translation\TranslatorInterface'
|
||||
tags:
|
||||
- { name: 'chill.menu_builder' }
|
7
Resources/config/services/security.yml
Normal file
7
Resources/config/services/security.yml
Normal file
@ -0,0 +1,7 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Security\Authorization\BudgetElementVoter:
|
||||
arguments:
|
||||
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
|
||||
tags:
|
||||
- { name: chill.role }
|
||||
- { name: security.voter }
|
7
Resources/config/services/templating.yml
Normal file
7
Resources/config/services/templating.yml
Normal file
@ -0,0 +1,7 @@
|
||||
services:
|
||||
Chill\AMLI\BudgetBundle\Templating\Twig:
|
||||
arguments:
|
||||
$configRepository: '@Chill\AMLI\BudgetBundle\Config\ConfigRepository'
|
||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||
tags:
|
||||
- { name: 'twig.extension' }
|
41
Resources/migrations/Version20180522080432.php
Normal file
41
Resources/migrations/Version20180522080432.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
/**
|
||||
* create schema for chill budget
|
||||
*/
|
||||
final class Version20180522080432 extends AbstractMigration
|
||||
{
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||
|
||||
$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))');
|
||||
$this->addSql('CREATE INDEX IDX_5E0A5E97217BBB47 ON chill_budget.resource (person_id)');
|
||||
$this->addSql('COMMENT ON COLUMN chill_budget.resource.startDate IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_budget.resource.endDate IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('CREATE TABLE chill_budget.charge (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, help VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_5C99D2C3217BBB47 ON chill_budget.charge (person_id)');
|
||||
$this->addSql('COMMENT ON COLUMN chill_budget.charge.startDate IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_budget.charge.endDate IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE chill_budget.resource ADD CONSTRAINT FK_5E0A5E97217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_budget.charge ADD CONSTRAINT FK_5C99D2C3217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
|
||||
}
|
||||
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||
|
||||
$this->addSql('CREATE SCHEMA chill_budget CASCADE');
|
||||
|
||||
}
|
||||
}
|
26
Resources/migrations/Version20181219145631.php
Normal file
26
Resources/migrations/Version20181219145631.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* autorise les valeurs nulles dans "HELP"
|
||||
*/
|
||||
final class Version20181219145631 extends AbstractMigration
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
60
Resources/translations/messages.fr.yml
Normal file
60
Resources/translations/messages.fr.yml
Normal file
@ -0,0 +1,60 @@
|
||||
Budget: Budget
|
||||
Budget for %name%: Budget de %name%
|
||||
Resource element type: Nature de la ressource
|
||||
Actual budget: Budget actuel
|
||||
Actual resources: Ressources actuelles
|
||||
Actual charges: Charges actuelles
|
||||
Past budget: Éléments du budget passé
|
||||
Past resources: Ressources passées
|
||||
Past charges: Chargées passées
|
||||
Future budget: Futurs éléments du budget
|
||||
Future resources: Ressources futures
|
||||
Future charges: Charges futures
|
||||
Budget element type: Nature
|
||||
Validity period: Période de validité
|
||||
Start of validity period: Début de la période de validité
|
||||
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
|
||||
|
||||
There isn't any element recorded: Aucun élément enregistré
|
||||
No resources registered: Aucune ressource enregistrée
|
||||
No charges registered: Aucune charge enregistrée
|
||||
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
|
||||
|
||||
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%
|
||||
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% ?
|
||||
Are you sure you want to remove the charge "%type%" associated to "%name%" ?: Êtes-vous sûr·e de vouloir supprimer la charge de nature "%type%" associée à %name% ?
|
||||
Resource deleted: Ressource supprimée
|
||||
Charge deleted: Charge supprimée
|
||||
Charge created: Charge créée
|
||||
Resource created: Ressource créée
|
||||
Resource updated: Resource mise à jour
|
||||
Charge updated: charge mise à jour
|
||||
|
||||
Choose a resource type: Choisissez un type de ressource
|
||||
Choose a charge type: Choisissez un type de charge
|
||||
Amount: Montant
|
||||
Comment: Commentaire
|
||||
|
||||
Help to pay charges: Aide au payement des dépenses d'énergie
|
||||
Choose a status: Choisissez un état
|
||||
charge.help.running: En cours
|
||||
charge.help.no: Non demandé
|
||||
charge.help.yes: Oui
|
||||
charge.help.not-concerned: Non concerné
|
||||
|
||||
Budget calculator: Calculs et indices sur le budget
|
||||
Budget calculator result: Résultats
|
||||
|
||||
'Valid since %startDate% until %endDate%': Valide depuis le %startDate% jusqu'au %endDate%
|
||||
'Valid since %startDate%': Valide depuis le %startDate%
|
2
Resources/translations/validators.fr.yml
Normal file
2
Resources/translations/validators.fr.yml
Normal file
@ -0,0 +1,2 @@
|
||||
The amount cannot be empty: Le montant ne peut pas être vide ou égal à zéro
|
||||
The budget element's end date must be after the start date: La date de fin doit être après la date de début
|
19
Resources/views/Charge/confirm_delete.html.twig
Normal file
19
Resources/views/Charge/confirm_delete.html.twig
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends "ChillPersonBundle::layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set person = element.person %}
|
||||
|
||||
{% block title 'Remove resource'|trans %}
|
||||
|
||||
{% block personcontent %}
|
||||
|
||||
{{ 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 },
|
||||
'form' : delete_form
|
||||
} ) }}
|
||||
|
||||
{% endblock %}
|
31
Resources/views/Charge/edit.html.twig
Normal file
31
Resources/views/Charge/edit.html.twig
Normal file
@ -0,0 +1,31 @@
|
||||
{% extends "@ChillPerson/layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set title = 'Edit Charge for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
|
||||
{% block title title %}
|
||||
|
||||
{% block personcontent %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.type) }}
|
||||
{{ form_row(form.amount) }}
|
||||
{{ form_row(form.help) }}
|
||||
{{ form_row(form.comment) }}
|
||||
{{ form_row(form.startDate) }}
|
||||
{{ form_row(form.endDate) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="sc-button bt-cancel">
|
||||
{{ 'Back to the list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ form_widget(form.submit, { 'attr' : { 'class': 'sc-button bt-create' }, 'label': 'Edit' } ) }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
31
Resources/views/Charge/new.html.twig
Normal file
31
Resources/views/Charge/new.html.twig
Normal file
@ -0,0 +1,31 @@
|
||||
{% extends "@ChillPerson/layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set title = 'New Charge for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
|
||||
{% block title title %}
|
||||
|
||||
{% block personcontent %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.type) }}
|
||||
{{ form_row(form.amount) }}
|
||||
{{ form_row(form.help) }}
|
||||
{{ form_row(form.comment) }}
|
||||
{{ form_row(form.startDate) }}
|
||||
{{ form_row(form.endDate) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="sc-button bt-cancel">
|
||||
{{ 'Back to the list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ form_widget(form.submit, { 'attr' : { 'class': 'sc-button bt-create' }, 'label': 'Create' } ) }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
52
Resources/views/Charge/view.html.twig
Normal file
52
Resources/views/Charge/view.html.twig
Normal file
@ -0,0 +1,52 @@
|
||||
{% extends "@ChillPerson/layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set person = element.person %}
|
||||
{% set title = 'Charge for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
|
||||
|
||||
{% 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>
|
||||
|
||||
<dt>{{ 'Amount'|trans }}</dt>
|
||||
<dd>{{ element.amount|localizedcurrency('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') } ) }}
|
||||
{% else %}
|
||||
{{ 'Valid since %startDate%'|trans( { '%startDate%': element.startDate|localizeddate('long', 'none') } ) }}
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>{{ 'Comment'|trans }}</dt>
|
||||
<dd>
|
||||
{%- if element.comment is not empty -%}
|
||||
<blockquote class="chill-user-quote">
|
||||
{{ element.comment }}
|
||||
</blockquote>
|
||||
{%- else -%}
|
||||
<span class="chill-no-data-statement">{{ 'Not given'|trans }}</span>
|
||||
{%- endif -%}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="sc-button bt-cancel">
|
||||
{{ 'Back to the list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::UPDATE'), element) %}
|
||||
<li>
|
||||
<a href="{{ path('chill_budget_charge_edit', { 'id': element.id } ) }}" class="sc-button bt-edit">{{ 'Edit'|trans }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
228
Resources/views/Element/index.html.twig
Normal file
228
Resources/views/Element/index.html.twig
Normal file
@ -0,0 +1,228 @@
|
||||
{% extends "@ChillPerson/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> </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|localizedcurrency('EUR') }}</td>
|
||||
<td>
|
||||
{% if f.endDate is not null %}
|
||||
{{ 'Valid since %startDate% until %endDate%'|trans( { '%startDate%': f.startDate|localizeddate('long', 'none'), '%endDate%': f.endDate|localizeddate('long', 'none') } ) }}
|
||||
{% else %}
|
||||
{{ 'Valid since %startDate%'|trans( { '%startDate%': f.startDate|localizeddate('long', 'none') } ) }}
|
||||
{% 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="sc-button bt-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="sc-button bt-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="sc-button bt-delete"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ 'Total'|trans }}
|
||||
</td>
|
||||
<td>
|
||||
{{ total|localizedcurrency('EUR') }}
|
||||
</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro table_results(results) %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </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|localizedcurrency('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="sc-button bt-create" href="{{ path('chill_budget_resource_new', { 'id': person.id} ) }}">{{ 'Create new resource'|trans }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="sc-button bt-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="sc-button bt-create" href="{{ path('chill_budget_resource_new', { 'id': person.id} ) }}">{{ 'Create new resource'|trans }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="sc-button bt-create" href="{{ path('chill_budget_charge_new', { 'id': person.id} ) }}">{{ 'Create new charge'|trans }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
19
Resources/views/Resource/confirm_delete.html.twig
Normal file
19
Resources/views/Resource/confirm_delete.html.twig
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends "ChillPersonBundle::layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set person = element.person %}
|
||||
|
||||
{% block title 'Remove resource'|trans %}
|
||||
|
||||
{% block personcontent %}
|
||||
|
||||
{{ 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 },
|
||||
'form' : delete_form
|
||||
} ) }}
|
||||
|
||||
{% endblock %}
|
30
Resources/views/Resource/edit.html.twig
Normal file
30
Resources/views/Resource/edit.html.twig
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends "@ChillPerson/layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set title = 'Edit Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
|
||||
{% block title title %}
|
||||
|
||||
{% block personcontent %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.type) }}
|
||||
{{ form_row(form.amount) }}
|
||||
{{ form_row(form.comment) }}
|
||||
{{ form_row(form.startDate) }}
|
||||
{{ form_row(form.endDate) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="sc-button bt-cancel">
|
||||
{{ 'Back to the list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ form_widget(form.submit, { 'attr' : { 'class': 'sc-button bt-create' }, 'label': 'Edit' } ) }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
30
Resources/views/Resource/new.html.twig
Normal file
30
Resources/views/Resource/new.html.twig
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends "@ChillPerson/layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set title = 'New Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
|
||||
{% block title title %}
|
||||
|
||||
{% block personcontent %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.type) }}
|
||||
{{ form_row(form.amount) }}
|
||||
{{ form_row(form.comment) }}
|
||||
{{ form_row(form.startDate) }}
|
||||
{{ form_row(form.endDate) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="sc-button bt-cancel">
|
||||
{{ 'Back to the list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ form_widget(form.submit, { 'attr' : { 'class': 'sc-button bt-create' }, 'label': 'Create' } ) }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
52
Resources/views/Resource/view.html.twig
Normal file
52
Resources/views/Resource/view.html.twig
Normal file
@ -0,0 +1,52 @@
|
||||
{% extends "@ChillPerson/layout.html.twig" %}
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
{% set person = element.person %}
|
||||
{% set title = 'Resource for %name%'|trans({ '%name%' : person.firstName ~ " " ~ person.lastName } ) %}
|
||||
|
||||
{% block title title %}
|
||||
|
||||
{% block personcontent %}
|
||||
<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>
|
||||
<dd>{{ element.amount|localizedcurrency('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') } ) }}
|
||||
{% else %}
|
||||
{{ 'Valid since %startDate%'|trans( { '%startDate%': element.startDate|localizeddate('long', 'none') } ) }}
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>{{ 'Comment'|trans }}</dt>
|
||||
<dd>
|
||||
{%- if element.comment is not empty -%}
|
||||
<blockquote class="chill-user-quote">
|
||||
{{ element.comment }}
|
||||
</blockquote>
|
||||
{%- else -%}
|
||||
<span class="chill-no-data-statement">{{ 'Not given'|trans }}</span>
|
||||
{%- endif -%}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ path("chill_budget_elements_index", { 'id': person.id } ) }}" class="sc-button bt-cancel">
|
||||
{{ 'Back to the list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
{% if is_granted(constant('Chill\\AMLI\\BudgetBundle\\Security\\Authorization\\BudgetElementVoter::UPDATE'), element) %}
|
||||
<li>
|
||||
<a href="{{ path('chill_budget_resource_edit', { 'id': element.id } ) }}" class="sc-button bt-edit">{{ 'Edit'|trans }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
79
Security/Authorization/BudgetElementVoter.php
Normal file
79
Security/Authorization/BudgetElementVoter.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Security\Authorization;
|
||||
|
||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||
use Chill\AMLI\BudgetBundle\Entity\AbstractElement;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class BudgetElementVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||
{
|
||||
const CREATE = 'CHILL_BUDGET_ELEMENT_CREATE';
|
||||
const DELETE = 'CHILL_BUDGET_ELEMENT_DELETE';
|
||||
const UPDATE = 'CHILL_BUDGET_ELEMENT_UPDATE';
|
||||
const SHOW = 'CHILL_BUDGET_ELEMENT_SHOW';
|
||||
|
||||
const ROLES = [
|
||||
self::CREATE,
|
||||
self::DELETE,
|
||||
self::SHOW,
|
||||
self::UPDATE
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
protected $authorizationHelper;
|
||||
|
||||
public function __construct(AuthorizationHelper $authorizationHelper)
|
||||
{
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
}
|
||||
|
||||
|
||||
protected function supports($attribute, $subject)
|
||||
{
|
||||
return (\in_array($attribute, self::ROLES) && $subject instanceof AbstractElement)
|
||||
or
|
||||
($subject instanceof Person && \in_array($attribute, [ self::SHOW, self::CREATE ]));
|
||||
}
|
||||
|
||||
protected function voteOnAttribute($attribute, $subject, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token)
|
||||
{
|
||||
$user = $token->getUser();
|
||||
|
||||
if (FALSE === $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->authorizationHelper
|
||||
->userHasAccess($user, $subject, new Role($attribute));
|
||||
}
|
||||
|
||||
public function getRoles()
|
||||
{
|
||||
return self::ROLES;
|
||||
}
|
||||
|
||||
public function getRolesWithHierarchy(): array
|
||||
{
|
||||
return [ 'Budget elements' => self::ROLES ];
|
||||
}
|
||||
|
||||
public function getRolesWithoutScope()
|
||||
{
|
||||
return self::ROLES;
|
||||
}
|
||||
|
||||
}
|
64
Templating/Twig.php
Normal file
64
Templating/Twig.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
*/
|
||||
namespace Chill\AMLI\BudgetBundle\Templating;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class Twig extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var ConfigRepository
|
||||
*/
|
||||
protected $configRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatableStringHelper
|
||||
*/
|
||||
protected $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
ConfigRepository $configRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->configRepository = $configRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new \Twig_Filter('budget_element_type_display', [ $this, 'displayLink' ], [ 'is_safe' => [ 'html' ]])
|
||||
];
|
||||
}
|
||||
|
||||
public function displayLink($link, $family)
|
||||
{
|
||||
switch($family) {
|
||||
case 'resource':
|
||||
return $this->translatableStringHelper->localize(
|
||||
$this->configRepository->getResourcesLabels()[$link]
|
||||
);
|
||||
case 'charge':
|
||||
return $this->translatableStringHelper->localize(
|
||||
$this->configRepository->getChargesLabels()[$link]
|
||||
);
|
||||
default:
|
||||
throw new \UnexpectedValueException("This family of element: $family is not "
|
||||
. "supported. Supported families are 'resource', 'charge'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
23
Tests/Controller/ElementControllerTest.php
Normal file
23
Tests/Controller/ElementControllerTest.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AMLI\BudgetBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class ElementControllerTest extends WebTestCase
|
||||
{
|
||||
public function testList()
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$crawler = $client->request('GET', '/list');
|
||||
}
|
||||
|
||||
public function testIndex()
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$crawler = $client->request('GET', '/index');
|
||||
}
|
||||
|
||||
}
|
32
composer.json
Normal file
32
composer.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "chill-project/budget",
|
||||
"description": "This bundle extend chill for recording element of a budget for peoples",
|
||||
"type": "symfony-bundle",
|
||||
"license": "AGPL-3.0",
|
||||
"keywords" : ["chill", "social work"],
|
||||
"homepage" : "https://framagit.org/Chill-project/BudgetBundle",
|
||||
"autoload": {
|
||||
"psr-4": { "Chill\\AMLI\BudgetBundle\\": "" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Champs-Libres",
|
||||
"email": "info@champs-libres.coop"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"chill-project/person": "~1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6"
|
||||
},
|
||||
"extra": {
|
||||
"app-migrations-dir": "Resources/test/Fixtures/App/app/DoctrineMigrations",
|
||||
"symfony-app-dir": "Test/Fixtures/App/app/"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user