json(['error' => false, 'data' => $this->serviceProvisioning->getServices($uuid)]); } public function attachService(string $uuid, Request $request): JsonResponse { $data = $request->validate(['service_id' => 'required|integer|exists:services,id']); $service = $this->serviceProvisioning->attachService($uuid, $data['service_id']); return response()->json(['error' => false, 'message' => 'Đã gán dịch vụ cho khách hàng', 'data' => $service]); } public function bulkDeleteServices(string $uuid, Request $request): JsonResponse { $data = $request->validate(['ids' => 'required|array|min:1', 'ids.*' => 'integer']); $deleted = $this->serviceProvisioning->bulkDeleteServices($uuid, $data['ids']); return response()->json(['error' => false, 'message' => "Đã gỡ {$deleted} dịch vụ khỏi khách hàng", 'data' => ['deleted' => $deleted]]); } public function updateService(string $uuid, int $serviceId, Request $request): JsonResponse { $data = $request->validate([ 'server_name' => 'nullable|string|max:255', 'status' => 'nullable|in:pending,active,suspended,expired,cancelled,terminated', 'auto_renew' => 'nullable|boolean', 'started_at' => 'nullable|date', 'expires_at' => 'nullable|date', 'note' => 'nullable|string', 'requirements' => 'nullable|string', 'feedback' => 'nullable|string', 'price' => 'nullable|numeric|min:0', 'billing_cycle' => 'nullable|in:monthly,quarterly,semi_annually,annually,biennially,triennially', 'virtual_machine_id' => 'nullable|integer|exists:virtual_machines,id', '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', ]); $service = $this->serviceProvisioning->updateService($uuid, $serviceId, $data); return response()->json(['error' => false, 'message' => 'Cập nhật dịch vụ thành công', 'data' => $service]); } public function changeServiceIp(string $uuid, int $serviceId, Request $request): JsonResponse { $data = $request->validate(['ip' => 'required|ip']); abort_if(!Service::where('id', $serviceId)->value('vm_id'), 422, 'Dịch vụ chưa gắn VM.'); $service = $this->serviceProvisioning->updateService($uuid, $serviceId, ['vm_ip' => $data['ip']]); return response()->json(['error' => false, 'message' => 'Đã đổi IP thành công', 'data' => $service]); } public function changeServicePort(string $uuid, int $serviceId, Request $request): JsonResponse { $data = $request->validate(['port' => 'required|integer|min:1|max:65535']); abort_if(!Service::where('id', $serviceId)->value('vm_id'), 422, 'Dịch vụ chưa gắn VM.'); $service = $this->serviceProvisioning->updateService($uuid, $serviceId, ['vm_port' => $data['port']]); return response()->json(['error' => false, 'message' => 'Đã đổi port thành công', 'data' => $service]); } public function notifyServiceRenewal(string $uuid, int $serviceId): JsonResponse { AutoEmailGate::markManual(); $this->serviceProvisioning->notifyRenewal($uuid, $serviceId); return response()->json(['error' => false, 'message' => 'Đã gửi thông báo gia hạn đến khách hàng.']); } public function createService(string $uuid, Request $request): JsonResponse { $data = $request->validate([ 'product_id' => 'required|integer|exists:products,id', 'virtual_machine_id' => 'nullable|integer|exists:virtual_machines,id', 'server_name' => 'nullable|string|max:255', 'status' => 'nullable|in:pending,active,suspended,expired,cancelled,terminated', 'auto_renew' => 'nullable|boolean', 'started_at' => 'nullable|date', 'expires_at' => 'nullable|date', 'note' => 'nullable|string', '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', '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', ]); // Upload proof images (chuyển khoản) — I/O ở tầng HTTP, service chỉ nhận đường dẫn đã lưu. if ($data['payment_method'] === 'transfer' && $request->hasFile('proof_images')) { $data['_proof_paths'] = collect($request->file('proof_images')) ->map(fn($file) => $file->store('payment-proofs', 'public')) ->all(); } $service = $this->serviceProvisioning->createService($uuid, $data, $request->ip()); return response()->json(['error' => false, 'message' => 'Service created', 'data' => $service], 201); } public function listAvailableVms(Request $request): JsonResponse { $vms = $this->serviceProvisioning->listAvailableVms(trim((string) $request->get('q', ''))); return response()->json(['error' => false, 'data' => $vms]); } }