feat(notification): email event date changes
This commit is contained in:
@@ -6,11 +6,13 @@ use App\Domains\Auth\Models\ResetPasswordAttempt;
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Integration\Services\MailService;
|
||||
use App\Domains\Notification\Events\PasswordResetRequested;
|
||||
use App\Domains\Notification\Models\EventDateNotificationDelivery;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticket\Services\TicketPdfService;
|
||||
use App\Domains\Ticket\Services\TicketPresentationResolver;
|
||||
use App\Domains\Ticket\Services\TicketValidityResolver;
|
||||
use Closure;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -184,6 +186,277 @@ class NotificationMailService
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array{purchase_id: int, ticket_ids: list<int>}> $purchaseTickets
|
||||
*/
|
||||
public function sendEventDateRescheduled(
|
||||
string $tenantCode,
|
||||
int $sourceEventDateId,
|
||||
int $destinationEventDateId,
|
||||
string $previousDate,
|
||||
string $newDate,
|
||||
array $purchaseTickets,
|
||||
): void {
|
||||
foreach ($purchaseTickets as $purchaseTicketGroup) {
|
||||
$purchaseId = $purchaseTicketGroup['purchase_id'];
|
||||
$ticketIds = $purchaseTicketGroup['ticket_ids'];
|
||||
$context = [
|
||||
'tenant_code' => $tenantCode,
|
||||
'event_date_id' => $sourceEventDateId,
|
||||
'destination_event_date_id' => $destinationEventDateId,
|
||||
'purchase_id' => $purchaseId,
|
||||
'ticket_ids' => $ticketIds,
|
||||
];
|
||||
$purchase = $this->eventDateNotificationPurchase($tenantCode, $purchaseId);
|
||||
|
||||
if ($purchase === null || $purchase->status !== Purchase::STATUS_PAID) {
|
||||
$this->logSkipped('event_date_rescheduled', array_merge($context, [
|
||||
'reason' => 'purchase_not_paid_or_not_found',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Collection<int, Ticket> $tickets */
|
||||
$tickets = $purchase->tickets()
|
||||
->where('tenant_code', $tenantCode)
|
||||
->whereKey($ticketIds)
|
||||
->with([
|
||||
...TicketPresentationResolver::RELATIONS,
|
||||
...TicketValidityResolver::RELATIONS,
|
||||
])
|
||||
->get()
|
||||
->filter(fn (Ticket $ticket): bool => $ticket->is_active())
|
||||
->values();
|
||||
|
||||
if ($tickets->isEmpty()) {
|
||||
$this->logSkipped('event_date_rescheduled', array_merge($context, [
|
||||
'reason' => 'no_longer_active_tickets',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipient = $this->recipientFor($purchase);
|
||||
if ($recipient === '') {
|
||||
$this->logSkipped('event_date_rescheduled', array_merge($context, [
|
||||
'reason' => 'missing_recipient',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$deliveryKey = "event-date-rescheduled:{$sourceEventDateId}:{$destinationEventDateId}:{$purchaseId}";
|
||||
if (! $this->claimDelivery(
|
||||
$deliveryKey,
|
||||
'event_date_rescheduled',
|
||||
$tenantCode,
|
||||
$sourceEventDateId,
|
||||
$destinationEventDateId,
|
||||
$purchaseId,
|
||||
)) {
|
||||
$this->logSkipped('event_date_rescheduled', array_merge($context, [
|
||||
'reason' => 'already_sent',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->sendLogged('event_date_rescheduled', $context, function () use (
|
||||
$tenantCode,
|
||||
$purchase,
|
||||
$recipient,
|
||||
$previousDate,
|
||||
$newDate,
|
||||
$tickets,
|
||||
): array {
|
||||
$brand = $purchase->tenant->websiteType ?? $purchase->tenant;
|
||||
|
||||
$this->mailService
|
||||
->forTenant($tenantCode)
|
||||
->send(
|
||||
$recipient,
|
||||
"Tu evento fue reprogramado - Compra #{$purchase->getKey()}",
|
||||
view('mail.notifications.event-date-rescheduled', compact(
|
||||
'purchase', 'previousDate', 'newDate', 'tickets'
|
||||
))->render(),
|
||||
$brand,
|
||||
);
|
||||
|
||||
return ['ticket_count' => $tickets->count()];
|
||||
});
|
||||
$this->markDeliverySent($deliveryKey);
|
||||
} catch (Throwable $exception) {
|
||||
$this->releaseDelivery($deliveryKey);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array{purchase_id: int, ticket_ids: list<int>}> $purchaseTickets
|
||||
*/
|
||||
public function sendEventDateSuspended(
|
||||
string $tenantCode,
|
||||
int $eventDateId,
|
||||
string $date,
|
||||
array $purchaseTickets,
|
||||
): void {
|
||||
foreach ($purchaseTickets as $purchaseTicketGroup) {
|
||||
$purchaseId = $purchaseTicketGroup['purchase_id'];
|
||||
$ticketIds = $purchaseTicketGroup['ticket_ids'];
|
||||
$context = [
|
||||
'tenant_code' => $tenantCode,
|
||||
'event_date_id' => $eventDateId,
|
||||
'purchase_id' => $purchaseId,
|
||||
'ticket_ids' => $ticketIds,
|
||||
];
|
||||
$purchase = $this->eventDateNotificationPurchase($tenantCode, $purchaseId);
|
||||
|
||||
if ($purchase === null || $purchase->status !== Purchase::STATUS_PAID) {
|
||||
$this->logSkipped('event_date_suspended', array_merge($context, [
|
||||
'reason' => 'purchase_not_paid_or_not_found',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Collection<int, Ticket> $tickets */
|
||||
$tickets = $purchase->tickets()
|
||||
->where('tenant_code', $tenantCode)
|
||||
->whereKey($ticketIds)
|
||||
->with([
|
||||
...TicketPresentationResolver::RELATIONS,
|
||||
...TicketValidityResolver::RELATIONS,
|
||||
])
|
||||
->get()
|
||||
->filter(fn (Ticket $ticket): bool => in_array($ticket->status, [
|
||||
Ticket::STATUS_ACTIVE,
|
||||
Ticket::STATUS_DISABLED,
|
||||
], true))
|
||||
->values();
|
||||
|
||||
if ($tickets->isEmpty()) {
|
||||
$this->logSkipped('event_date_suspended', array_merge($context, [
|
||||
'reason' => 'no_longer_relevant_tickets',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipient = $this->recipientFor($purchase);
|
||||
if ($recipient === '') {
|
||||
$this->logSkipped('event_date_suspended', array_merge($context, [
|
||||
'reason' => 'missing_recipient',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$deliveryKey = "event-date-suspended:{$eventDateId}:{$purchaseId}";
|
||||
if (! $this->claimDelivery(
|
||||
$deliveryKey,
|
||||
'event_date_suspended',
|
||||
$tenantCode,
|
||||
$eventDateId,
|
||||
null,
|
||||
$purchaseId,
|
||||
)) {
|
||||
$this->logSkipped('event_date_suspended', array_merge($context, [
|
||||
'reason' => 'already_sent',
|
||||
]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$disabledTickets = $tickets
|
||||
->filter(fn (Ticket $ticket): bool => $ticket->status === Ticket::STATUS_DISABLED)
|
||||
->values();
|
||||
$activeTickets = $tickets
|
||||
->filter(fn (Ticket $ticket): bool => $ticket->status === Ticket::STATUS_ACTIVE)
|
||||
->values();
|
||||
|
||||
try {
|
||||
$this->sendLogged('event_date_suspended', $context, function () use (
|
||||
$tenantCode,
|
||||
$purchase,
|
||||
$recipient,
|
||||
$date,
|
||||
$disabledTickets,
|
||||
$activeTickets,
|
||||
): array {
|
||||
$brand = $purchase->tenant->websiteType ?? $purchase->tenant;
|
||||
|
||||
$this->mailService
|
||||
->forTenant($tenantCode)
|
||||
->send(
|
||||
$recipient,
|
||||
"Una fecha de tu evento fue suspendida - Compra #{$purchase->getKey()}",
|
||||
view('mail.notifications.event-date-suspended', compact(
|
||||
'purchase', 'date', 'disabledTickets', 'activeTickets'
|
||||
))->render(),
|
||||
$brand,
|
||||
);
|
||||
|
||||
return [
|
||||
'ticket_count' => $disabledTickets->count() + $activeTickets->count(),
|
||||
'disabled_ticket_ids' => $disabledTickets->modelKeys(),
|
||||
'active_ticket_ids' => $activeTickets->modelKeys(),
|
||||
];
|
||||
});
|
||||
$this->markDeliverySent($deliveryKey);
|
||||
} catch (Throwable $exception) {
|
||||
$this->releaseDelivery($deliveryKey);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function eventDateNotificationPurchase(string $tenantCode, int $purchaseId): ?Purchase
|
||||
{
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenantCode)
|
||||
->with(['tenant.websiteType', 'user'])
|
||||
->find($purchaseId);
|
||||
}
|
||||
|
||||
private function claimDelivery(
|
||||
string $deliveryKey,
|
||||
string $type,
|
||||
string $tenantCode,
|
||||
int $eventDateId,
|
||||
?int $destinationEventDateId,
|
||||
int $purchaseId,
|
||||
): bool {
|
||||
return EventDateNotificationDelivery::query()->insertOrIgnore([
|
||||
'notification_key' => $deliveryKey,
|
||||
'notification_type' => $type,
|
||||
'tenant_code' => $tenantCode,
|
||||
'event_date_id' => $eventDateId,
|
||||
'destination_event_date_id' => $destinationEventDateId,
|
||||
'purchase_id' => $purchaseId,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]) === 1;
|
||||
}
|
||||
|
||||
private function markDeliverySent(string $deliveryKey): void
|
||||
{
|
||||
EventDateNotificationDelivery::query()
|
||||
->where('notification_key', $deliveryKey)
|
||||
->update(['sent_at' => now()]);
|
||||
}
|
||||
|
||||
private function releaseDelivery(string $deliveryKey): void
|
||||
{
|
||||
EventDateNotificationDelivery::query()
|
||||
->where('notification_key', $deliveryKey)
|
||||
->delete();
|
||||
}
|
||||
|
||||
private function recipientFor(Purchase $purchase): string
|
||||
{
|
||||
return (string) ($purchase->email ?: $purchase->user?->email);
|
||||
|
||||
Reference in New Issue
Block a user