Files
portal-api/app/Services/EmailNotificationTemplateRenderer.php
T
2026-08-14 08:45:52 +07:00

161 lines
7.0 KiB
PHP

<?php
namespace App\Services;
use App\Models\EmailNotificationTemplate;
use App\Models\Invoice;
use Illuminate\Support\Facades\View;
class EmailNotificationTemplateRenderer
{
private const BANNERS = [
'vm_credentials' => 'https://res.cloudinary.com/izpast9i/image/upload/v1786503590/email_banner_cloud_vps.png',
];
public function render(EmailNotificationTemplate $tpl, Invoice $invoice, string $companyName = ''): string
{
$blocks = collect($tpl->blocks)
->filter(fn($b) => $b['enabled'] ?? false)
->sortBy('order')
->values();
$bodyHtml = '';
foreach ($blocks as $block) {
$bodyHtml .= $this->renderBlock($block, $invoice, $companyName);
}
$title = $tpl->header_title ?? 'Thông báo hóa đơn';
return $this->wrapLayout($title, $bodyHtml, $companyName, self::BANNERS[$tpl->type] ?? null);
}
/**
* Render a vm_credentials template using the emailData array from SendVmCredentialsEmailJob.
* $emailData keys: company_name, client_name, product_name, product_billing, product_price,
* service_host, service_username, service_port, service_password, os_name, service_due_exp
*/
public function renderVmCredentials(EmailNotificationTemplate $tpl, array $emailData, ?Invoice $invoice = null): string
{
$blocks = collect($tpl->blocks)
->filter(fn($b) => $b['enabled'] ?? false)
->sortBy('order')
->values();
$companyName = $emailData['company_name'] ?? '';
$bodyHtml = '';
foreach ($blocks as $block) {
$bodyHtml .= match ($block['type'] ?? '') {
'greeting' => $this->renderView('emails.partials.greeting', ['name' => $emailData['client_name'] ?? 'Quý khách']),
'vm_credentials' => $this->renderView('emails.partials.vm-credentials', ['fields' => $block['config']['fields'] ?? null, 'data' => $emailData]),
'product_info' => $this->renderView('emails.partials.product-info', ['fields' => $block['config']['fields'] ?? null, 'data' => $emailData]),
'invoice_info' => $invoice ? $this->renderView('emails.partials.invoice-info', ['fields' => $block['config']['fields'] ?? null, 'invoice' => $invoice]) : '',
'order_items' => $invoice ? $this->renderOrderItems($invoice) : '',
'attachments' => $invoice ? $this->renderAttachments($invoice) : '',
'custom_text' => $this->renderView('emails.partials.custom-text', ['content' => $block['config']['content'] ?? '']),
'footer' => $this->renderView('emails.partials.signature', ['companyName' => $companyName]),
default => '',
};
}
$title = $tpl->header_title ?? 'Thông tin truy cập VPS';
return $this->wrapLayout($title, $bodyHtml, $companyName, self::BANNERS[$tpl->type] ?? null);
}
public function renderPreview(EmailNotificationTemplate $tpl): string
{
if ($tpl->type === 'vm_credentials') {
return $this->renderVmCredentials($tpl, $this->sampleVmData(), null);
}
$invoice = $this->sampleInvoice();
return $this->render($tpl, $invoice, 'Công ty Demo');
}
// ─── Block renderers ──────────────────────────────────────────────────────
private function renderBlock(array $block, Invoice $invoice, string $companyName): string
{
return match ($block['type'] ?? '') {
'greeting' => $this->renderView('emails.partials.greeting', ['name' => $invoice->customer?->fullname ?? 'Quý khách']),
'invoice_info' => $this->renderView('emails.partials.invoice-info', ['fields' => $block['config']['fields'] ?? null, 'invoice' => $invoice]),
'customer_info' => $this->renderView('emails.partials.customer-info', ['fields' => $block['config']['fields'] ?? null, 'customer' => $invoice->customer]),
'order_items' => $this->renderOrderItems($invoice),
'attachments' => $this->renderAttachments($invoice),
'custom_text' => $this->renderView('emails.partials.custom-text', ['content' => $block['config']['content'] ?? '']),
'footer' => $this->renderView('emails.partials.signature', ['companyName' => $companyName]),
default => '',
};
}
private function renderOrderItems(Invoice $invoice): string
{
$order = $invoice->order;
if (!$order) return '';
$order->loadMissing('orderItems.product');
return $this->renderView('emails.partials.order-items', ['items' => $order->orderItems]);
}
private function renderAttachments(Invoice $invoice): string
{
$invoice->loadMissing('attachments');
return $this->renderView('emails.partials.attachments', ['attachments' => $invoice->attachments]);
}
private function renderView(string $view, array $data): string
{
return View::make($view, $data)->render();
}
// ─── Layout wrapper ───────────────────────────────────────────────────────
private function wrapLayout(string $title, string $body, string $companyName, ?string $bannerUrl = null): string
{
return View::make('emails.layouts.notification', [
'title' => $title,
'body' => $body,
'companyName' => $companyName ?: config('app.name', 'Thế Giới Số'),
'bannerUrl' => $bannerUrl,
])->render();
}
// ─── Sample data for preview ──────────────────────────────────────────────
private function sampleVmData(): array
{
return [
'company_name' => 'Công ty Demo',
'company_logo' => '',
'client_name' => 'Nguyễn Văn A',
'product_name' => 'VPS Starter',
'product_billing' => 'Hàng tháng',
'product_price' => '420.000',
'service_host' => '203.113.x.x',
'service_username' => 'root',
'service_port' => '22',
'service_password' => 'P@ssw0rd!2026',
'os_name' => 'Ubuntu 22.04 LTS',
'service_due_exp' => date('d/m/Y', strtotime('+1 month')),
];
}
private function sampleInvoice(): Invoice
{
$invoice = new Invoice([
'invoice_number' => 'INV-20260521-00001',
'sub_total' => 420000,
'tax' => 0,
'total' => 420000,
'status' => 2,
'payment_method' => 'credit',
]);
$invoice->created_at = now();
$invoice->due_date = now()->addDays(7)->toDateString();
return $invoice;
}
}