feat: Enhance service management with VMware integration and update note field to LONGTEXT
This commit is contained in:
@@ -931,7 +931,7 @@ class CustomerController extends Controller
|
||||
{
|
||||
$services = $this->serviceRepository->filter(
|
||||
['customer_uuid' => $uuid],
|
||||
['product', 'orderItem', 'invoice']
|
||||
['product', 'orderItem', 'invoice', 'vmware.os.osGroup']
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
@@ -992,18 +992,45 @@ class CustomerController extends Controller
|
||||
'started_at' => 'nullable|date',
|
||||
'expires_at' => 'nullable|date',
|
||||
'note' => 'nullable|string',
|
||||
// module_vmware fields
|
||||
'os_id' => 'nullable|integer|exists:os,id',
|
||||
'vm_cpu' => 'nullable|integer|min:1',
|
||||
'vm_ram_mb' => 'nullable|integer|min:1',
|
||||
'vm_disk_gb' => 'nullable|integer|min:1',
|
||||
'vm_ip' => 'nullable|string|max:45',
|
||||
'vm_dns' => 'nullable|string|max:100',
|
||||
'vm_user' => 'nullable|string|max:255',
|
||||
'vm_password' => 'nullable|string|max:255',
|
||||
'vm_port' => 'nullable|integer|min:1|max:65535',
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$service->fill($data);
|
||||
$service->fill(collect($data)->except([
|
||||
'os_id', 'vm_cpu', 'vm_ram_mb', 'vm_disk_gb', 'vm_ip', 'vm_dns', 'vm_user', 'vm_password', 'vm_port',
|
||||
])->all());
|
||||
$service->save();
|
||||
|
||||
// Đồng bộ hostname sang module_vmware nếu có gán VM
|
||||
if ($service->vm_id && array_key_exists('server_name', $data)) {
|
||||
\App\Models\ModuleVmware::where('id', $service->vm_id)
|
||||
->update(['hostname' => $data['server_name']]);
|
||||
// Đồng bộ sang module_vmware nếu có gán VM
|
||||
if ($service->vm_id) {
|
||||
$vmData = array_filter([
|
||||
'hostname' => $data['server_name'] ?? null,
|
||||
'os_id' => $data['os_id'] ?? null,
|
||||
'cpu' => $data['vm_cpu'] ?? null,
|
||||
'ram_mb' => $data['vm_ram_mb'] ?? null,
|
||||
'disk_gb' => $data['vm_disk_gb'] ?? null,
|
||||
'ip' => $data['vm_ip'] ?? null,
|
||||
'dns' => $data['vm_dns'] ?? null,
|
||||
'user' => $data['vm_user'] ?? null,
|
||||
'password' => $data['vm_password'] ?? null,
|
||||
'plain_password' => $data['vm_password'] ?? null,
|
||||
'port' => $data['vm_port'] ?? null,
|
||||
], fn ($v) => $v !== null);
|
||||
|
||||
if ($vmData) {
|
||||
\App\Models\ModuleVmware::where('id', $service->vm_id)->update($vmData);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
@@ -1011,7 +1038,7 @@ class CustomerController extends Controller
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Cập nhật dịch vụ thành công',
|
||||
'data' => $service->load(['product', 'orderItem', 'invoice']),
|
||||
'data' => $service->load(['product', 'orderItem', 'invoice', 'vmware.os.osGroup']),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
@@ -1043,8 +1070,19 @@ class CustomerController extends Controller
|
||||
// New: billing & payment
|
||||
'billing_cycle' => 'nullable|in:monthly,quarterly,semi_annually,annually,biennially,triennially',
|
||||
'payment_method' => 'required|in:transfer,balance',
|
||||
'amount_paid' => 'nullable|numeric|min:0',
|
||||
'proof_images' => 'nullable|array',
|
||||
'proof_images.*' => 'file|image|max:5120',
|
||||
// module_vmware fields — admin can override the vCenter snapshot / fill in what's not tracked there (disk, OS, credentials, port)
|
||||
'os_id' => 'nullable|integer|exists:os,id',
|
||||
'vm_cpu' => 'nullable|integer|min:1',
|
||||
'vm_ram_mb' => 'nullable|integer|min:1',
|
||||
'vm_disk_gb' => 'nullable|integer|min:1',
|
||||
'vm_ip' => 'nullable|string|max:45',
|
||||
'vm_dns' => 'nullable|string|max:100',
|
||||
'vm_user' => 'nullable|string|max:255',
|
||||
'vm_password' => 'nullable|string|max:255',
|
||||
'vm_port' => 'nullable|integer|min:1|max:65535',
|
||||
]);
|
||||
|
||||
$product = \App\Models\Product::with('pricings')->find($data['product_id']);
|
||||
@@ -1061,7 +1099,10 @@ class CustomerController extends Controller
|
||||
$pricing = $product->pricings
|
||||
->where('billing_cycle', $billingCycle)
|
||||
->first();
|
||||
$basePrice = (int) ($pricing->price ?? 0);
|
||||
// Số tiền đã thanh toán: admin nhập tay để khớp với thực tế (có thể lệch giá niêm yết do khuyến mãi/thoả thuận)
|
||||
$basePrice = isset($data['amount_paid'])
|
||||
? (int) $data['amount_paid']
|
||||
: (int) ($pricing->price ?? 0);
|
||||
|
||||
$paymentMethod = $data['payment_method'];
|
||||
|
||||
@@ -1088,32 +1129,7 @@ class CustomerController extends Controller
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
// 1) ModuleVmware: snapshot từ virtual_machines
|
||||
$vmId = null;
|
||||
if (!empty($data['virtual_machine_id'])) {
|
||||
$vm = \App\Models\VirtualMachines::with('datacenter')
|
||||
->find($data['virtual_machine_id']);
|
||||
|
||||
$vcenterId = $vm->datacenter->vcenter_id ?? null;
|
||||
|
||||
$moduleVm = \App\Models\ModuleVmware::updateOrCreate(
|
||||
['virtual_machine_id' => $vm->id],
|
||||
[
|
||||
'customer_id' => $customer->id,
|
||||
'name' => $vm->name,
|
||||
'vmware_id' => $vm->vm_id,
|
||||
'vcenter_id' => $vcenterId,
|
||||
'hostname' => $data['server_name'] ?? $vm->name,
|
||||
'cpu' => $vm->cpu,
|
||||
'ram_mb' => $vm->ram_mb,
|
||||
'disk_gb' => $vm->disk_gb ?? null,
|
||||
'status' => 1,
|
||||
]
|
||||
);
|
||||
$vmId = $moduleVm->id;
|
||||
}
|
||||
|
||||
// 2) Order + OrderItem (mô phỏng flow customer đặt hàng)
|
||||
// 1) Order + OrderItem (mô phỏng flow customer đặt hàng)
|
||||
$order = Order::create([
|
||||
'order_num' => OrderHelper::generateOrderNumber(),
|
||||
'customer_id' => $customer->id,
|
||||
@@ -1135,6 +1151,41 @@ class CustomerController extends Controller
|
||||
'price' => $basePrice,
|
||||
]);
|
||||
|
||||
// 2) ModuleVmware: snapshot từ virtual_machines. `order_id` phải trỏ về
|
||||
// order vừa tạo — client console-ticket/rebuild resolve VM qua
|
||||
// service->orderItem->order->vmWare, không qua services.vm_id.
|
||||
$vmId = null;
|
||||
if (!empty($data['virtual_machine_id'])) {
|
||||
$vm = \App\Models\VirtualMachines::with('datacenter')
|
||||
->find($data['virtual_machine_id']);
|
||||
|
||||
$vcenterId = $vm->datacenter->vcenter_id ?? null;
|
||||
|
||||
$moduleVm = \App\Models\ModuleVmware::updateOrCreate(
|
||||
['virtual_machine_id' => $vm->id],
|
||||
[
|
||||
'customer_id' => $customer->id,
|
||||
'order_id' => $order->id,
|
||||
'name' => $vm->name,
|
||||
'vmware_id' => $vm->vm_id,
|
||||
'vcenter_id' => $vcenterId,
|
||||
'hostname' => $data['server_name'] ?? $vm->name,
|
||||
'cpu' => $data['vm_cpu'] ?? $vm->cpu,
|
||||
'ram_mb' => $data['vm_ram_mb'] ?? $vm->ram_mb,
|
||||
'disk_gb' => $data['vm_disk_gb'] ?? null,
|
||||
'os_id' => $data['os_id'] ?? null,
|
||||
'ip' => $data['vm_ip'] ?? $vm->ip,
|
||||
'dns' => $data['vm_dns'] ?? null,
|
||||
'user' => $data['vm_user'] ?? null,
|
||||
'password' => $data['vm_password'] ?? null,
|
||||
'plain_password' => $data['vm_password'] ?? null,
|
||||
'port' => $data['vm_port'] ?? null,
|
||||
'status' => 1,
|
||||
]
|
||||
);
|
||||
$vmId = $moduleVm->id;
|
||||
}
|
||||
|
||||
// 3) Invoice — đánh dấu PAID luôn vì admin đứng ra tạo & xác nhận thanh toán
|
||||
$invoice = Invoice::create([
|
||||
'invoice_number' => OrderHelper::generateOrderNumber('INV'),
|
||||
@@ -1217,7 +1268,7 @@ class CustomerController extends Controller
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Service created',
|
||||
'data' => $service->load(['product']),
|
||||
'data' => $service->load(['product', 'vmware.os.osGroup']),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
@@ -1244,16 +1295,24 @@ class CustomerController extends Controller
|
||||
->get()
|
||||
->keyBy('virtual_machine_id');
|
||||
|
||||
$vms = DB::table('virtual_machines')
|
||||
->select('id', 'vm_id', 'name', 'power_state', 'cpu', 'ram_mb', 'ip')
|
||||
->where('is_template', 0)
|
||||
->where('is_system', 0)
|
||||
$vms = DB::table('virtual_machines as vm')
|
||||
->leftJoin('module_datacenter as dc', 'dc.id', '=', 'vm.datacenter_id')
|
||||
->leftJoin('module_host as h', 'h.id', '=', 'vm.host_id')
|
||||
->leftJoin('module_vcenter as vc', 'vc.id', '=', 'dc.vcenter_id')
|
||||
->select(
|
||||
'vm.id', 'vm.vm_id', 'vm.name', 'vm.power_state', 'vm.cpu', 'vm.ram_mb', 'vm.ip',
|
||||
'vc.host as vcenter_name',
|
||||
'dc.name as datacenter_name',
|
||||
'h.name as host_name',
|
||||
)
|
||||
->where('vm.is_template', 0)
|
||||
->where('vm.is_system', 0)
|
||||
->when($search, fn ($q) => $q->where(function ($w) use ($search) {
|
||||
$w->where('name', 'like', "%{$search}%")
|
||||
->orWhere('vm_id', 'like', "%{$search}%")
|
||||
->orWhere('ip', 'like', "%{$search}%");
|
||||
$w->where('vm.name', 'like', "%{$search}%")
|
||||
->orWhere('vm.vm_id', 'like', "%{$search}%")
|
||||
->orWhere('vm.ip', 'like', "%{$search}%");
|
||||
}))
|
||||
->orderBy('name')
|
||||
->orderBy('vm.name')
|
||||
->limit(200)
|
||||
->get()
|
||||
->map(function ($vm) use ($assignments) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
// ponytail: raw SQL instead of Schema::table()->change() — this repo doesn't have doctrine/dbal installed
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
DB::statement('ALTER TABLE services MODIFY note LONGTEXT NULL');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::statement('ALTER TABLE services MODIFY note TEXT NULL');
|
||||
}
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
Reference in New Issue
Block a user