Skip to content

Commit

Permalink
Send an email with the paymentOrder form to confirmation persons, aft…
Browse files Browse the repository at this point in the history
…er an paymentOrder was confirmed
  • Loading branch information
jbtronics committed Oct 26, 2024
1 parent 0871143 commit 20a7d9f
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 31 deletions.
15 changes: 11 additions & 4 deletions src/Controller/PaymentOrderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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,
Expand Down
27 changes: 27 additions & 0 deletions src/Event/PaymentOrderConfirmedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);


namespace App\Event;

use App\Entity\PaymentOrder;
use Symfony\Contracts\EventDispatcher\Event;

/**
* Represents the event that is triggered, if a payment order has been confirmed by all responsible persons,
* and is now ready for the next steps.
*/
final class PaymentOrderConfirmedEvent extends Event implements PaymentOrderEventInterface
{
public const NAME = 'payment_order.confirmed';

public function __construct(private readonly PaymentOrder $paymentOrder)
{
}

public function getPaymentOrder(): PaymentOrder
{
return $this->paymentOrder;
}
}
13 changes: 13 additions & 0 deletions src/Event/PaymentOrderEventInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);


namespace App\Event;

use App\Entity\PaymentOrder;

interface PaymentOrderEventInterface
{
public function getPaymentOrder(): PaymentOrder;
}
9 changes: 6 additions & 3 deletions src/Event/PaymentOrderSubmittedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@
use App\Entity\PaymentOrder;
use Symfony\Contracts\EventDispatcher\Event;

final class PaymentOrderSubmittedEvent extends Event
/**
* This event is triggered if an payment order was submitted.
*/
final class PaymentOrderSubmittedEvent extends Event implements PaymentOrderEventInterface
{
public const NAME = 'payment_order.submitted';

public function __construct(private readonly PaymentOrder $payment_order)
public function __construct(private readonly PaymentOrder $paymentOrder)
{
}

public function getPaymentOrder(): PaymentOrder
{
return $this->payment_order;
return $this->paymentOrder;
}
}
22 changes: 1 addition & 21 deletions src/EventSubscriber/PaymentOrderNotificationSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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],
],
];
Expand Down
59 changes: 59 additions & 0 deletions src/EventSubscriber/PaymentOrderPDFGenerationSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);


namespace App\EventSubscriber;

use App\Audit\UserProvider;
use App\Event\PaymentOrderConfirmedEvent;
use App\Event\PaymentOrderSubmittedEvent;
use App\Services\PDF\PaymentOrderPDFGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class PaymentOrderPDFGenerationSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly PaymentOrderPDFGenerator $paymentOrderPDFGenerator,
private readonly EntityManagerInterface $entityManager,
private readonly UserProvider $userProvider,)
{

}

public function generatePDF(PaymentOrderSubmittedEvent|PaymentOrderConfirmedEvent $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
{
//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]
],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
{
}

Expand All @@ -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],
],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
/*
* Copyright (C) 2020 Jan Böhmer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

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);
}
}
Loading

0 comments on commit 20a7d9f

Please sign in to comment.