diff --git a/src/Controller/PaymentOrderController.php b/src/Controller/PaymentOrderController.php index c8f9bc9..a298dfc 100644 --- a/src/Controller/PaymentOrderController.php +++ b/src/Controller/PaymentOrderController.php @@ -21,6 +21,7 @@ use App\Audit\UserProvider; use App\Entity\ConfirmationToken; use App\Entity\PaymentOrder; +use App\Event\PaymentOrderConfirmedEvent; use App\Event\PaymentOrderSubmittedEvent; use App\Form\PaymentOrderConfirmationType; use App\Form\PaymentOrderType; @@ -55,12 +56,13 @@ public function __construct( private readonly EntityManagerInterface $entityManager, private readonly MessageBusInterface $messageBus, private readonly ConfirmationHelper $confirmationHelper, + private readonly EventDispatcherInterface $eventDispatcher ) { } #[Route(path: '/new', name: 'payment_order_new')] - public function new(Request $request, EntityManagerInterface $entityManager, EventDispatcherInterface $dispatcher, + public function new(Request $request, EntityManagerInterface $entityManager, PaymentReferenceGenerator $paymentReferenceGenerator, RateLimiterFactory $paymentOrderSubmitLimiter): Response { $limiter = $paymentOrderSubmitLimiter->create($request->getClientIp()); @@ -131,7 +133,7 @@ public function new(Request $request, EntityManagerInterface $entityManager, Eve //Dispatch event so an email can be sent $event = new PaymentOrderSubmittedEvent($new_order); - $dispatcher->dispatch($event, $event::NAME); + $this->eventDispatcher->dispatch($event, $event::NAME); //Redirect to homepage, if no further paymentOrders should be submitted //Otherwise create a new form for further ones @@ -173,8 +175,7 @@ public function new(Request $request, EntityManagerInterface $entityManager, Eve private function copyProperties(PaymentOrder $source, PaymentOrder $target): void { - $target->setFirstName($source->getFirstName()); - $target->setLastName($source->getLastName()); + $target->setSubmitterName($source->getSubmitterName()); $target->setSubmitterEmail($source->getSubmitterEmail()); $target->setDepartment($source->getDepartment()); $target->setBankInfo($source->getBankInfo()); @@ -293,6 +294,12 @@ public function confirmation( $this->entityManager->flush(); $this->addFlash('success', 'payment_order.confirmation.success'); + //If the payment order is now confirmed, trigger the event + if ($paymentOrder->isConfirmed()) { + $event = new PaymentOrderConfirmedEvent($paymentOrder); + $this->eventDispatcher->dispatch($event, $event::NAME); + } + //Rerender form if it was confirmed, to apply the disabled state $form = $this->createForm(PaymentOrderConfirmationType::class, null, [ 'disabled' => true, diff --git a/src/Event/PaymentOrderConfirmedEvent.php b/src/Event/PaymentOrderConfirmedEvent.php new file mode 100644 index 0000000..25ef131 --- /dev/null +++ b/src/Event/PaymentOrderConfirmedEvent.php @@ -0,0 +1,27 @@ +paymentOrder; + } +} \ No newline at end of file diff --git a/src/Event/PaymentOrderEventInterface.php b/src/Event/PaymentOrderEventInterface.php new file mode 100644 index 0000000..db7a4c7 --- /dev/null +++ b/src/Event/PaymentOrderEventInterface.php @@ -0,0 +1,13 @@ +payment_order; + return $this->paymentOrder; } } diff --git a/src/EventSubscriber/PaymentOrderNotificationSubscriber.php b/src/EventSubscriber/PaymentOrderNotificationSubscriber.php index a88322e..5c68690 100644 --- a/src/EventSubscriber/PaymentOrderNotificationSubscriber.php +++ b/src/EventSubscriber/PaymentOrderNotificationSubscriber.php @@ -39,9 +39,7 @@ final class PaymentOrderNotificationSubscriber implements EventSubscriberInterfa public function __construct( private readonly MailerInterface $mailer, private readonly TranslatorInterface $translator, - private readonly PaymentOrderPDFGenerator $paymentOrderPDFGenerator, - private readonly EntityManagerInterface $entityManager, - private readonly UserProvider $userProvider, + private readonly string $fsb_email, private readonly string $hhv_email, private readonly bool $send_notifications, @@ -88,30 +86,12 @@ public function sendUserEmail(PaymentOrderSubmittedEvent $event): void $this->mailer->send($email); } - public function generatePDF(PaymentOrderSubmittedEvent $event): void - { - $payment_order = $event->getPaymentOrder(); - $pdf_content = $this->paymentOrderPDFGenerator->generatePDF($payment_order); - - //Create temporary file - $tmpfname = tempnam(sys_get_temp_dir(), 'stura'); - file_put_contents($tmpfname, $pdf_content); - $file = new UploadedFile($tmpfname, 'form.pdf', null, null, true); - - $payment_order->setPrintedFormFile($file); - - $this->userProvider->setManualUsername('[Automatic form generation]', UserProvider::INTERNAL_USER_IDENTIFIER); - - //Save to database and let VichUploadBundle handle everything else (it will also remove the temp file) - $this->entityManager->flush(); - } public static function getSubscribedEvents(): array { return [ PaymentOrderSubmittedEvent::NAME => [ - ['generatePDF', 10], ['sendUserEmail', 0], ], ]; diff --git a/src/EventSubscriber/PaymentOrderPDFGenerationSubscriber.php b/src/EventSubscriber/PaymentOrderPDFGenerationSubscriber.php new file mode 100644 index 0000000..46977e3 --- /dev/null +++ b/src/EventSubscriber/PaymentOrderPDFGenerationSubscriber.php @@ -0,0 +1,59 @@ +getPaymentOrder(); + $pdf_content = $this->paymentOrderPDFGenerator->generatePDF($payment_order); + + //Create temporary file + $tmpfname = tempnam(sys_get_temp_dir(), 'stura'); + file_put_contents($tmpfname, $pdf_content); + + $file = new UploadedFile($tmpfname, 'form.pdf', null, null, true); + + $payment_order->setPrintedFormFile($file); + + $this->userProvider->setManualUsername('[Automatic form generation]', UserProvider::INTERNAL_USER_IDENTIFIER); + + //Save to database and let VichUploadBundle handle everything else (it will also remove the temp file) + $this->entityManager->flush(); + } + + public static function getSubscribedEvents(): array + { + //The priorities here need to be high, so that the PDF is generated before the emails are sent + return [ + //Generate a draft version of the PDF when a payment order is submitted + PaymentOrderSubmittedEvent::NAME => [ + ['generatePDF', 1000], + ], + //Generae the final version of the PDF when a payment order is confirmed + PaymentOrderConfirmedEvent::NAME => [ + ['generatePDF', 1000] + ], + ]; + } +} \ No newline at end of file diff --git a/src/EventSubscriber/PaymentOrderSendConfirmationEmailsSubscriber.php b/src/EventSubscriber/PaymentOrderSendConfirmationEmailsSubscriber.php index 5d7106d..1afcd1d 100644 --- a/src/EventSubscriber/PaymentOrderSendConfirmationEmailsSubscriber.php +++ b/src/EventSubscriber/PaymentOrderSendConfirmationEmailsSubscriber.php @@ -18,13 +18,24 @@ namespace App\EventSubscriber; +use App\Event\PaymentOrderConfirmedEvent; use App\Event\PaymentOrderSubmittedEvent; use App\Services\EmailConfirmation\ConfirmationEmailSender; +use App\Services\ReplyEmailDecisonMaker; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Email; + +use function Symfony\Component\String\u; final readonly class PaymentOrderSendConfirmationEmailsSubscriber implements EventSubscriberInterface { - public function __construct(private ConfirmationEmailSender $confirmationSender) + public function __construct( + private ConfirmationEmailSender $confirmationSender, + private readonly MailerInterface $mailer, + private readonly ReplyEmailDecisonMaker $replyEmailDecisonMaker, + ) { } @@ -35,12 +46,45 @@ public function sendConfirmationEmails(PaymentOrderSubmittedEvent $event): void $this->confirmationSender->sendAllConfirmationEmails($paymentOrder); } + /** + * Send the confirmed email to the confirmer persons + * @param PaymentOrderConfirmedEvent $event + * @return void + */ + public function sendConfirmedEmail(PaymentOrderConfirmedEvent $event): void + { + $paymentOrder = $event->getPaymentOrder(); + + $email = new TemplatedEmail(); + $email->priority(Email::PRIORITY_HIGH); + $email->replyTo($this->replyEmailDecisonMaker->getReplyToMailForPaymentOrder($paymentOrder)); + $email->subject(sprintf('%s (%s) bestätigt', $paymentOrder->getIDString(), u($paymentOrder->getProjectName())->truncate(50))); + + $email->htmlTemplate('mails/confirmed_notification.html.twig'); + $email->context([ + 'payment_order' => $paymentOrder, + ]); + + //Add all confirmers for the payment order into the BCC + foreach ($paymentOrder->getDepartment()->getConfirmers() as $confirmer) { + $email->addBcc($confirmer->getEmail()); + } + + //Add the form as attachment + $email->attachFromPath($paymentOrder->getPrintedFormFile()->getRealPath(), $paymentOrder->getIDString() . '.pdf', 'application/pdf'); + + $this->mailer->send($email); + } + public static function getSubscribedEvents(): array { return [ PaymentOrderSubmittedEvent::NAME => [ ['sendConfirmationEmails', 5], ], + PaymentOrderConfirmedEvent::NAME => [ + ['sendConfirmedEmail', 5], + ], ]; } } diff --git a/src/MessageHandler/PaymentOrder/PaymentOrderDeletedNotificationHandler.php b/src/MessageHandler/PaymentOrder/PaymentOrderDeletedNotificationHandler.php new file mode 100644 index 0000000..96b4d3e --- /dev/null +++ b/src/MessageHandler/PaymentOrder/PaymentOrderDeletedNotificationHandler.php @@ -0,0 +1,78 @@ +. + */ + +namespace App\MessageHandler\PaymentOrder; + +use App\Message\PaymentOrder\PaymentOrderDeletedNotification; +use App\Services\ReplyEmailDecisonMaker; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; +use Symfony\Component\Mime\Email; +use Symfony\Contracts\Translation\TranslatorInterface; + +#[AsMessageHandler] +final readonly class PaymentOrderDeletedNotificationHandler +{ + + public function __construct( + private MailerInterface $mailer, + private ReplyEmailDecisonMaker $reply_decision_maker, + private TranslatorInterface $translator + ) + { + } + + public function __invoke(PaymentOrderDeletedNotification $message): void + { + $paymentOrder = $message->getPaymentOrder(); + + $email = new TemplatedEmail(); + $email->priority(Email::PRIORITY_HIGH); + $reply_to_email = $this->reply_decision_maker->getReplyToMailForPaymentOrder($paymentOrder); + $email->replyTo($reply_to_email); + + $email->subject( + $this->translator->trans( + 'payment_order.deletion_email.subject', + [ + '%project%' => $paymentOrder->getProjectName(), + ] + )); + + $email->htmlTemplate('mails/deletion_notification.html.twig'); + $email->context([ + 'payment_order' => $paymentOrder, + 'blame_user' => $message->getBlameUser(), + 'deleted_where' => $message->getDeletedWhere(), + ]); + + //Send the email to the FSR officers and the HHV/FSB + $email_addresses = array_merge( + $paymentOrder->getDepartment()->getEmailHhv(), + $paymentOrder->getDepartment()->getEmailTreasurer(), + [$reply_to_email] + ); + + $email->addBcc(...$email_addresses); + + + //Send email + $this->mailer->send($email); + } +} \ No newline at end of file diff --git a/src/Services/EmailConfirmation/ManualConfirmationHelper.php b/src/Services/EmailConfirmation/ManualConfirmationHelper.php index bfd5e2b..2825fc1 100644 --- a/src/Services/EmailConfirmation/ManualConfirmationHelper.php +++ b/src/Services/EmailConfirmation/ManualConfirmationHelper.php @@ -21,7 +21,7 @@ use App\Entity\Embeddable\Confirmation; use App\Entity\PaymentOrder; use App\Entity\User; -use Carbon\Carbon; +use App\Event\PaymentOrderConfirmedEvent; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Mailer\MailerInterface; @@ -41,7 +41,8 @@ public function __construct( private MailerInterface $mailer, array $notifications_risky, private string $fsb_email, - private string $hhv_email + private string $hhv_email, + private readonly \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher, ) { $this->notifications_risky = array_filter($notifications_risky); @@ -77,6 +78,10 @@ public function confirmManually(PaymentOrder $paymentOrder, string $reason, ?Use if ($paymentOrder->getRequiredConfirmations() > 1) { $this->performConfirmationIfNeeded($paymentOrder->getConfirmation2(), $reason, $user); } + + //Trigger the confirmed event + $event = new PaymentOrderConfirmedEvent($paymentOrder); + $this->eventDispatcher->dispatch($event); } private function performConfirmationIfNeeded(Confirmation $confirmation, string $reason, User $user): void diff --git a/templates/mails/confirmed_notification.html.twig b/templates/mails/confirmed_notification.html.twig new file mode 100644 index 0000000..c7cf494 --- /dev/null +++ b/templates/mails/confirmed_notification.html.twig @@ -0,0 +1,26 @@ +{% extends "mails/base_mail.html.twig" %} + +{# @var payment_order \App\Entity\PaymentOrder #} + +{% block content %} + + +

Zahlungsauftrag {{ payment_order.iDString }} bestätigt

+
+ +

Untenstehender Zahlungsauftrag wurde durch euch bestätigt. Bitte druckt das angehängte Formular aus + und unterschreibt es. Anschließend gebt es zusammen mit allen nicht digital vorliegenden Originalbelegen + bei den StuRa-Finanzen ab, damit der Auftrag weiter bearbeitet werden kann!

+ + {% include "mails/_payment_order_table.html.twig" %} + +
+ +

Du erhältst diese E-Mail, da du als Finanzverantwortlichen für den oben genannten FSR / Referat eingetragen bist. + Sollte dies nicht stimmen, melde dich bitte bei {{ hhv_email }} +

+ +
+
+ +{% endblock %} \ No newline at end of file