Files
baodev0andClaude Sonnet 5.5 55a834a2f8 feat: nhắc gia hạn QR theo dịch vụ, failover server hosting, CCCD admin, log cấp phát dịch vụ
- Mail campaign: mẫu nhắc gia hạn thanh toán QR, chọn dịch vụ + chu kỳ từng dòng (renewal_services)
- Hosting: nhiều server Plesk cho một gói (service_plan_servers), chuyển server khi server chết
- Admin xem/sửa giấy tờ định danh khách, tuỳ chọn gia hạn cho khách, nhật ký cấp phát dịch vụ
- Đánh dấu mẫu email dịch vụ là non-marketing

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 18:36:41 +07:00

202 lines
8.2 KiB
PHP

<?php
use App\Http\Controllers\Api\Admin\ActivityLog\ActivityLogController;
use App\Http\Controllers\Api\Admin\Auth\AdminLoginBlockController;
use App\Http\Controllers\Api\Admin\EmailLog\EmailLogController;
use App\Http\Controllers\Api\Admin\EmailTemplate\EmailHealthController;
use App\Http\Controllers\Api\Admin\EmailTemplate\EmailTemplateController;
use App\Http\Controllers\Api\Admin\MailCampaign\MailCampaignController;
use App\Http\Controllers\Api\Admin\Setting\ClientMenuController;
use App\Http\Controllers\Api\Admin\Setting\PopupBannerController;
use App\Http\Controllers\Api\Admin\Setting\VatNumberingController;
use App\Http\Controllers\Api\Admin\Setting\SettingController as AdminSettingController;
use App\Http\Controllers\Api\Admin\Staff\StaffOnlineController;
use App\Http\Controllers\Api\Admin\Ticket\TicketController as AdminTicketController;
use App\Http\Controllers\Api\NotificationController;
use App\Http\Controllers\Api\QueueMonitorController;
use Illuminate\Support\Facades\Route;
// Settings (module: administrator)
Route::prefix('settings')
->controller(AdminSettingController::class)
->middleware('perm:setting.manager')
->group(function () {
Route::post('verify-password', 'verifyPassword')->middleware('throttle:10,1');
Route::get('/', 'index');
Route::put('/', 'update');
Route::post('test-telegram', 'testTelegram');
Route::post('test-smtp', 'testSmtp')->middleware('throttle:10,1');
});
Route::prefix('login-blocks')
->controller(AdminLoginBlockController::class)
->middleware('perm:setting.manager')
->group(function () {
Route::get('/', 'index');
Route::delete('{id}', 'destroy')->whereNumber('id');
});
Route::prefix('client-menu')
->controller(ClientMenuController::class)
->middleware('perm:setting.manager')
->group(function () {
Route::get('/', 'show');
Route::put('/', 'update');
Route::get('quick-links', 'showQuickLinks');
Route::put('quick-links', 'updateQuickLinks');
});
Route::prefix('popup-banners')
->controller(PopupBannerController::class)
->middleware('perm:setting.manager')
->group(function () {
Route::get('/', 'index');
Route::post('/', 'store');
Route::post('{id}', 'update')->whereNumber('id');
Route::delete('{id}', 'destroy')->whereNumber('id');
});
// VAT settings per service type (module: settings)
Route::prefix('vat-settings')
->controller(AdminSettingController::class)
->middleware('perm:setting.manager')
->group(function () {
Route::get('/', 'vatIndex');
Route::put('/', 'vatUpdate');
});
Route::prefix('vat-numbering')
->controller(VatNumberingController::class)
->middleware('perm:setting.manager')
->group(function () {
Route::get('/', 'show');
Route::put('/', 'update');
});
// Dashboard Stats
Route::prefix('dashboard')
->controller(\App\Http\Controllers\Api\Admin\Dashboard\DashboardController::class)
->middleware('perm:dashboard.view')
->group(function () {
Route::get('stats', 'stats');
Route::get('monthly-stats', 'monthlyStats');
Route::get('daily-stats', 'dailyStats');
Route::get('recent-orders', 'recentOrders');
Route::get('recent-deposits', 'recentDeposits');
Route::get('top-services', 'topServices');
Route::get('expiring-services', 'expiringServices');
Route::get('activities', 'activities');
Route::get('latest-customers', 'latestCustomers');
});
// Staff Online
Route::prefix('staff-online')
->controller(StaffOnlineController::class)
->group(function () {
Route::get('/', 'index');
Route::post('ping', 'ping');
});
// Queue Monitor (Horizon)
Route::prefix('queue')
->controller(QueueMonitorController::class)
->middleware('perm:queue.manager')
->group(function () {
Route::get('jobs/recent', 'recent');
Route::get('jobs/pending', 'pending');
Route::get('jobs/failed', 'failed');
Route::post('jobs/failed/{id}/retry', 'retry');
Route::get('jobs/metrics', 'metrics');
Route::get('jobs/{id}', 'show');
});
// Email Templates (module: settings)
Route::prefix('email-templates')
->controller(EmailTemplateController::class)
->middleware('perm:email-template.manager')
->group(function () {
Route::get('/', 'index');
Route::post('/', 'store');
Route::get('health', [EmailHealthController::class, 'show']);
Route::get('scenarios', 'scenarios');
Route::put('scenarios/{key}/label', 'updateScenarioLabel');
Route::get('email-settings', 'getEmailSettings');
Route::put('email-settings', 'updateEmailSettings');
Route::get('{id}', 'show');
Route::put('{id}', 'update');
Route::delete('{id}', 'destroy');
Route::post('{id}/preview', 'preview');
Route::post('{id}/send-test', 'sendTest');
});
// Tickets (support tickets)
Route::prefix('tickets')
->controller(AdminTicketController::class)
->group(function () {
Route::get('/', 'index')->middleware('perm:support.view');
Route::get('pending-count', 'pendingCount')->middleware('perm:support.view');
Route::get('export', 'export')->middleware('perm:support.view');
Route::get('{ticket_num}', 'show')->middleware('perm:support.view');
Route::patch('{ticket_num}/status', 'updateStatus')->middleware('perm:support.edit');
Route::post('{ticket_num}/reply', 'reply')->middleware('perm:support.edit');
});
Route::prefix('notifications')
->controller(NotificationController::class)
->group(function () {
Route::get('/', fn() => app(NotificationController::class)->index(request(), 'admin'));
Route::get(
'{uuid}',
fn($uuid) => app(NotificationController::class)->show(request(), 'admin', $uuid),
)->whereUuid('uuid');
Route::patch(
'{uuid}/read',
fn($uuid) => app(NotificationController::class)->markRead(request(), 'admin', $uuid),
)->whereUuid('uuid');
Route::patch(
'read-all',
fn() => app(NotificationController::class)->markAllRead(request(), 'admin'),
);
});
// Activity Logs
Route::prefix('activity-logs')
->controller(ActivityLogController::class)
->middleware('perm:system-log.manager')
->group(function () {
Route::get('/', 'index');
Route::get('export', 'export');
Route::get('modules', 'modules');
Route::get('stats', 'stats');
Route::delete('/', 'destroy');
Route::get('{id}', 'show');
});
// Email Logs
Route::prefix('email-logs')
->controller(EmailLogController::class)
->middleware('perm:system-log.manager')
->group(function () {
Route::get('/', 'index');
Route::get('{id}', 'show')->whereNumber('id');
});
// Mail Campaigns (module: mail-campaign)
Route::prefix('mail-campaigns')
->controller(MailCampaignController::class)
->group(function () {
Route::get('/', 'index')->middleware('perm:mail-campaign.view');
Route::get('variable-suggestions', 'variableSuggestions')->middleware('perm:mail-campaign.create');
Route::get('sender', 'sender')->middleware('perm:mail-campaign.create');
Route::get('renewal-services', 'renewalServices')->middleware('perm:mail-campaign.create');
Route::post('preview', 'preview')->middleware('perm:mail-campaign.create');
Route::post('resolve-emails', 'resolveEmails')->middleware('perm:mail-campaign.create');
Route::post('bulk-action', 'bulkAction')->middleware('perm:mail-campaign.create');
Route::post('bulk-delete', 'bulkDelete')->middleware('perm:mail-campaign.manager');
Route::get('{uuid}/preview', 'previewCampaign')->middleware('perm:mail-campaign.view');
Route::get('{uuid}/logs/{id}', 'showLog')->whereNumber('id')->middleware('perm:mail-campaign.view');
Route::get('{uuid}/attachments/{index}', 'downloadAttachment')->whereNumber('index')->middleware('perm:mail-campaign.view');
Route::get('{uuid}', 'show')->middleware('perm:mail-campaign.view');
Route::post('/', 'store')->middleware('perm:mail-campaign.create');
});