activeTemplate(); $fallbackSubject = $this->type === 'renewal' ? "Thông báo gia hạn cước #{$this->invoice->invoice_number} - {$this->companyName}" : "Thông báo hóa đơn #{$this->invoice->invoice_number} - {$this->companyName}"; $subject = $tpl ? $this->resolveSubject($tpl->subject) : $fallbackSubject; return new Envelope(subject: $subject); } public function content(): Content { $tpl = $this->activeTemplate(); if ($tpl) { try { $renderer = app(EmailNotificationTemplateRenderer::class); $html = $renderer->render( $tpl, $this->invoice->load(['order.orderItems.product', 'customer', 'attachments']), $this->companyName ); return new Content(htmlString: $html); } catch (\Throwable $e) { Log::warning('InvoiceNotificationMail: renderer failed, falling back to blade', [ 'template_id' => $tpl->id, 'error' => $e->getMessage(), ]); } } return new Content( view: 'emails.invoice-notification', with: [ 'invoice' => $this->invoice, 'attachments' => $this->invoiceAttachments, 'customerName' => $this->customerName, 'bodyMessage' => $this->message, 'companyName' => $this->companyName, 'type' => $this->type, 'paymentUrl' => $this->paymentUrl, ] ); } public function attachments(): array { if ($this->invoicePdf !== null && $this->invoicePdfFileName !== null) { return [ Attachment::fromData(fn() => $this->invoicePdf, $this->invoicePdfFileName) ->withMime('application/pdf'), ]; } return []; } private function activeTemplate(): ?EmailNotificationTemplate { return EmailNotificationTemplate::where('type', 'invoice_notification') ->where('is_active', true) ->first(); } private function resolveSubject(string $subject): string { return str_replace( ['{{invoice_number}}', '{{company_name}}'], [$this->invoice->invoice_number ?? '', $this->companyName], $subject ); } }