Skip to content
Open
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
6 changes: 6 additions & 0 deletions backend/app/DomainObjects/Enums/MessageTypeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ enum MessageTypeEnum

// Emails all customers who have purchased a specific product, ticket or merchandise etc.
case ORDER_OWNERS_WITH_PRODUCT;

// Emails attendees who have checked in to the event
case CHECKED_IN_ATTENDEES;

// Emails attendees who have not checked in to the event
case NOT_CHECKED_IN_ATTENDEES;
}
1 change: 1 addition & 0 deletions backend/app/Http/Actions/Messages/SendMessageAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public function __invoke(SendMessageRequest $request, int $eventId): JsonRespons
'sent_by_user_id' => $user->getId(),
'account_id' => $this->getAuthenticatedAccountId(),
'scheduled_at' => $request->input('scheduled_at'),
'check_in_list_id' => $request->input('check_in_list_id'),
]));
} catch (AccountNotVerifiedException $e) {
return $this->errorResponse($e->getMessage(), Response::HTTP_UNAUTHORIZED);
Expand Down
2 changes: 2 additions & 0 deletions backend/app/Http/Request/Message/SendMessageRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public function rules(): array
new In([OrderStatus::COMPLETED->name, OrderStatus::AWAITING_OFFLINE_PAYMENT->name]),
],
'scheduled_at' => 'nullable|date',
'check_in_list_id' => 'nullable|integer|required_if:message_type,' . MessageTypeEnum::CHECKED_IN_ATTENDEES->name
. '|required_if:message_type,' . MessageTypeEnum::NOT_CHECKED_IN_ATTENDEES->name,
];
}

Expand Down
93 changes: 93 additions & 0 deletions backend/app/Repository/Eloquent/AttendeeRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,97 @@ public function getAttendeesByCheckInShortId(string $shortId, QueryParamsDTO $pa
limit: min($params->per_page, 250),
);
}

public function findCheckedInAttendees(int $eventId, ?int $checkInListId = null, array $columns = ['*']): Collection
{
$query = $this->model
->where('event_id', $eventId)
->where('status', AttendeeStatus::ACTIVE->name)
->whereIn('product_id', function ($sub) use ($checkInListId) {
$sub->select('product_id')->from('product_check_in_lists')->whereNull('deleted_at');
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
})
->whereHas('check_ins', function ($sub) use ($checkInListId) {
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
});

$results = $query->get($columns);
$this->resetModel();

return $this->handleResults($results);
}

public function findNotCheckedInAttendees(int $eventId, ?int $checkInListId = null, array $columns = ['*']): Collection
{
$query = $this->model
->where('event_id', $eventId)
->where('status', AttendeeStatus::ACTIVE->name)
->whereIn('product_id', function ($sub) use ($checkInListId) {
$sub->select('product_id')->from('product_check_in_lists')->whereNull('deleted_at');
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
})
->whereDoesntHave('check_ins', function ($sub) use ($checkInListId) {
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
});

$results = $query->get($columns);
$this->resetModel();

return $this->handleResults($results);
}

public function countCheckedInAttendees(int $eventId, ?int $checkInListId = null): int
{
$query = $this->model
->where('event_id', $eventId)
->where('status', AttendeeStatus::ACTIVE->name)
->whereIn('product_id', function ($sub) use ($checkInListId) {
$sub->select('product_id')->from('product_check_in_lists')->whereNull('deleted_at');
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
})
->whereHas('check_ins', function ($sub) use ($checkInListId) {
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
});

$count = $query->count();
$this->resetModel();

return $count;
}

