feat(admin): IP pool allocation, billing exports, service attachments

- IP pool: sheet import (xlsx/csv) matched by address, bulk allocate/revoke
  with notification email (ip_allocated/ip_revoked), ip_pool_logs history.
- Orders/invoices: Excel export on branded template (BrandedReportWriter),
  shared billing filters, order item service info in list responses.
- Web design quote Excel export; activity log export.
- Service attachments with copy-to-invoice; deployment invoice attachments.
- Customer email attachments stored on disk and attached by path.
- Admin password change endpoint; user.fullname backfill migration;
  orders.user_id backfill from logs.
- Disable deploy workflow until CI/CD is set up.
- Ignore stored customer email and service attachment uploads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-15 19:58:36 +07:00
co-authored by Claude Opus 5.5
parent ea5697cb81
commit 46aa138eec
95 changed files with 4247 additions and 454 deletions
@@ -118,29 +118,7 @@ final class BillingTemplates
'scenario' => 'domain_order_approved',
'name' => 'Bàn giao tên miền',
'subject' => 'Bàn giao tên miền {{domain_name}} - {{company_name}}',
'body' => T::title('Bàn giao tên miền')
. T::greeting('{{client_name}}')
. T::paragraph('Công ty Cổ phần Giải pháp Công nghệ Thế Giới Số xin chân thành cảm ơn Quý khách đã tin tưởng lựa chọn dịch vụ đăng ký và quản lý tên miền của chúng tôi.')
. T::heading('🌐 Thông tin tên miền')
. T::infoTable([
'Tên miền' => '{{domain_name}}',
'Mã đơn hàng' => '{{order_num}}',
'Ngày đăng ký' => '{{registered_at}}',
'Ngày hết hạn' => '{{expires_at}}',
'NS1' => '{{name_server_1}}',
'NS2' => '{{name_server_2}}',
])
. T::heading('🔐 Thông tin tài khoản quản lý')
. T::infoTable([
'Trang đăng nhập' => '<a href="{{login_url}}" target="_blank" rel="noopener">{{login_url}}</a>',
'Tên đăng nhập' => '{{customer_email}}',
'Mật khẩu' => 'Mật khẩu tài khoản portal của Quý khách',
])
. T::note('Quý khách vui lòng bảo mật thông tin tài khoản. Nếu quên mật khẩu, sử dụng chức năng "Quên mật khẩu" tại trang đăng nhập.')
. '{{kyc_block}}'
. T::heading('📞 Hỗ trợ kỹ thuật 24/7')
. T::supportLine()
. T::paragraph('Một lần nữa, Thế Giới Số xin chân thành cảm ơn sự tin tưởng và đồng hành của Quý khách.'),
'body' => self::domainOrderApprovedBody(),
],
[
'scenario' => 'domain_order_rejected',
@@ -160,4 +138,33 @@ final class BillingTemplates
],
];
}
private static function domainOrderApprovedBody(): string
{
return <<<'HTML'
<p style="font-size:15px;color:#1f2937;margin:0 0 8px">Kính gửi Quý Khách <strong>{{client_name}}</strong>,</p>
<p style="font-size:14px;color:#4b5563;line-height:1.6;margin:0 0 24px">Công ty Cổ phần Giải pháp Công nghệ Thế Giới Số xin chân thành cảm ơn Quý Khách đã tin tưởng lựa chọn dịch vụ đăng ký và quản lý tên miền của chúng tôi.</p>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin-bottom:12px"><tbody><tr><td style="font-size:15px;font-weight:bold;color:#f97316;padding-bottom:10px;border-bottom:2px solid #fed7aa">🌐 I. THÔNG TIN TÊN MIỀN</td></tr></tbody></table>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid #e5e7eb;border-radius:6px;overflow:hidden;margin-bottom:24px;font-size:12.5px"><tbody>
<tr style="background:#fed7aa"><td style="padding:9px 10px;color:#9a3412;font-weight:bold;text-align:center">Tên miền</td><td style="padding:9px 10px;color:#9a3412;font-weight:bold;text-align:center">Ngày đăng ký</td><td style="padding:9px 10px;color:#9a3412;font-weight:bold;text-align:center">Ngày hết hạn</td><td style="padding:9px 10px;color:#9a3412;font-weight:bold;text-align:center">NS1</td><td style="padding:9px 10px;color:#9a3412;font-weight:bold;text-align:center">NS2</td></tr>
<tr style="background:#fff7ed"><td style="padding:9px 10px;color:#111827;font-weight:bold;text-align:center">{{domain_name}}</td><td style="padding:9px 10px;color:#111827;text-align:center">{{registered_at}}</td><td style="padding:9px 10px;color:#9a3412;font-weight:bold;text-align:center">{{expires_at}}</td><td style="padding:9px 10px;color:#111827;text-align:center">{{name_server_1}}</td><td style="padding:9px 10px;color:#111827;text-align:center">{{name_server_2}}</td></tr>
</tbody></table>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin-bottom:12px"><tbody><tr><td style="font-size:15px;font-weight:bold;color:#f97316;padding-bottom:10px;border-bottom:2px solid #fed7aa">🔐 II. THÔNG TIN TÀI KHOẢN QUẢN LÝ</td></tr></tbody></table>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#eff6ff;border:1px solid #bfdbfe;border-radius:6px;margin-bottom:12px"><tbody><tr><td style="padding:16px"><p style="margin:0 0 8px;font-size:13px;color:#374151">🔗 <strong>Trang đăng nhập:</strong> <a href="{{login_url}}" style="color:#c2410c" target="_blank" rel="noopener">{{login_url}}</a></p><p style="margin:0 0 8px;font-size:13px;color:#374151">👤 <strong>Tên đăng nhập:</strong> {{customer_email}}</p><p style="margin:0;font-size:13px;color:#374151">🔑 <strong>Mật khẩu:</strong> Mật khẩu tài khoản portal của Quý Khách</p></td></tr></tbody></table>
<p style="font-size:12.5px;color:#065f46;background:#ecfdf5;border-left:3px solid #6ee7b7;padding:10px 14px;margin:0 0 24px;border-radius:4px">🔒 Quý Khách vui lòng đổi mật khẩu ngay sau lần đăng nhập đầu tiên và bảo mật thông tin tài khoản.</p>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin-bottom:12px"><tbody><tr><td style="font-size:15px;font-weight:bold;color:#f97316;padding-bottom:10px;border-bottom:2px solid #fed7aa">📋 III. LƯU Ý QUAN TRỌNG – XÁC THỰC TÊN MIỀN</td></tr></tbody></table>
<p style="font-size:13.5px;color:#4b5563;line-height:1.7;margin:0 0 16px">Quý Khách cần hoàn tất thủ tục xác thực tên miền theo hướng dẫn để tránh tình trạng gián đoạn dịch vụ do chưa hoàn tất xác thực.</p>
{{kyc_block}}
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#ecfdf5;border:1px solid #a7f3d0;border-radius:6px;margin:0 0 24px"><tbody><tr><td style="padding:16px"><p style="margin:0 0 8px;font-size:13px;color:#065f46;font-weight:bold">📮 Bản gốc vui lòng gửi về:</p><p style="margin:0 0 4px;font-size:13px;color:#374151">CÔNG TY CỔ PHẦN GIẢI PHÁP CÔNG NGHỆ THẾ GIỚI SỐ</p><p style="margin:0 0 4px;font-size:13px;color:#374151">128/38 Tân Hương, Phường Phú Thọ Hòa, TP. Hồ Chí Minh</p><p style="margin:0;font-size:13px;color:#374151">Người nhận: Ms. Vân Anh – 0818 006 119 (P. HCNS)</p></td></tr></tbody></table>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin-bottom:12px"><tbody><tr><td style="font-size:15px;font-weight:bold;color:#f97316;padding-bottom:10px;border-bottom:2px solid #fed7aa">📞 IV. HỖ TRỢ KỸ THUẬT 24/7</td></tr></tbody></table>
<p style="font-size:13.5px;color:#374151;margin:0 0 4px">☎ <strong>Hotline:</strong> (028) 7309 7379</p>
<p style="font-size:13.5px;color:#374151;margin:0 0 24px">✉ <strong>Email:</strong> <a href="mailto:support@tgs.com.vn" style="color:#c2410c">support@tgs.com.vn</a></p>
<p style="font-size:14px;color:#4b5563;line-height:1.6;margin:0">Một lần nữa, Thế Giới Số xin chân thành cảm ơn sự tin tưởng và đồng hành của Quý Khách. Chúng tôi luôn sẵn sàng hỗ trợ để đảm bảo trải nghiệm dịch vụ tốt nhất.</p>
HTML;
}
}