feat(notification): email event date changes
This commit is contained in:
parent
205d77bc0b
commit
756f4dad0a
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Domains\Notification\Listeners;
|
||||
|
||||
use App\Domains\Event\Events\EventDateRescheduled;
|
||||
use App\Domains\Notification\Services\NotificationMailService;
|
||||
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class SendEventDateRescheduledEmails implements ShouldQueueAfterCommit
|
||||
{
|
||||
use InteractsWithQueue;
|
||||
|
||||
public string $queue = 'emails';
|
||||
|
||||
public int $tries = 3;
|
||||
|
||||
/** @var array<int, int> */
|
||||
public array $backoff = [30, 120, 300];
|
||||
|
||||
public function handle(EventDateRescheduled $event): void
|
||||
{
|
||||
app(NotificationMailService::class)->sendEventDateRescheduled(
|
||||
$event->tenantCode,
|
||||
$event->sourceEventDateId,
|
||||
$event->destinationEventDateId,
|
||||
$event->previousDate,
|
||||
$event->newDate,
|
||||
$event->purchaseTickets,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Domains\Notification\Listeners;
|
||||
|
||||
use App\Domains\Event\Events\EventDateSuspended;
|
||||
use App\Domains\Notification\Services\NotificationMailService;
|
||||
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class SendEventDateSuspendedEmails implements ShouldQueueAfterCommit
|
||||
{
|
||||
use InteractsWithQueue;
|
||||
|
||||
public string $queue = 'emails';
|
||||
|
||||
public int $tries = 3;
|
||||
|
||||
/** @var array<int, int> */
|
||||
public array $backoff = [30, 120, 300];
|
||||
|
||||
public function handle(EventDateSuspended $event): void
|
||||
{
|
||||
app(NotificationMailService::class)->sendEventDateSuspended(
|
||||
$event->tenantCode,
|
||||
$event->eventDateId,
|
||||
$event->date,
|
||||
$event->purchaseTickets,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Domains\Notification\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
#[Fillable([
|
||||
'notification_key',
|
||||
'notification_type',
|
||||
'tenant_code',
|
||||
'event_date_id',
|
||||
'destination_event_date_id',
|
||||
'purchase_id',
|
||||
'sent_at',
|
||||
])]
|
||||
class EventDateNotificationDelivery extends Model
|
||||
{
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'event_date_id' => 'integer',
|
||||
'destination_event_date_id' => 'integer',
|
||||
'purchase_id' => 'integer',
|
||||
'sent_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Domains\Event\Events\EventDateRescheduled;
|
||||
use App\Domains\Event\Events\EventDateSuspended;
|
||||
use App\Domains\Integration\Models\Integration;
|
||||
use App\Domains\Integration\Policies\IntegrationPolicy;
|
||||
use App\Domains\Notification\Events\PasswordResetRequested;
|
||||
use App\Domains\Notification\Events\UserRegistered;
|
||||
use App\Domains\Notification\Listeners\SendEventDateRescheduledEmails;
|
||||
use App\Domains\Notification\Listeners\SendEventDateSuspendedEmails;
|
||||
use App\Domains\Notification\Listeners\SendPasswordResetEmail;
|
||||
use App\Domains\Notification\Listeners\SendPurchaseConfirmedEmail;
|
||||
use App\Domains\Notification\Listeners\SendWelcomeEmail;
|
||||
|
|
@ -40,6 +44,8 @@ class AppServiceProvider extends ServiceProvider
|
|||
);
|
||||
Event::listen(PurchasePaid::class, GenerateTicketsForPaidPurchase::class);
|
||||
Event::listen(PurchasePaid::class, SendPurchaseConfirmedEmail::class);
|
||||
Event::listen(EventDateRescheduled::class, SendEventDateRescheduledEmails::class);
|
||||
Event::listen(EventDateSuspended::class, SendEventDateSuspendedEmails::class);
|
||||
Event::listen(UserRegistered::class, SendWelcomeEmail::class);
|
||||
Event::listen(PasswordResetRequested::class, SendPasswordResetEmail::class);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('event_date_notification_deliveries', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('notification_key')->unique();
|
||||
$table->string('notification_type');
|
||||
$table->string('tenant_code');
|
||||
$table->unsignedBigInteger('event_date_id');
|
||||
$table->unsignedBigInteger('destination_event_date_id')->nullable();
|
||||
$table->unsignedBigInteger('purchase_id');
|
||||
$table->timestamp('sent_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('event_date_notification_deliveries');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<h1 style="margin: 0 0 20px;">Tu evento fue reprogramado</h1>
|
||||
<p>Te informamos que la fecha de tu evento cambió.</p>
|
||||
<p>
|
||||
<strong>Fecha anterior:</strong> {{ $previousDate }}<br>
|
||||
<strong>Nueva fecha:</strong> {{ $newDate }}
|
||||
</p>
|
||||
<p>Tus tickets continúan siendo válidos para la nueva fecha.</p>
|
||||
<p><strong>Tickets afectados</strong></p>
|
||||
<ul>
|
||||
@foreach ($tickets as $ticket)
|
||||
<li>{{ $ticket->name }} · #{{ $ticket->id }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
<p style="color: #64748b; font-size: 13px;">Compra #{{ $purchase->id }}</p>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<h1 style="margin: 0 0 20px;">Actualización sobre tu evento</h1>
|
||||
<p>La fecha <strong>{{ $date }}</strong> fue suspendida.</p>
|
||||
|
||||
@if ($disabledTickets->isNotEmpty())
|
||||
<p>Los siguientes tickets quedaron inhabilitados porque no tienen otra fecha disponible:</p>
|
||||
<ul>
|
||||
@foreach ($disabledTickets as $ticket)
|
||||
<li>{{ $ticket->name }} · #{{ $ticket->id }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
<p>Para conocer las alternativas o condiciones de devolución, comunicate con la organización.</p>
|
||||
@endif
|
||||
|
||||
@if ($activeTickets->isNotEmpty())
|
||||
<p>Estos tickets conservan otras fechas disponibles:</p>
|
||||
<ul>
|
||||
@foreach ($activeTickets as $ticket)
|
||||
<li>{{ $ticket->name }} · #{{ $ticket->id }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
<p style="color: #64748b; font-size: 13px;">Compra #{{ $purchase->id }}</p>
|
||||
|
|
@ -270,6 +270,131 @@ class NotificationMailServiceTest extends TestCase
|
|||
});
|
||||
}
|
||||
|
||||
public function test_it_sends_one_rescheduling_email_per_purchase_and_does_not_duplicate_it(): void
|
||||
{
|
||||
$purchase = Purchase::query()->create([
|
||||
'tenant_codigo' => $this->tenant->codigo,
|
||||
'user_id' => $this->user->id,
|
||||
'status' => Purchase::STATUS_PAID,
|
||||
'payment_method' => 'transfer',
|
||||
'total' => 25,
|
||||
'email' => 'checkout@example.com',
|
||||
]);
|
||||
$purchaseItem = $purchase->items()->create([
|
||||
'source_catalog_item_id' => $this->catalogItem()->id,
|
||||
'nombre' => 'Entrada',
|
||||
'item_nombre' => 'Entrada general',
|
||||
'variant_attributes' => [],
|
||||
'cantidad' => 2,
|
||||
'precio_unitario' => 25,
|
||||
'total' => 25,
|
||||
]);
|
||||
$firstTicket = $this->ticketFor($purchaseItem->id);
|
||||
$secondTicket = $this->ticketFor($purchaseItem->id);
|
||||
$purchaseTickets = [[
|
||||
'purchase_id' => $purchase->id,
|
||||
'ticket_ids' => [$firstTicket->id, $secondTicket->id],
|
||||
]];
|
||||
|
||||
app(NotificationMailService::class)->sendEventDateRescheduled(
|
||||
$this->tenant->codigo,
|
||||
10,
|
||||
20,
|
||||
'09/10/2027',
|
||||
'20/10/2027',
|
||||
$purchaseTickets,
|
||||
);
|
||||
app(NotificationMailService::class)->sendEventDateRescheduled(
|
||||
$this->tenant->codigo,
|
||||
10,
|
||||
20,
|
||||
'09/10/2027',
|
||||
'20/10/2027',
|
||||
$purchaseTickets,
|
||||
);
|
||||
|
||||
Mail::assertSent(Mailable::class, 1);
|
||||
Mail::assertSent(Mailable::class, function (Mailable $mail) use ($purchase, $firstTicket, $secondTicket): bool {
|
||||
$mail->assertTo('checkout@example.com');
|
||||
|
||||
return $mail->subject === "Tu evento fue reprogramado - Compra #{$purchase->id}"
|
||||
&& str_contains($mail->render(), '09/10/2027')
|
||||
&& str_contains($mail->render(), '20/10/2027')
|
||||
&& str_contains($mail->render(), '#'.$firstTicket->id)
|
||||
&& str_contains($mail->render(), '#'.$secondTicket->id);
|
||||
});
|
||||
$this->assertDatabaseHas('event_date_notification_deliveries', [
|
||||
'notification_key' => "event-date-rescheduled:10:20:{$purchase->id}",
|
||||
'purchase_id' => $purchase->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_suspension_email_uses_the_account_email_and_separates_disabled_tickets(): void
|
||||
{
|
||||
$purchase = Purchase::query()->create([
|
||||
'tenant_codigo' => $this->tenant->codigo,
|
||||
'user_id' => $this->user->id,
|
||||
'status' => Purchase::STATUS_PAID,
|
||||
'payment_method' => 'transfer',
|
||||
'total' => 25,
|
||||
'email' => null,
|
||||
]);
|
||||
$purchaseItem = $purchase->items()->create([
|
||||
'source_catalog_item_id' => $this->catalogItem()->id,
|
||||
'nombre' => 'Entrada',
|
||||
'item_nombre' => 'Entrada general',
|
||||
'variant_attributes' => [],
|
||||
'cantidad' => 2,
|
||||
'precio_unitario' => 25,
|
||||
'total' => 25,
|
||||
]);
|
||||
$disabledTicket = $this->ticketFor($purchaseItem->id);
|
||||
$disabledTicket->markAsDisabled();
|
||||
$disabledTicket->save();
|
||||
$activeTicket = $this->ticketFor($purchaseItem->id);
|
||||
|
||||
app(NotificationMailService::class)->sendEventDateSuspended(
|
||||
$this->tenant->codigo,
|
||||
10,
|
||||
'09/10/2027',
|
||||
[[
|
||||
'purchase_id' => $purchase->id,
|
||||
'ticket_ids' => [$disabledTicket->id, $activeTicket->id],
|
||||
]],
|
||||
);
|
||||
|
||||
Mail::assertSent(Mailable::class, function (Mailable $mail) use ($disabledTicket, $activeTicket): bool {
|
||||
$mail->assertTo('ada@example.com');
|
||||
|
||||
return str_contains($mail->render(), 'quedaron inhabilitados')
|
||||
&& str_contains($mail->render(), 'conservan otras fechas disponibles')
|
||||
&& str_contains($mail->render(), '#'.$disabledTicket->id)
|
||||
&& str_contains($mail->render(), '#'.$activeTicket->id);
|
||||
});
|
||||
}
|
||||
|
||||
private function ticketFor(int $purchaseItemId): Ticket
|
||||
{
|
||||
return Ticket::query()->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'ticket' => fake()->uuid(),
|
||||
'source_purchase_item_id' => $purchaseItemId,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
}
|
||||
|
||||
private function catalogItem(): CatalogItem
|
||||
{
|
||||
return CatalogItem::query()->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'slug' => fake()->unique()->slug(),
|
||||
'nombre' => 'Entrada',
|
||||
'descripcion' => 'Entrada general',
|
||||
'precio' => 25,
|
||||
'has_tickets' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
private function useWebsiteTypeBranding(): void
|
||||
{
|
||||
$websiteType = WebsiteType::query()->create([
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
namespace Tests\Feature\Notification;
|
||||
|
||||
use App\Domains\Event\Events\EventDateRescheduled;
|
||||
use App\Domains\Event\Events\EventDateSuspended;
|
||||
use App\Domains\Notification\Listeners\SendEventDateRescheduledEmails;
|
||||
use App\Domains\Notification\Listeners\SendEventDateSuspendedEmails;
|
||||
use App\Domains\Notification\Listeners\SendPurchaseConfirmedEmail;
|
||||
use App\Domains\Notification\Services\NotificationMailService;
|
||||
use App\Domains\Purchase\Events\PurchasePaid;
|
||||
|
|
@ -27,4 +31,42 @@ class QueuedNotificationListenerTest extends TestCase
|
|||
|
||||
$this->assertSame(123, $purchasePaid->purchaseId);
|
||||
}
|
||||
|
||||
public function test_rescheduled_date_email_listener_delegates_the_captured_purchase_tickets(): void
|
||||
{
|
||||
$mailService = Mockery::mock(NotificationMailService::class);
|
||||
$mailService->shouldReceive('sendEventDateRescheduled')
|
||||
->once()
|
||||
->with('acme', 10, 20, '2027-10-09', '2027-10-20', [[
|
||||
'purchase_id' => 123,
|
||||
'ticket_ids' => [456, 789],
|
||||
]]);
|
||||
$this->app->instance(NotificationMailService::class, $mailService);
|
||||
|
||||
(new SendEventDateRescheduledEmails)->handle(new EventDateRescheduled(
|
||||
'acme', 10, 20, '2027-10-09', '2027-10-20', [[
|
||||
'purchase_id' => 123,
|
||||
'ticket_ids' => [456, 789],
|
||||
]]
|
||||
));
|
||||
}
|
||||
|
||||
public function test_suspended_date_email_listener_delegates_the_captured_purchase_tickets(): void
|
||||
{
|
||||
$mailService = Mockery::mock(NotificationMailService::class);
|
||||
$mailService->shouldReceive('sendEventDateSuspended')
|
||||
->once()
|
||||
->with('acme', 10, '2027-10-09', [[
|
||||
'purchase_id' => 123,
|
||||
'ticket_ids' => [456],
|
||||
]]);
|
||||
$this->app->instance(NotificationMailService::class, $mailService);
|
||||
|
||||
(new SendEventDateSuspendedEmails)->handle(new EventDateSuspended(
|
||||
'acme', 10, '2027-10-09', [[
|
||||
'purchase_id' => 123,
|
||||
'ticket_ids' => [456],
|
||||
]]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue