From 732f2dab5182f6d5cb750c9fa64b70830f5136e7 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Mon, 10 Apr 2023 16:47:59 +0200 Subject: [PATCH] add status update with mail --- config/packages/security.yaml | 1 + src/Controller/BillAdminController.php | 29 ++++- src/EventSubscriber/BillEventSubscriber.php | 126 +++++++++++++++++++ src/Form/BillFilterType.php | 13 +- src/Form/BillType.php | 1 + src/Form/DateRangeType.php | 49 ++++++++ src/Repository/BillRepositoryQuery.php | 18 ++- templates/admin/bill/_show.html.twig | 5 +- templates/admin/bill/edit.html.twig | 15 +++ templates/admin/bill/index.html.twig | 7 ++ templates/admin/menu.html.twig | 2 +- templates/mail/bill/status_updated.html.twig | 17 +++ 12 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 src/EventSubscriber/BillEventSubscriber.php create mode 100644 src/Form/DateRangeType.php create mode 100644 templates/admin/bill/edit.html.twig create mode 100644 templates/admin/bill/index.html.twig create mode 100644 templates/mail/bill/status_updated.html.twig diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 1131f5d..cf35f70 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -47,6 +47,7 @@ security: - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/resetting, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS } + - { path: ^/admin/bill, roles: [ROLE_MANAGER, ROLE_TREASURER] } - { path: ^/admin/user, roles: ROLE_ADMIN } - { path: ^/admin/task, roles: ROLE_ADMIN } - { path: ^/admin/setting, roles: ROLE_ADMIN } diff --git a/src/Controller/BillAdminController.php b/src/Controller/BillAdminController.php index e68e00d..7169355 100644 --- a/src/Controller/BillAdminController.php +++ b/src/Controller/BillAdminController.php @@ -23,6 +23,8 @@ use App\Repository\BillVendorRepositoryQuery; use App\Factory\BillVendorFactory; use App\Repository\BillCategoryRepositoryQuery; use App\Factory\BillCategoryFactory; +use App\Event\EntityManagerEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; class BillAdminController extends CrudController { @@ -119,6 +121,27 @@ class BillAdminController extends CrudController ); } + #[Route(path: "/admin/bill/update_status/{entity}/{status}", name: "admin_bill_update_status", methods: ['GET'])] + public function updateStatus(Entity $entity, int $status, EntityManager $entityManager, Request $request, EventDispatcherInterface $eventDispatcher): Response + { + if (!$this->isCsrfTokenValid('update_status', $request->query->get('_token'))) { + throw $this->createAccessDeniedException(); + } + + $entity->setStatus($status); + $entityManager->update($entity); + + $eventDispatcher->dispatch(new EntityManagerEvent($entity, [ + 'user' => $this->getUser(), + ]), 'bill.status_updated'); + + $this->addFlash('success', 'The data has been saved.'); + + return $this->redirectToRoute('admin_bill_show', [ + 'entity' => $entity->getId(), + ]); + } + #[Route(path: "/admin/bill/sort/{page}", name: "admin_bill_sort", methods: ['POST'], requirements: ['page' => '\d+'])] public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response { @@ -176,6 +199,8 @@ class BillAdminController extends CrudController // ->setAction('show', 'edit', true) ->setView('form', 'admin/bill/_form.html.twig') + ->setView('index', 'admin/bill/index.html.twig') + ->setView('edit', 'admin/bill/edit.html.twig') ->setView('show_entity', 'admin/bill/_show.html.twig') ->setDefaultSort('index', 'id', 'desc') ->setField('index', 'ID', Field\TextField::class, [ @@ -214,7 +239,7 @@ class BillAdminController extends CrudController ]) ->setField('index', 'Montant TTC', Field\TextField::class, [ 'property_builder' => function(EntityInterface $entity) { - if ($entity->getAmountTtc()) { + if ($entity->getAmountTtc() !== null) { return sprintf('%01.2f €', $entity->getAmountTtc()); } }, @@ -224,7 +249,7 @@ class BillAdminController extends CrudController ]) ->setField('index', 'Montant HT', Field\TextField::class, [ 'property_builder' => function(EntityInterface $entity) { - if ($entity->getAmountHt()) { + if ($entity->getAmountHt() !== null) { return sprintf('%01.2f €', $entity->getAmountHt()); } }, diff --git a/src/EventSubscriber/BillEventSubscriber.php b/src/EventSubscriber/BillEventSubscriber.php new file mode 100644 index 0000000..af4ded7 --- /dev/null +++ b/src/EventSubscriber/BillEventSubscriber.php @@ -0,0 +1,126 @@ +slugger = $slugger; + $this->notifier = $notifier; + $this->userQuery = $userQuery; + $this->urlGenerator = $urlGenerator; + } + + public static function getSubscribedEvents() + { + return array_merge(parent::getSubscribedEvents(), [ + 'bill.status_updated' => ['onStatusUpdate', self::$priority], + ]); + } + + public function supports(EntityInterface $entity) + { + return $entity instanceof Bill; + } + + public function onStatusUpdate(EntityManagerEvent $event) + { + if (!$this->supports($event->getEntity())) { + return; + } + + $this->notifier + ->setSubject('[Tinternet][Facture] '.$event->getEntity()->getHumanStatus()) + ->addRecipientsByUsers($this->userQuery + ->where('.isTreasurer = true') + ->orWhere('.isManager = true') + ->find(), + true) + ->notify('mail/bill/status_updated.html.twig', [ + 'entity' => $event->getEntity(), + 'user' => $event->getParams()['user'], + 'show_url' => $this->urlGenerator->generate( + 'admin_bill_show', + [ + 'entity' => $event->getEntity()->getId(), + ], + UrlGeneratorInterface::ABSOLUTE_URL + ), + ]) + ; + } + + public function onPreUpdate(EntityManagerEvent $event) + { + if (!$this->supports($event->getEntity())) { + return; + } + + $entity = $event->getEntity(); + + $splInfo = new \SplFileInfo($event->getEntity()->getFile()); + + $datas = []; + + if ($entity->getDate()) { + $datas[] = $entity->getDate()->format('Ymd'); + } + + if ($entity->getCategory()) { + $datas[] = $this->slugger->slugify($entity->getCategory()->getLabel()); + } + + if ($entity->getVendor()) { + $datas[] = $this->slugger->slugify($entity->getVendor()->getLabel()); + } + + if ($entity->getReference()) { + $datas[] = $entity->getReference(); + } + + $datas[] = $entity->getId().'.'.$splInfo->getExtension(); + + $expectedFilename = implode('_', $datas); + $expectedPath = dirname($entity->getFile()).'/'.$expectedFilename; + + if ($splInfo->getFilename() !== $expectedFilename) { + $fs = new Filesystem(); + $fs->rename( + $event->getEntity()->getFile(), + $expectedPath + ); + + $event->getEntity()->setFile($expectedPath); + } + } + + public function onDelete(EntityManagerEvent $event) + { + if (!$this->supports($event->getEntity())) { + return; + } + + $fs = new Filesystem(); + $fs->remove($event->getEntity()->getFile()); + } +} diff --git a/src/Form/BillFilterType.php b/src/Form/BillFilterType.php index 591b18e..ef47043 100644 --- a/src/Form/BillFilterType.php +++ b/src/Form/BillFilterType.php @@ -11,6 +11,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use App\Form\DateRangeType; class BillFilterType extends AbstractType { @@ -51,9 +52,11 @@ class BillFilterType extends AbstractType 'data-jschoice' => '', ], ]) - ->add('status', ChoiceType::class, [ - 'choices' => BillPeer::choices(), - 'required' => false, + ->add('dateRange', DateRangeType::class, [ + 'label' => 'Date', + 'attr' => [ + 'class' => 'row', + ], ]) ->add('amountTtcRange', AmountRangeType::class, [ 'label' => 'Montant TTC', @@ -67,6 +70,10 @@ class BillFilterType extends AbstractType 'class' => 'row', ], ]) + ->add('status', ChoiceType::class, [ + 'choices' => BillPeer::choices(), + 'required' => false, + ]) ; } diff --git a/src/Form/BillType.php b/src/Form/BillType.php index 475a82f..8107338 100644 --- a/src/Form/BillType.php +++ b/src/Form/BillType.php @@ -122,6 +122,7 @@ class BillType extends AbstractType ]) ->add('status', ChoiceType::class, [ 'choices' => BillPeer::choices(), + 'help' => 'Modifier cette valeur manuellement ne permet pas d\'envoyer des notifications par mail', 'label_attr' => [ 'class' => 'mt-3', ], diff --git a/src/Form/DateRangeType.php b/src/Form/DateRangeType.php new file mode 100644 index 0000000..b91b1ae --- /dev/null +++ b/src/Form/DateRangeType.php @@ -0,0 +1,49 @@ +add('min', DateType::class, [ + 'label' => 'Min', + 'html5' => true, + 'widget' => 'single_text', + 'required' => false, + 'row_attr' => [ + 'class' => 'col-md-6 pr-1', + ], + 'label_attr' => [ + 'class' => 'font-weight-normal', + ], + ]) + ->add('max', DateType::class, [ + 'label' => 'Max', + 'html5' => true, + 'widget' => 'single_text', + 'required' => false, + 'row_attr' => [ + 'class' => 'col-md-6 pl-1', + ], + 'label_attr' => [ + 'class' => 'font-weight-normal', + ], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => null, + ]); + } +} diff --git a/src/Repository/BillRepositoryQuery.php b/src/Repository/BillRepositoryQuery.php index c9f4ffb..c8c1a8d 100644 --- a/src/Repository/BillRepositoryQuery.php +++ b/src/Repository/BillRepositoryQuery.php @@ -44,10 +44,26 @@ class BillRepositoryQuery extends RepositoryQuery if (null !== $value['max']) { $this - ->andWhere('.amountHt <= :amountHtMin') + ->andWhere('.amountHt <= :amountHtMax') ->setParameter('amountHtMax', $value['max']) ; } + } elseif ('dateRange' === $name) { + if (null !== $value['min']) { + $this + ->andWhere('.date >= :dateMin') + ->setParameter('dateMin', $value['min']) + ; + } + + if (null !== $value['max']) { + $value['max']->add(new \DateInterval('PT'.(3600 * 24).'S')); + + $this + ->andWhere('.date <= :dateMax') + ->setParameter('dateMax', $value['max']) + ; + } } } } diff --git a/templates/admin/bill/_show.html.twig b/templates/admin/bill/_show.html.twig index 7af5fae..c7e1040 100644 --- a/templates/admin/bill/_show.html.twig +++ b/templates/admin/bill/_show.html.twig @@ -2,6 +2,9 @@ 'Référence': entity.reference, 'Fournisseur': entity.vendor, 'Catégorie': entity.category, + 'Date': entity.date ? entity.date.format('d/m/Y') : '/', + 'Date limite de paiement': entity.paymentDeadlineDate ? entity.paymentDeadlineDate.format('d/m/Y') : '/', + 'Catégorie': entity.category, 'Montant TTC': entity.amountTtc is not null ? (entity.amountTtc|number_format(2, ',') ~ ' €') : '/', 'Montant HT': entity.amountHt is not null ? (entity.amountHt|number_format(2, ',') ~ ' €') : '/', 'Status': entity.humanStatus, @@ -14,7 +17,7 @@ {% for label, value in values %}
{{ label|trans }}
-
{{ value }}
+
{{ value }}
{% endfor %} diff --git a/templates/admin/bill/edit.html.twig b/templates/admin/bill/edit.html.twig new file mode 100644 index 0000000..8fbd580 --- /dev/null +++ b/templates/admin/bill/edit.html.twig @@ -0,0 +1,15 @@ +{% extends '@Core/admin/crud/edit.html.twig' %} + +{% block header_actions_after %} + {% if entity.status == 0 %} + + Demander le paiement + + {% endif %} + + {% if entity.status == 1 %} + + Définir comme payée + + {% endif %} +{% endblock %} diff --git a/templates/admin/bill/index.html.twig b/templates/admin/bill/index.html.twig new file mode 100644 index 0000000..bffa527 --- /dev/null +++ b/templates/admin/bill/index.html.twig @@ -0,0 +1,7 @@ +{% extends '@Core/admin/crud/index.html.twig' %} + +{% block list_item_actions_before %} + + + +{% endblock %} diff --git a/templates/admin/menu.html.twig b/templates/admin/menu.html.twig index 0d9d8ab..e4dd2e6 100644 --- a/templates/admin/menu.html.twig +++ b/templates/admin/menu.html.twig @@ -66,7 +66,7 @@ {{ include('@Core/admin/module/_menu_section.html.twig', {label: 'Comptabilité'}) }}