Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/app/DomainObjects/Status/OrderStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace HiEvents\DomainObjects\Status;

use HiEvents\DomainObjects\Enums\BaseEnum;

enum OrderStatus
{
use BaseEnum;

case RESERVED;
case CANCELLED;
case COMPLETED;
Expand Down
1 change: 1 addition & 0 deletions backend/app/Mail/Attendee/AttendeeTicketMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public function content(): Content
with: [
'renderedBody' => $this->renderedTemplate->body,
'renderedCta' => $this->renderedTemplate->cta,
'eventSettings' => $this->eventSettings,
]
);
}
Expand Down
1 change: 1 addition & 0 deletions backend/app/Mail/Order/OrderSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public function content(): Content
with: [
'renderedBody' => $this->renderedTemplate->body,
'renderedCta' => $this->renderedTemplate->cta,
'eventSettings' => $this->eventSettings,
]
);
}
Expand Down
13 changes: 5 additions & 8 deletions backend/app/Services/Domain/Email/EmailTemplateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ public function __construct(
) {
}

/**
* Get a template for the given type and scope
*/
public function getTemplate(
public function getTemplateByType(
EmailTemplateType $type,
int $accountId,
?int $eventId = null,
Expand Down Expand Up @@ -165,7 +162,7 @@ private function getDefaultTemplates(): array
'body' => <<<'LIQUID'
<strong>Your Order is Confirmed! 🎉</strong><br>

{% if order.is_pending %}
{% if order.is_awaiting_offline_payment %}
<strong>ℹ️ Payment Pending:</strong> Your order is pending payment. Tickets have been issued but will not be valid until payment is received.<br>
<strong>Payment Instructions</strong><br>
Please follow the instructions below to complete your payment:<br>
Expand All @@ -180,7 +177,7 @@ private function getDefaultTemplates(): array
<strong>Event Details</strong><br>
<strong>Event Name:</strong> {{ event.title }}<br>
<strong>Date & Time:</strong> {{ event.date }} at {{ event.time }}<br>
{% if event.location %}<strong>Location:</strong> {{ event.location }}<br>{% endif %}
{% if event.full_address %}<strong>Location:</strong> {{ event.full_address }}<br>{% endif %}
<br>

{% if settings.post_checkout_message %}
Expand All @@ -203,7 +200,7 @@ private function getDefaultTemplates(): array
'body' => <<<'LIQUID'
<strong>You're going to {{ event.title }}! 🎉</strong><br>

{% if order.is_pending %}
{% if order.is_awaiting_offline_payment %}
<strong>ℹ️ Payment Pending:</strong> Your order is pending payment. Tickets have been issued but will not be valid until payment is received.<br>
{% endif %}

Expand All @@ -215,7 +212,7 @@ private function getDefaultTemplates(): array
<strong>Event:</strong> {{ event.title }}<br>
<strong>Date:</strong> {{ event.date }}<br>
<strong>Time:</strong> {{ event.time }}<br>
{% if event.location %}<strong>Location:</strong> {{ event.location }}<br>{% endif %}
{% if event.full_address %}<strong>Location:</strong> {{ event.full_address }}<br>{% endif %}
<br>

<strong>Your Ticket</strong><br>
Expand Down
42 changes: 31 additions & 11 deletions backend/app/Services/Domain/Email/EmailTokenContextBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use HiEvents\Helper\DateHelper;
use HiEvents\Helper\IdHelper;
use HiEvents\Helper\Url;
use HiEvents\Locale;

class EmailTokenContextBuilder
{
Expand All @@ -25,16 +26,21 @@ public function buildOrderConfirmationContext(
EventSettingDomainObject $eventSettings
): array
{
$eventDate = new Carbon(DateHelper::convertFromUTC($event->getStartDate(), $event->getTimezone()));
$eventStartDate = new Carbon(DateHelper::convertFromUTC($event->getStartDate(), $event->getTimezone()));
$eventEndDate = $event->getEndDate() ? new Carbon(DateHelper::convertFromUTC($event->getEndDate(), $event->getTimezone())) : null;

return [
// Event object
'event' => [
'title' => $event->getTitle(),
'date' => $eventDate->format('F j, Y'),
'time' => $eventDate->format('g:i A'),
'location' => $eventSettings->getLocationDetails() ? AddressHelper::formatAddress($eventSettings->getLocationDetails()) : '',
'date' => $eventStartDate->format('F j, Y'),
'time' => $eventStartDate->format('g:i A'),
'end_date' => $eventEndDate?->format('F j, Y') ?? '',
'end_time' => $eventEndDate?->format('g:i A') ?? '',
'full_address' => $eventSettings->getLocationDetails() ? AddressHelper::formatAddress($eventSettings->getLocationDetails()) : '',
'location_details' => $eventSettings->getLocationDetails(),
'description' => $event->getDescription() ?? '',
'timezone' => $event->getTimezone(),
],

// Order object
Expand All @@ -47,10 +53,13 @@ public function buildOrderConfirmationContext(
'number' => $order->getPublicId(),
'total' => Currency::format($order->getTotalGross(), $event->getCurrency()),
'date' => (new Carbon($order->getCreatedAt()))->format('F j, Y'),
'currency' => $order->getCurrency(), // added
'locale' => $order->getLocale(), // added
'first_name' => $order->getFirstName() ?? '',
'last_name' => $order->getLastName() ?? '',
'email' => $order->getEmail() ?? '',
'is_pending' => $order->isOrderAwaitingOfflinePayment(),
'is_awaiting_offline_payment' => $order->isOrderAwaitingOfflinePayment(),
'is_offline_payment' => $order->getPaymentProvider() === PaymentProviders::OFFLINE->value,
],

// Organizer object
Expand All @@ -65,9 +74,6 @@ public function buildOrderConfirmationContext(
'offline_payment_instructions' => $eventSettings->getOfflinePaymentInstructions() ?? '',
'post_checkout_message' => $eventSettings->getPostCheckoutMessage() ?? '',
],

// Top-level flags (for backward compatibility and convenience)
'is_offline_payment' => $order->getPaymentProvider() === PaymentProviders::OFFLINE->value,
];
}

Expand Down Expand Up @@ -113,8 +119,20 @@ public function buildPreviewContext(string $templateType): array
'title' => __('Summer Music Festival 2024'),
'date' => 'April 25, 2029',
'time' => '7:00 PM',
'location' => __('Madison Square Garden, New York'),
'end_date' => 'April 26, 2029',
'end_time' => '11:00 PM',
'full_address' => __('3 Arena, North Wall Quay, Dublin 1, Ireland'),
'description' => __('Join us for an unforgettable evening of live music featuring top artists from around the world.'),
'timezone' => 'UTC',
'location_details' => [
'venue_name' => '3 Arena',
'address_line_1' => 'North Wall Quay',
'address_line_2' => '',
'city' => 'Dublin',
'state_or_region' => 'Dublin 1',
'zip_or_postal_code' => 'D01 T0X4',
'country' => 'IE',
]
],
'order' => [
'url' => 'https://example.com/order/ABC123',
Expand All @@ -124,7 +142,10 @@ public function buildPreviewContext(string $templateType): array
'first_name' => 'John',
'last_name' => 'Smith',
'email' => '[email protected]',
'is_pending' => false,
'is_awaiting_offline_payment' => false,
'is_offline_payment' => false,
'locale' => Locale::EN->value,
'currency' => 'USD'
],
'organizer' => [
'name' => 'ACME Events Inc.',
Expand All @@ -135,7 +156,6 @@ public function buildPreviewContext(string $templateType): array
'offline_payment_instructions' => __('Please transfer the total amount to the following bank account within 5 business days.'),
'post_checkout_message' => __('Thank you for your purchase! We look forward to seeing you at the event.'),
],
'is_offline_payment' => false,
];

if ($templateType === 'attendee_ticket') {
Expand Down
4 changes: 2 additions & 2 deletions backend/app/Services/Domain/Email/MailBuilderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private function renderAttendeeTicketTemplate(
EventSettingDomainObject $eventSettings,
OrganizerDomainObject $organizer
): ?RenderedEmailTemplateDTO {
$template = $this->emailTemplateService->getTemplate(
$template = $this->emailTemplateService->getTemplateByType(
type: EmailTemplateType::ATTENDEE_TICKET,
accountId: $event->getAccountId(),
eventId: $event->getId(),
Expand Down Expand Up @@ -105,7 +105,7 @@ private function renderOrderSummaryTemplate(
EventSettingDomainObject $eventSettings,
OrganizerDomainObject $organizer
): ?RenderedEmailTemplateDTO {
$template = $this->emailTemplateService->getTemplate(
$template = $this->emailTemplateService->getTemplateByType(
type: EmailTemplateType::ORDER_CONFIRMATION,
accountId: $event->getAccountId(),
eventId: $event->getId(),
Expand Down
3 changes: 1 addition & 2 deletions backend/app/Services/Domain/Invoice/InvoiceCreateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function createInvoiceForOrder(int $orderId): InvoiceDomainObject
]);
}

public function getLatestInvoiceNumber(int $eventId, EventSettingDomainObject $eventSettings): string
private function getLatestInvoiceNumber(int $eventId, EventSettingDomainObject $eventSettings): string
{
$latestInvoice = $this->invoiceRepository->findLatestInvoiceForEvent($eventId);

Expand All @@ -76,5 +76,4 @@ public function getLatestInvoiceNumber(int $eventId, EventSettingDomainObject $e

return $prefix . $nextInvoiceNumber;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,63 @@ public function getAvailableTokens(EmailTemplateType $type): array
],
[
'token' => '{{ event.date }}',
'description' => __('The event date'),
'description' => __('The event start date'),
'example' => 'January 15, 2024',
],
[
'token' => '{{ event.time }}',
'description' => __('The event time'),
'description' => __('The event start time'),
'example' => '7:00 PM',
],
[
'token' => '{{ event.location }}',
'description' => __('The event location'),
'example' => 'Madison Square Garden',
'token' => '{{ event.end_date }}',
'description' => __('The event end date'),
'example' => 'January 16, 2024',
],
[
'token' => '{{ event.end_time }}',
'description' => __('The event end time'),
'example' => '11:00 PM',
],
[
'token' => '{{ event.full_address }}',
'description' => __('The full event address'),
'example' => '3 Arena, North Wall Quay, Dublin 1, D01 T0X4, Ireland',
],
[
'token' => '{{ event.location_details.venue_name }}',
'description' => __('The event venue name'),
'example' => '3 Arena',
],
[
'token' => '{{ event.location_details.address_line_1 }}',
'description' => __('The venue address line 1'),
'example' => 'North Wall Quay',
],
[
'token' => '{{ event.location_details.address_line_2 }}',
'description' => __('The venue address line 2'),
'example' => '',
],
[
'token' => '{{ event.location_details.city }}',
'description' => __('The venue city'),
'example' => 'Dublin',
],
[
'token' => '{{ event.location_details.state_or_region }}',
'description' => __('The venue state or region'),
'example' => 'Dublin 1',
],
[
'token' => '{{ event.location_details.zip_or_postal_code }}',
'description' => __('The venue ZIP or postal code'),
'example' => 'D01 T0X4',
],
[
'token' => '{{ event.location_details.country }}',
'description' => __('The venue country code'),
'example' => 'IE',
],
[
'token' => '{{ event.description }}',
Expand Down Expand Up @@ -139,16 +184,6 @@ public function getAvailableTokens(EmailTemplateType $type): array
'description' => __('The email of the person who placed the order'),
'example' => '[email protected]',
],
[
'token' => '{% if order.is_pending %}',
'description' => __('Conditional: Check if order is pending payment'),
'example' => '{% if order.is_pending %}Payment pending{% endif %}',
],
[
'token' => '{% if is_offline_payment %}',
'description' => __('Conditional: Check if payment is offline'),
'example' => '{% if is_offline_payment %}Offline payment{% endif %}',
],
];

$attendeeTokens = [
Expand Down
5 changes: 4 additions & 1 deletion backend/resources/views/emails/custom-template.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
{{ $renderedCta['label'] }}
</x-mail::button>
@endif
</x-mail::message>

{!! $eventSettings->getGetEmailFooterHtml() !!}

</x-mail::message>
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ class EmailTemplateServiceTest extends TestCase
protected function setUp(): void
{
parent::setUp();

$this->mockRepository = Mockery::mock(EmailTemplateRepositoryInterface::class);
$this->mockLiquidRenderer = Mockery::mock(LiquidTemplateRenderer::class);
$this->mockTokenBuilder = Mockery::mock(EmailTokenContextBuilder::class);

$this->emailTemplateService = new EmailTemplateService(
$this->mockRepository,
$this->mockLiquidRenderer,
Expand Down Expand Up @@ -55,7 +55,7 @@ public function test_gets_event_level_template_when_exists(): void
->once()
->andReturn($eventTemplate);

$result = $this->emailTemplateService->getTemplate(
$result = $this->emailTemplateService->getTemplateByType(
EmailTemplateType::ORDER_CONFIRMATION,
1, // accountId
1, // eventId
Expand Down Expand Up @@ -87,7 +87,7 @@ public function test_falls_back_to_organizer_template_when_no_event_template():
->once()
->andReturn($organizerTemplate);

$result = $this->emailTemplateService->getTemplate(
$result = $this->emailTemplateService->getTemplateByType(
EmailTemplateType::ORDER_CONFIRMATION,
1, // accountId
1, // eventId
Expand All @@ -110,7 +110,7 @@ public function test_returns_null_when_no_templates_exist(): void
->once()
->andReturn(null);

$result = $this->emailTemplateService->getTemplate(
$result = $this->emailTemplateService->getTemplateByType(
EmailTemplateType::ORDER_CONFIRMATION,
1, // accountId
1, // eventId
Expand Down Expand Up @@ -142,7 +142,7 @@ public function test_gets_organizer_level_template_when_no_event_id(): void
->once()
->andReturn($organizerTemplate);

$result = $this->emailTemplateService->getTemplate(
$result = $this->emailTemplateService->getTemplateByType(
EmailTemplateType::ATTENDEE_TICKET,
1, // accountId
null, // eventId
Expand Down Expand Up @@ -174,7 +174,7 @@ public function test_prefers_active_templates_over_inactive(): void
->once()
->andReturn($activeTemplate);

$result = $this->emailTemplateService->getTemplate(
$result = $this->emailTemplateService->getTemplateByType(
EmailTemplateType::ORDER_CONFIRMATION,
1, // accountId
1, // eventId
Expand Down Expand Up @@ -207,7 +207,7 @@ public function test_handles_different_template_types(): void
->once()
->andReturn($attendeeTicketTemplate);

$result = $this->emailTemplateService->getTemplate(
$result = $this->emailTemplateService->getTemplateByType(
EmailTemplateType::ATTENDEE_TICKET,
1, // accountId
null, // eventId
Expand Down Expand Up @@ -238,4 +238,4 @@ private function createMockTemplate(
'getEngine' => 'liquid',
]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ private function createMockOrder(): OrderDomainObject
'isOrderAwaitingOfflinePayment' => false,
'getPaymentProvider' => PaymentProviders::STRIPE->value,
'getOrderItems' => $orderItems,
'getCurrency' => 'USD',
'getLocale' => 'en',
]);
}

Expand All @@ -185,6 +187,7 @@ private function createMockEvent(): EventDomainObject
'getTitle' => 'Amazing Event',
'getDescription' => 'This is an amazing event',
'getStartDate' => '2024-02-15 19:00:00',
'getEndDate' => '2024-02-15 22:00:00',
'getTimezone' => 'America/New_York',
'getCurrency' => 'USD',
'getId' => 1,
Expand Down
Loading
Loading