feat: email gửi tay/nhắc gia hạn, gói hosting, sửa dữ liệu sản phẩm

- Gửi email theo template cho 1 khách, tab lịch sử email, nhắc gia hạn dịch vụ hàng loạt
- Mail lưu from/bcc/sent_by; mẫu MARKETING và mẫu cũ trong TemplateSeeder
- Gói hosting: giới hạn, trạng thái, lấy plan Plesk qua CLI gateway
- Backfill payment_method và ngày đơn hàng còn thiếu
- Bổ sung field CPU/RAM/Disk/Băng thông cho loại sản phẩm vps và cloud

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-09 11:32:05 +07:00
co-authored by Claude Opus 5.5
parent 8651dde6b1
commit 30898ea46f
59 changed files with 1771 additions and 108 deletions
@@ -82,7 +82,7 @@ class CustomerServiceProvisioningService
return DB::transaction(function () use ($customer, $service, $data) {
$vmFields = ['virtual_machine_id', 'os_id', 'vm_cpu', 'vm_ram_mb', 'vm_disk_gb', 'vm_ip', 'vm_dns', 'vm_user', 'vm_password', 'vm_port'];
$service->fill(collect($data)->except(['price', ...$vmFields])->all());
$service->fill(collect($data)->except(['price', 'billing_cycle', ...$vmFields])->all());
$service->save();
if (!empty($data['virtual_machine_id'])) {
@@ -93,6 +93,13 @@ class CustomerServiceProvisioningService
$service->orderItem->update(['price' => $data['price']]);
}
if (!empty($data['billing_cycle']) && $service->orderItem) {
$service->orderItem->update([
'billing_cycle' => $data['billing_cycle'],
'months' => OrderHelper::cycleToMonths($data['billing_cycle']),
]);
}
// Đồng bộ sang module_vmware nếu có gán VM
if ($service->vm_id) {
$vmData = array_filter([