diff --git a/app/Domains/Integration/Services/MailService.php b/app/Domains/Integration/Services/MailService.php index 4b7b0f8..c264c24 100644 --- a/app/Domains/Integration/Services/MailService.php +++ b/app/Domains/Integration/Services/MailService.php @@ -72,11 +72,15 @@ class MailService extends BaseIntegrationService return []; } + /** + * @param array $attachments + */ public function send( string|array $recipient, string $subject, string $content, Tenant|WebsiteType|null $brand = null, + array $attachments = [], ): void { if (! $this->mailer || ! $this->tenant) { throw new Exception('MailService no está configurado. Llamá a forTenant() o forClient() primero.'); @@ -105,6 +109,14 @@ class MailService extends BaseIntegrationService ->subject($subject) ->html($html); + foreach ($attachments as $attachment) { + $mail->attachData( + $attachment['data'], + $attachment['name'], + ['mime' => $attachment['mime']], + ); + } + $this->mailer->to($recipient)->send($mail); } diff --git a/app/Domains/Notification/Services/NotificationMailService.php b/app/Domains/Notification/Services/NotificationMailService.php index fccd708..69561e8 100644 --- a/app/Domains/Notification/Services/NotificationMailService.php +++ b/app/Domains/Notification/Services/NotificationMailService.php @@ -9,6 +9,7 @@ use App\Domains\Notification\Events\PasswordResetRequested; 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 Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; @@ -17,6 +18,7 @@ class NotificationMailService { public function __construct( private readonly MailService $mailService, + private readonly TicketPdfService $ticketPdfService, ) {} public function sendWelcome(int $userId, string $tenantCode): void @@ -130,6 +132,11 @@ class NotificationMailService $this->recipientFor($purchase), 'Tus tickets ya están disponibles', view('mail.notifications.tickets-available', compact('purchase', 'tickets'))->render(), + attachments: [[ + 'data' => $this->ticketPdfService->contents($purchase->tenant, $tickets), + 'name' => $this->ticketPdfService->filename($tickets), + 'mime' => 'application/pdf', + ]], ); } diff --git a/app/Domains/Ticket/Services/TicketPdfService.php b/app/Domains/Ticket/Services/TicketPdfService.php index 34bc681..211a4cf 100644 --- a/app/Domains/Ticket/Services/TicketPdfService.php +++ b/app/Domains/Ticket/Services/TicketPdfService.php @@ -5,6 +5,7 @@ namespace App\Domains\Ticket\Services; use App\Domains\Tenant\Models\Tenant; use App\Domains\Ticket\Models\Ticket; use Barryvdh\DomPDF\Facade\Pdf; +use Barryvdh\DomPDF\PDF as DomPdf; use Endroid\QrCode\ErrorCorrectionLevel; use Endroid\QrCode\QrCode; use Endroid\QrCode\Writer\PngWriter; @@ -19,12 +20,36 @@ class TicketPdfService * @param Collection $tickets */ public function download(Tenant $tenant, Collection $tickets): Response + { + return $this->pdf($tenant, $tickets)->download($this->filename($tickets)); + } + + /** + * @param Collection $tickets + */ + public function contents(Tenant $tenant, Collection $tickets): string + { + return $this->pdf($tenant, $tickets)->output(); + } + + /** + * @param Collection $tickets + */ + public function filename(Collection $tickets): string + { + return 'tickets_'.$tickets->pluck('id')->implode('_').'.pdf'; + } + + /** + * @param Collection $tickets + */ + private function pdf(Tenant $tenant, Collection $tickets): DomPdf { $tenant->loadMissing('headerLogo'); $primaryColor = $this->color($tenant->primary_color, '#009933'); $headerBackgroundColor = $this->color($tenant->header_bg_color, $primaryColor); - $pdf = Pdf::loadView('pdf.tickets', [ + return Pdf::loadView('pdf.tickets', [ 'tenant' => $tenant, 'tickets' => $tickets, 'logoDataUri' => $this->logoDataUri($tenant), @@ -35,10 +60,6 @@ class TicketPdfService fn (Ticket $ticket): array => [$ticket->id => $this->qrCodeDataUri($ticket->ticket)] ), ])->setPaper('a4'); - - $ticketIds = $tickets->pluck('id')->implode('_'); - - return $pdf->download("tickets_{$ticketIds}.pdf"); } private function qrCodeDataUri(string $value): string diff --git a/resources/views/mail/notifications/tickets-available.blade.php b/resources/views/mail/notifications/tickets-available.blade.php index ab0bb53..ecc06d1 100644 --- a/resources/views/mail/notifications/tickets-available.blade.php +++ b/resources/views/mail/notifications/tickets-available.blade.php @@ -1,5 +1,6 @@

Tus tickets ya están disponibles

Generamos {{ $tickets->count() }} {{ $tickets->count() === 1 ? 'ticket' : 'tickets' }} para la compra #{{ $purchase->id }}.

+

{{ $tickets->count() === 1 ? 'El ticket está adjunto' : 'Los tickets están adjuntos' }} a este correo en formato PDF.

    @foreach ($tickets as $ticket)
  • {{ $ticket->name }}
  • diff --git a/tests/Feature/Notification/NotificationMailServiceTest.php b/tests/Feature/Notification/NotificationMailServiceTest.php index 1f02278..87cdae7 100644 --- a/tests/Feature/Notification/NotificationMailServiceTest.php +++ b/tests/Feature/Notification/NotificationMailServiceTest.php @@ -192,11 +192,16 @@ class NotificationMailServiceTest extends TestCase && str_contains($mail->render(), 'border-top: 4px solid #112233') && ! str_contains($mail->render(), 'border-top: 4px solid #ff7006'); }); - Mail::assertSent(Mailable::class, function (Mailable $mail): bool { + Mail::assertSent(Mailable::class, function (Mailable $mail) use ($ticket): bool { $mail->assertTo('checkout@example.com'); + $attachment = collect($mail->rawAttachments)->firstWhere('name', "tickets_{$ticket->id}.pdf"); return $mail->subject === 'Tus tickets ya están disponibles' && str_contains($mail->render(), 'Entrada general') + && str_contains($mail->render(), 'El ticket está adjunto') + && $attachment !== null + && $attachment['options'] === ['mime' => 'application/pdf'] + && str_starts_with($attachment['data'], '%PDF-') && str_contains($mail->render(), 'border-top: 4px solid #112233') && ! str_contains($mail->render(), 'border-top: 4px solid #ff7006'); });