feat: email notifications about uploaded invoices to management
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Controller\Traits\ReturnUrlTrait;
|
|||||||
use App\Entity\Disposition;
|
use App\Entity\Disposition;
|
||||||
use App\Entity\Upload;
|
use App\Entity\Upload;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Event\DocumentUploadedEvent;
|
||||||
use App\Form\TeamerDispositionType;
|
use App\Form\TeamerDispositionType;
|
||||||
use App\Model\UploadSessionDto;
|
use App\Model\UploadSessionDto;
|
||||||
use App\Service\Upload\UploadHandler;
|
use App\Service\Upload\UploadHandler;
|
||||||
@@ -18,6 +19,7 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
use Symfony\Component\Workflow\WorkflowInterface;
|
use Symfony\Component\Workflow\WorkflowInterface;
|
||||||
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
|
|
||||||
class DetailController extends AbstractController
|
class DetailController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -28,6 +30,7 @@ class DetailController extends AbstractController
|
|||||||
private readonly EntityManagerInterface $entityManager,
|
private readonly EntityManagerInterface $entityManager,
|
||||||
#[Target('disposition')]
|
#[Target('disposition')]
|
||||||
private readonly WorkflowInterface $workflow,
|
private readonly WorkflowInterface $workflow,
|
||||||
|
private readonly EventDispatcherInterface $eventDispatcher,
|
||||||
private readonly LoggerInterface $logger
|
private readonly LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -63,7 +66,7 @@ class DetailController extends AbstractController
|
|||||||
|
|
||||||
return $this->render('teamer/disposition/detail.html.twig', [
|
return $this->render('teamer/disposition/detail.html.twig', [
|
||||||
'disposition' => $disposition,
|
'disposition' => $disposition,
|
||||||
'form' => $form,
|
'form' => $form->createView(),
|
||||||
'returnUrl' => $this->getReturnUrl($request, 'app_teamer_index'),
|
'returnUrl' => $this->getReturnUrl($request, 'app_teamer_index'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -93,6 +96,8 @@ class DetailController extends AbstractController
|
|||||||
$this->logger->info('Upload contract', [
|
$this->logger->info('Upload contract', [
|
||||||
'user' => $user->getUserIdentifier(),
|
'user' => $user->getUserIdentifier(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(new DocumentUploadedEvent($upload), DocumentUploadedEvent::NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function uploadInvoice(Disposition $disposition, UploadSessionDto $uploadSession): void
|
private function uploadInvoice(Disposition $disposition, UploadSessionDto $uploadSession): void
|
||||||
@@ -120,5 +125,7 @@ class DetailController extends AbstractController
|
|||||||
$this->logger->info('Upload invoice', [
|
$this->logger->info('Upload invoice', [
|
||||||
'user' => $user->getUserIdentifier(),
|
'user' => $user->getUserIdentifier(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(new DocumentUploadedEvent($upload), DocumentUploadedEvent::NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Event;
|
||||||
|
|
||||||
|
use App\Entity\Upload;
|
||||||
|
use Symfony\Contracts\EventDispatcher\Event;
|
||||||
|
|
||||||
|
class DocumentUploadedEvent extends Event
|
||||||
|
{
|
||||||
|
public const NAME = 'document.uploaded';
|
||||||
|
|
||||||
|
public function __construct(private readonly Upload $document)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDocument(): Upload
|
||||||
|
{
|
||||||
|
return $this->document;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,19 +3,25 @@
|
|||||||
namespace App\EventListener;
|
namespace App\EventListener;
|
||||||
|
|
||||||
use App\Email\Mailer;
|
use App\Email\Mailer;
|
||||||
|
use App\Entity\Upload;
|
||||||
use App\Event\DispositionCreatedEvent;
|
use App\Event\DispositionCreatedEvent;
|
||||||
|
use App\Event\DocumentUploadedEvent;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
class EmailNotificationSubscriber implements EventSubscriberInterface
|
class EmailNotificationSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
public function __construct(private readonly Mailer $mailer)
|
public function __construct(
|
||||||
{
|
private readonly Mailer $mailer,
|
||||||
|
private readonly UserRepository $userRepository
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSubscribedEvents(): array
|
public static function getSubscribedEvents(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
DispositionCreatedEvent::NAME => 'onDispositionCreated',
|
DispositionCreatedEvent::NAME => 'onDispositionCreated',
|
||||||
|
DocumentUploadedEvent::NAME => 'onDocumentUploaded',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,4 +38,33 @@ class EmailNotificationSubscriber implements EventSubscriberInterface
|
|||||||
'template' => 'email/application_accepted.html.twig',
|
'template' => 'email/application_accepted.html.twig',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onDocumentUploaded(DocumentUploadedEvent $event): void
|
||||||
|
{
|
||||||
|
$document = $event->getDocument();
|
||||||
|
|
||||||
|
if (Upload::TYPE_INVOICE === $document->getType()) {
|
||||||
|
$disposition = $document->getDisposition();
|
||||||
|
$hotelCode = $disposition
|
||||||
|
->getAssignment()
|
||||||
|
->getDestination()
|
||||||
|
->getHotelCode()
|
||||||
|
;
|
||||||
|
|
||||||
|
$managers = $this
|
||||||
|
->userRepository
|
||||||
|
->getUsersByRoleAndHotelCode('ROLE_MANAGER', $hotelCode)
|
||||||
|
;
|
||||||
|
|
||||||
|
foreach ($managers as $manager) {
|
||||||
|
$this->mailer->createAndSendEmail([
|
||||||
|
'disposition' => $disposition,
|
||||||
|
], [
|
||||||
|
'to' => $manager->getEmail(),
|
||||||
|
'subject' => 'Honorarnote hochgeladen',
|
||||||
|
'template' => 'email/invoice_uploaded.html.twig',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,4 +20,22 @@ class UserRepository extends ServiceEntityRepository
|
|||||||
{
|
{
|
||||||
parent::__construct($registry, User::class);
|
parent::__construct($registry, User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUsersByRoleAndHotelCode(string $role, string $hotelCode): array
|
||||||
|
{
|
||||||
|
$hotelCodeBase = substr($hotelCode, 0, 3);
|
||||||
|
|
||||||
|
$qb = $this->createQueryBuilder('user');
|
||||||
|
|
||||||
|
return $qb
|
||||||
|
->where($qb->expr()->andX(
|
||||||
|
$qb->expr()->eq('user.hotelCode', ':hotelCode'),
|
||||||
|
$qb->expr()->like('user.roles', ':role')
|
||||||
|
))
|
||||||
|
->setParameter('hotelCode', $hotelCodeBase)
|
||||||
|
->setParameter('role', '%"'.$role.'"%')
|
||||||
|
->getQuery()
|
||||||
|
->getResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'email/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1>
|
||||||
|
Honorarnote hochgeladen
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<strong>{{ disposition.teamer }}</strong> hat eine Honorarnote zum Einsatz
|
||||||
|
<strong>{{ disposition.assignment.jobProfile.name }} {{ disposition.assignment.destination}}</strong>
|
||||||
|
hochgeladen.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="{{ url('app_teamer_index') }}" class="button">
|
||||||
|
Zum Portal
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user