public function countNotCheckedInAttendees(int $eventId, ?int $checkInListId = null): int
{
$query = $this->model
->where('event_id', $eventId)
->where('status', AttendeeStatus::ACTIVE->name)
->whereIn('product_id', function ($sub) use ($checkInListId) {
$sub->select('product_id')->from('product_check_in_lists')->whereNull('deleted_at');
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
})
->whereDoesntHave('check_ins', function ($sub) use ($checkInListId) {
if ($checkInListId) {
$sub->where('check_in_list_id', $checkInListId);
}
});

$count = $query->count();

$this->resetModel();

return $count;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ public function findByEventId(int $eventId, QueryParamsDTO $params): LengthAware
public function findByEventIdForExport(int $eventId): Collection;

public function getAttendeesByCheckInShortId(string $shortId, QueryParamsDTO $params): Paginator;

public function findCheckedInAttendees(int $eventId, ?int $checkInListId = null, array $columns = ['*']): Collection;

public function findNotCheckedInAttendees(int $eventId, ?int $checkInListId = null, array $columns = ['*']): Collection;

public function countCheckedInAttendees(int $eventId, ?int $checkInListId = null): int;

public function countNotCheckedInAttendees(int $eventId, ?int $checkInListId = null): int;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public function __construct(
public readonly ?array $attendee_ids = [],
public readonly ?array $product_ids = [],
public readonly ?string $scheduled_at = null,
public readonly ?int $check_in_list_id = null,
)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public function handle(SendMessageDTO $messageData): MessageDomainObject
'account_id' => $messageData->account_id,
'attendee_ids' => $messageData->attendee_ids,
'product_ids' => $messageData->product_ids,
'check_in_list_id' => $messageData->check_in_list_id,
],
]);

Expand All @@ -139,6 +140,7 @@ public function handle(SendMessageDTO $messageData): MessageDomainObject
'id' => $message->getId(),
'attendee_ids' => $message->getAttendeeIds(),
'product_ids' => $message->getProductIds(),
'check_in_list_id' => $messageData->check_in_list_id,
]);

SendMessagesJob::dispatch($updatedData);
Expand All @@ -164,6 +166,14 @@ private function estimateRecipientCount(SendMessageDTO $messageData): int
productIds: $messageData->product_ids ?? [],
orderStatuses: $messageData->order_statuses ?? ['COMPLETED'],
),
MessageTypeEnum::CHECKED_IN_ATTENDEES => $this->attendeeRepository->countCheckedInAttendees(
eventId: $messageData->event_id,
checkInListId: $messageData->check_in_list_id,
),
MessageTypeEnum::NOT_CHECKED_IN_ATTENDEES => $this->attendeeRepository->countNotCheckedInAttendees(
eventId: $messageData->event_id,
checkInListId: $messageData->check_in_list_id,
),
};
}

Expand Down
28 changes: 28 additions & 0 deletions backend/app/Services/Domain/Mail/SendEventEmailMessagesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public function send(SendMessageDTO $messageData): void
case MessageTypeEnum::ORDER_OWNERS_WITH_PRODUCT:
$this->sendProductMessages($messageData, $event);
break;
case MessageTypeEnum::CHECKED_IN_ATTENDEES:
$this->sendCheckedInMessages($messageData, $event);
break;
case MessageTypeEnum::NOT_CHECKED_IN_ATTENDEES:
$this->sendNotCheckedInMessages($messageData, $event);
break;
}

$this->updateMessageStatus($messageData, MessageStatus::SENT);
Expand Down Expand Up @@ -195,6 +201,28 @@ private function sendEventMessages(SendMessageDTO $messageData, EventDomainObjec
$this->emailAttendees($attendees, $messageData, $event);
}

private function sendCheckedInMessages(SendMessageDTO $messageData, EventDomainObject $event): void
{
$attendees = $this->attendeeRepository->findCheckedInAttendees(
eventId: $messageData->event_id,
checkInListId: $messageData->check_in_list_id,
columns: ['first_name', 'last_name', 'email'],
);

$this->emailAttendees($attendees, $messageData, $event);
}

private function sendNotCheckedInMessages(SendMessageDTO $messageData, EventDomainObject $event): void
{
$attendees = $this->attendeeRepository->findNotCheckedInAttendees(
eventId: $messageData->event_id,
checkInListId: $messageData->check_in_list_id,
columns: ['first_name', 'last_name', 'email'],
);

$this->emailAttendees($attendees, $messageData, $event);
}

private function sendEmailToMessageSender(SendMessageDTO $messageData, EventDomainObject $event): void
{
if (!$messageData->send_copy_to_current_user && !$messageData->is_test) {
Expand Down
Loading
Loading