Files
portal-api/app/Http/Controllers/Api/Admin/EmailNotificationTemplateController.php
baodev0 520f21cb11 feat: add GeneratesUniqueSlug class for unique slug generation
feat: create PostCategoryFactory for generating post category data

feat: create PostFactory for generating post data

feat: add retry_requested_at column to services table

feat: add vcenter provisioning fields to products table

feat: add module_host_id to os table

feat: create email_notification_templates table for email templates

feat: add scenario and format fields to template table

feat: add admin fields to transactions table

fix: update ticket table columns and types

feat: add uuid to ticket table and backfill existing records

fix: make ticket_reply user_id nullable

feat: create notifications table for user notifications

fix: make ticket uuid nullable

feat: create post_categories table for blog categories

feat: create posts table for blog posts

feat: add invoice email template for PDF generation
2026-05-25 15:39:42 +07:00

128 lines
5.6 KiB
PHP

<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;
use App\Models\EmailNotificationTemplate;
use App\Services\EmailNotificationTemplateRenderer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class EmailNotificationTemplateController extends Controller
{
public function __construct(
private readonly EmailNotificationTemplateRenderer $renderer,
) {}
public function index(): JsonResponse
{
$templates = EmailNotificationTemplate::orderByDesc('is_active')
->orderBy('name')
->get();
return response()->json(['error' => false, 'data' => $templates]);
}
public function show(int $id): JsonResponse
{
$tpl = EmailNotificationTemplate::findOrFail($id);
$tpl['block_field_definitions'] = EmailNotificationTemplate::blockFieldDefinitions();
return response()->json(['error' => false, 'data' => $tpl]);
}
public function store(Request $request): JsonResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'type' => 'required|string|in:invoice_notification,vm_credentials',
'subject' => 'required|string|max:500',
'header_color' => 'nullable|string|max:20',
'header_title' => 'nullable|string|max:255',
'blocks' => 'nullable|array',
'is_active' => 'boolean',
]);
// Use default blocks if none provided
if (empty($validated['blocks'])) {
$validated['blocks'] = EmailNotificationTemplate::defaultBlocks($validated['type']);
}
// If activating this template, deactivate others of the same type
if ($validated['is_active'] ?? true) {
EmailNotificationTemplate::where('type', $validated['type'])->update(['is_active' => false]);
}
$tpl = EmailNotificationTemplate::create($validated);
return response()->json(['error' => false, 'data' => $tpl], 201);
}
public function update(Request $request, int $id): JsonResponse
{
$tpl = EmailNotificationTemplate::findOrFail($id);
$validated = $request->validate([
'name' => 'sometimes|string|max:255',
'subject' => 'sometimes|string|max:500',
'header_color' => 'nullable|string|max:20',
'header_title' => 'nullable|string|max:255',
'blocks' => 'nullable|array',
'is_active' => 'boolean',
]);
// If activating this template, deactivate others of the same type
if (!empty($validated['is_active'])) {
EmailNotificationTemplate::where('type', $tpl->type)
->where('id', '!=', $id)
->update(['is_active' => false]);
}
$tpl->update($validated);
return response()->json(['error' => false, 'data' => $tpl->fresh()]);
}
public function destroy(int $id): JsonResponse
{
EmailNotificationTemplate::findOrFail($id)->delete();
return response()->json(['error' => false, 'message' => 'Đã xoá template.']);
}
public function preview(int $id): JsonResponse
{
$tpl = EmailNotificationTemplate::findOrFail($id);
$html = $this->renderer->renderPreview($tpl);
return response()->json(['error' => false, 'html' => $html]);
}
public function fieldDefinitions(): JsonResponse
{
return response()->json([
'error' => false,
'data' => [
'block_types' => $this->blockTypeDefinitions(),
'block_field_definitions' => EmailNotificationTemplate::blockFieldDefinitions(),
'default_blocks' => EmailNotificationTemplate::defaultBlocks(),
],
]);
}
private function blockTypeDefinitions(): array
{
return [
// Dùng cho cả 2 loại
['type' => 'greeting', 'label' => 'Lời chào', 'description' => 'Chào hỏi khách hàng theo tên', 'for' => ['invoice_notification', 'vm_credentials']],
['type' => 'custom_text', 'label' => 'Văn bản tùy chỉnh', 'description' => 'Nội dung HTML hoặc text tự do', 'for' => ['invoice_notification', 'vm_credentials']],
['type' => 'footer', 'label' => 'Chữ ký kết thúc', 'description' => 'Trân trọng + tên công ty', 'for' => ['invoice_notification', 'vm_credentials']],
// invoice_notification
['type' => 'invoice_info', 'label' => 'Thông tin hóa đơn', 'description' => 'Số HĐ, ngày tạo, tổng tiền, trạng thái...', 'for' => ['invoice_notification']],
['type' => 'customer_info', 'label' => 'Thông tin khách hàng', 'description' => 'Tên, email, địa chỉ khách hàng', 'for' => ['invoice_notification']],
['type' => 'order_items', 'label' => 'Chi tiết sản phẩm', 'description' => 'Bảng sản phẩm từ đơn hàng', 'for' => ['invoice_notification']],
['type' => 'attachments', 'label' => 'File đính kèm', 'description' => 'Danh sách file đính kèm hóa đơn', 'for' => ['invoice_notification']],
// vm_credentials
['type' => 'vm_credentials', 'label' => 'Thông tin truy cập VPS', 'description' => 'IP, username, port, password, OS', 'for' => ['vm_credentials']],
['type' => 'product_info', 'label' => 'Thông tin dịch vụ', 'description' => 'Tên sản phẩm, chu kỳ, giá, hạn dùng', 'for' => ['vm_credentials']],
];
}
}