From dc6d9a0a87eccdf101c3d65430fcf01b419a58d7 Mon Sep 17 00:00:00 2001 From: Dave Earley Date: Fri, 14 Mar 2025 09:39:53 +0000 Subject: [PATCH] Send order emails when offline payments marked as paid --- .../Jobs/Order/SendOrderDetailsEmailJob.php | 2 +- .../Domain/Mail/SendOrderDetailsService.php | 49 +++++++++++++------ .../Domain/Order/MarkOrderAsPaidService.php | 32 ++++++++++-- .../organizer/summary-for-organizer.blade.php | 2 + .../views/emails/orders/summary.blade.php | 23 ++++++--- backend/routes/mail.php | 23 +++++++-- 6 files changed, 98 insertions(+), 33 deletions(-) diff --git a/backend/app/Jobs/Order/SendOrderDetailsEmailJob.php b/backend/app/Jobs/Order/SendOrderDetailsEmailJob.php index 4ca2fcf193..c6fb63f948 100644 --- a/backend/app/Jobs/Order/SendOrderDetailsEmailJob.php +++ b/backend/app/Jobs/Order/SendOrderDetailsEmailJob.php @@ -22,6 +22,6 @@ public function __construct(private readonly OrderDomainObject $order) public function handle(SendOrderDetailsService $service): void { - $service->sendOrderSummaryAndProductEmails($this->order); + $service->sendOrderSummaryAndTicketEmails($this->order); } } diff --git a/backend/app/Services/Domain/Mail/SendOrderDetailsService.php b/backend/app/Services/Domain/Mail/SendOrderDetailsService.php index a4e63b66f9..10c808b340 100644 --- a/backend/app/Services/Domain/Mail/SendOrderDetailsService.php +++ b/backend/app/Services/Domain/Mail/SendOrderDetailsService.php @@ -18,18 +18,18 @@ use HiEvents\Services\Domain\Attendee\SendAttendeeTicketService; use Illuminate\Mail\Mailer; -readonly class SendOrderDetailsService +class SendOrderDetailsService { public function __construct( - private EventRepositoryInterface $eventRepository, - private OrderRepositoryInterface $orderRepository, - private Mailer $mailer, - private SendAttendeeTicketService $sendAttendeeTicketService, + private readonly EventRepositoryInterface $eventRepository, + private readonly OrderRepositoryInterface $orderRepository, + private readonly Mailer $mailer, + private readonly SendAttendeeTicketService $sendAttendeeTicketService, ) { } - public function sendOrderSummaryAndProductEmails(OrderDomainObject $order): void + public function sendOrderSummaryAndTicketEmails(OrderDomainObject $order): void { $order = $this->orderRepository ->loadRelation(OrderItemDomainObject::class) @@ -59,6 +59,26 @@ public function sendOrderSummaryAndProductEmails(OrderDomainObject $order): void } } + public function sendCustomerOrderSummary( + OrderDomainObject $order, + EventDomainObject $event, + OrganizerDomainObject $organizer, + EventSettingDomainObject $eventSettings, + ?InvoiceDomainObject $invoice = null + ): void + { + $this->mailer + ->to($order->getEmail()) + ->locale($order->getLocale()) + ->send(new OrderSummary( + order: $order, + event: $event, + organizer: $organizer, + eventSettings: $eventSettings, + invoice: $invoice, + )); + } + private function sendAttendeeTicketEmails(OrderDomainObject $order, EventDomainObject $event): void { $sentEmails = []; @@ -81,16 +101,13 @@ private function sendAttendeeTicketEmails(OrderDomainObject $order, EventDomainO private function sendOrderSummaryEmails(OrderDomainObject $order, EventDomainObject $event): void { - $this->mailer - ->to($order->getEmail()) - ->locale($order->getLocale()) - ->send(new OrderSummary( - order: $order, - event: $event, - organizer: $event->getOrganizer(), - eventSettings: $event->getEventSettings(), - invoice: $order->getLatestInvoice(), - )); + $this->sendCustomerOrderSummary( + order: $order, + event: $event, + organizer: $event->getOrganizer(), + eventSettings: $event->getEventSettings(), + invoice: $order->getLatestInvoice(), + ); if ($order->getIsManuallyCreated() || !$event->getEventSettings()->getNotifyOrganizerOfNewOrders()) { return; diff --git a/backend/app/Services/Domain/Order/MarkOrderAsPaidService.php b/backend/app/Services/Domain/Order/MarkOrderAsPaidService.php index 15a3e3e982..ea5a6bf906 100644 --- a/backend/app/Services/Domain/Order/MarkOrderAsPaidService.php +++ b/backend/app/Services/Domain/Order/MarkOrderAsPaidService.php @@ -4,11 +4,16 @@ use HiEvents\DomainObjects\AccountConfigurationDomainObject; use HiEvents\DomainObjects\AccountDomainObject; +use HiEvents\DomainObjects\AttendeeDomainObject; use HiEvents\DomainObjects\Enums\PaymentProviders; use HiEvents\DomainObjects\Enums\WebhookEventType; use HiEvents\DomainObjects\EventDomainObject; +use HiEvents\DomainObjects\EventSettingDomainObject; use HiEvents\DomainObjects\Generated\OrderDomainObjectAbstract; +use HiEvents\DomainObjects\InvoiceDomainObject; use HiEvents\DomainObjects\OrderDomainObject; +use HiEvents\DomainObjects\OrderItemDomainObject; +use HiEvents\DomainObjects\OrganizerDomainObject; use HiEvents\DomainObjects\Status\AttendeeStatus; use HiEvents\DomainObjects\Status\InvoiceStatus; use HiEvents\DomainObjects\Status\OrderApplicationFeeStatus; @@ -21,6 +26,7 @@ use HiEvents\Repository\Interfaces\EventRepositoryInterface; use HiEvents\Repository\Interfaces\InvoiceRepositoryInterface; use HiEvents\Repository\Interfaces\OrderRepositoryInterface; +use HiEvents\Services\Domain\Mail\SendOrderDetailsService; use HiEvents\Services\Infrastructure\Webhook\WebhookDispatchService; use Illuminate\Database\DatabaseManager; use Throwable; @@ -36,6 +42,7 @@ public function __construct( private readonly OrderApplicationFeeCalculationService $orderApplicationFeeCalculationService, private readonly EventRepositoryInterface $eventRepository, private readonly OrderApplicationFeeService $orderApplicationFeeService, + private readonly SendOrderDetailsService $sendOrderDetailsService, ) { } @@ -50,10 +57,19 @@ public function markOrderAsPaid( { return $this->databaseManager->transaction(function () use ($orderId, $eventId) { /** @var OrderDomainObject $order */ - $order = $this->orderRepository->findFirstWhere([ - OrderDomainObjectAbstract::ID => $orderId, - OrderDomainObjectAbstract::EVENT_ID => $eventId, - ]); + $order = $this->orderRepository + ->loadRelation(OrderItemDomainObject::class) + ->loadRelation(AttendeeDomainObject::class) + ->loadRelation(InvoiceDomainObject::class) + ->findFirstWhere([ + OrderDomainObjectAbstract::ID => $orderId, + OrderDomainObjectAbstract::EVENT_ID => $eventId, + ]); + + $event = $this->eventRepository + ->loadRelation(new Relationship(OrganizerDomainObject::class, name: 'organizer')) + ->loadRelation(new Relationship(EventSettingDomainObject::class)) + ->findById($order->getEventId()); if ($order->getStatus() !== OrderStatus::AWAITING_OFFLINE_PAYMENT->name) { throw new ResourceConflictException(__('Order is not awaiting offline payment')); @@ -79,6 +95,14 @@ public function markOrderAsPaid( $this->storeApplicationFeePayment($updatedOrder); + $this->sendOrderDetailsService->sendCustomerOrderSummary( + order: $updatedOrder, + event: $event, + organizer: $event->getOrganizer(), + eventSettings: $event->getEventSettings(), + invoice: $order->getLatestInvoice(), + ); + return $updatedOrder; }); } diff --git a/backend/resources/views/emails/orders/organizer/summary-for-organizer.blade.php b/backend/resources/views/emails/orders/organizer/summary-for-organizer.blade.php index 5dd6befa5a..6d69ccda10 100644 --- a/backend/resources/views/emails/orders/organizer/summary-for-organizer.blade.php +++ b/backend/resources/views/emails/orders/organizer/summary-for-organizer.blade.php @@ -20,6 +20,8 @@ @endif +{{ __('Name') }}: {{ $order->getFullName() }}
+{{ __('Email') }}: {{ $order->getEmail() }}
{{ __('Order Amount:') }} {{ Currency::format($order->getTotalGross(), $event->getCurrency()) }}
{{ __('Order ID:') }} {{ $order->getPublicId() }}
{{ __('Order Status:') }} {{ $order->getHumanReadableStatus() }} diff --git a/backend/resources/views/emails/orders/summary.blade.php b/backend/resources/views/emails/orders/summary.blade.php index e0b426b790..98ee28b8a6 100644 --- a/backend/resources/views/emails/orders/summary.blade.php +++ b/backend/resources/views/emails/orders/summary.blade.php @@ -9,10 +9,13 @@ # {{ __('Your Order is Confirmed! ') }} 🎉 @if($order->isOrderAwaitingOfflinePayment() === false) +

{{ __('Congratulations! Your order for :eventTitle on :eventDate at :eventTime was successful. Please find your order details below.', ['eventTitle' => $event->getTitle(), 'eventDate' => (new Carbon(DateHelper::convertFromUTC($event->getStartDate(), $event->getTimezone())))->format('F j, Y'), 'eventTime' => (new Carbon(DateHelper::convertFromUTC($event->getStartDate(), $event->getTimezone())))->format('g:i A')]) }}

+ @else +

{{ __('Your order is pending payment. Tickets have been issued but will not be valid until payment is received.') }} @@ -24,18 +27,29 @@ {!! $eventSettings->getOfflinePaymentInstructions() !!}

+ @endif

-## {{ __('Event Details') }} +# {{ __('Event Details') }} **{{ __('Event Name:') }}** {{ $event->getTitle() }}
**{{ __('Date & Time:') }}** {{ (new Carbon(DateHelper::convertFromUTC($event->getStartDate(), $event->getTimezone())))->format('F j, Y') }} at {{ (new Carbon(DateHelper::convertFromUTC($event->getStartDate(), $event->getTimezone())))->format('g:i A') }}

-## {{ __('Order Summary') }} +@if($eventSettings->getPostCheckoutMessage() && $order->isOrderCompleted()) +

+ +# {{ __('Additional Information') }} + +{!! $eventSettings->getPostCheckoutMessage() !!} + +

+@endif + +# {{ __('Order Summary') }} - **{{ __('Order Number:') }}** {{ $order->getPublicId() }} - **{{ __('Total Amount:') }}** {{ Currency::format($order->getTotalGross(), $event->getCurrency()) }} @@ -45,11 +59,6 @@ {{ __('If you have any questions or need assistance, feel free to reach out to our friendly support team at') }} {{ $organizer->getEmail() }}. -## {{ __('What\'s Next?') }} -- **{{ __('Download Tickets:') }}** {{ __('Please download your tickets from the order summary page.') }} -- **{{ __('Prepare for the Event:') }}** {{ __('Make sure to note the event date, time, and location.') }} -- **{{ __('Stay Updated:') }}** {{ __('Keep an eye on your email for any updates from the event organizer.') }} - {{ __('Best regards,') }}
{{ config('app.name') }} diff --git a/backend/routes/mail.php b/backend/routes/mail.php index c0b0b313e8..0d07ea5f1a 100644 --- a/backend/routes/mail.php +++ b/backend/routes/mail.php @@ -1,11 +1,12 @@ setItemName('Test Item'); $order = (new OrderDomainObject()) + ->setFirstName('Test') + ->setLastName('User') + ->setEmail('test@test.com') ->setId(2) - ->setPublicId('123') + ->setPublicId(IdHelper::publicId('o')) ->setShortId('123') ->setStatus(OrderStatus::COMPLETED->name) - ->setOrderItems(collect([$orderItem, $orderItem2])); + ->setOrderItems(collect([$orderItem, $orderItem2])) + ->setTotalGross(200); $organizer = (new OrganizerDomainObject()) ->setId(1) ->setName('Test Organizer') ->setEmail('s@d.com'); + $eventSettings = (new EventSettingDomainObject()) + ->setSupportEmail('d@d.com') + ->setPostCheckoutMessage('Thank you for your order'); + $event = (new EventDomainObject()) ->setId(1) ->setTitle('Test Event') ->setStartDate(now()) ->setTimeZone('UTC') - ->setOrganizer($organizer); + ->setOrganizer($organizer) + ->setEventSettings($eventSettings); - return new OrderSummaryForOrganizer($order, $event); + return new \HiEvents\Mail\Organizer\OrderSummaryForOrganizer( + order: $order, + event: $event, + ); });