From 21a2dfe8555689af572e9f874557d81062115aca Mon Sep 17 00:00:00 2001 From: Pham Bao Date: Tue, 29 Jul 2025 22:49:14 +0700 Subject: [PATCH] update bug --- app/Http/Services/vCenter.php | 108 +++++++ .../VirtualMachine/Create/AssignIPJob.php | 245 +++++++++++++++ .../Create/CreateVirtualMachineJob.php | 293 ++++++++++-------- .../VirtualMachine/ProcessOrderPaymentJob.php | 27 +- package-lock.json | 2 +- public/js/bootstrap.min.js | 2 +- public/js/cart-skeleton.min.js | 2 +- public/js/core.min.js | 2 +- public/js/main.min.js | 2 +- public/js/service/service.min.js | 2 +- public/js/service/service.min.js.LICENSE.txt | 1 - public/js/service/vminfo.min.js | 2 +- public/js/whois.min.js | 2 +- resources/js/service/service.js | 4 +- .../views/frontend/invoice/show.blade.php | 4 +- 15 files changed, 540 insertions(+), 158 deletions(-) create mode 100644 app/Jobs/VirtualMachine/Create/AssignIPJob.php delete mode 100644 public/js/service/service.min.js.LICENSE.txt diff --git a/app/Http/Services/vCenter.php b/app/Http/Services/vCenter.php index 83780e2..bed3268 100644 --- a/app/Http/Services/vCenter.php +++ b/app/Http/Services/vCenter.php @@ -2124,6 +2124,114 @@ class vCenter } } + /** + * Assign IP to Windows VM using PowerShell script + */ + public function assignIPWindows($product, $vmware_id = ''): array|string + { + try { + // Kiểm tra null safety + if (!$product || !$product->ipAddress || !$product->ipAddress->host || !$product->ipAddress->host->datacenter || !$product->ipAddress->host->datacenter->vCenter) { + Log::error('❌ assignIPWindows: Missing required data', [ + 'vmware_id' => $vmware_id, + 'product_id' => $product?->id ?? 'unknown', + 'ip_address' => $product?->ipAddress?->ip ?? 'unknown', + 'host' => $product?->ipAddress?->host?->name ?? 'unknown', + 'datacenter' => $product?->ipAddress?->host?->datacenter?->name ?? 'unknown', + 'vcenter' => $product?->ipAddress?->host?->datacenter?->vCenter?->host ?? 'unknown' + ]); + return [ + 'error' => true, + 'data' => 'Missing required data for IP assignment' + ]; + } + + $this->SetConfig($product->ipAddress->host->datacenter->vCenter); + + $vmware_name = (string) $product->name; + $ipAddress = $product->ipAddress->ip; + $gateway = $product->ipAddress->gateway; + $netmask = $product->ipAddress->netmask ?? '255.255.255.0'; + $dns = $product->ipAddress->dns ?? '8.8.8.8'; + + // Convert netmask to prefix length (e.g., 255.255.255.0 = 24) + $maskBits = $this->convertNetmaskToPrefixLength($netmask); + + Log::channel('Custom')->info("==================================================================="); + Log::channel('Custom')->info("Assign IP to Windows VM - $vmware_name"); + Log::channel('Custom')->info("IP: $ipAddress, Gateway: $gateway, DNS: $dns, MaskBits: $maskBits"); + Log::channel('Custom')->info("\r\n"); + + // Create PowerShell command with dynamic values + $Command = "\$vmName = '$vmware_name'; \$IP = '$ipAddress'; \$MaskBits = $maskBits; \$Gateway = '$gateway'; \$DNS = '$dns'; cd /; C:\CLISave\AssignIP\assignIPWindows.ps1;"; + + Log::channel('Custom')->info("Executing Command: $Command"); + + $output = $this->Command($Command); + + Log::channel('Custom')->info("Script output: " . $output); + Log::channel('Custom')->info("==================================================================="); + + // Check if execution was successful + if (strpos($output, '🎉') !== false || strpos($output, 'successfully') !== false) { + return [ + 'error' => false, + 'data' => 'IP assigned successfully', + 'output' => $output + ]; + } else { + return [ + 'error' => true, + 'data' => 'Failed to assign IP', + 'output' => $output + ]; + } + + } catch (\Exception $e) { + Log::channel('Custom')->error("Exception in assignIPWindows: " . $e->getMessage()); + return [ + 'error' => true, + 'data' => $e->getMessage() + ]; + } + } + + /** + * Convert netmask to prefix length (e.g., 255.255.255.0 = 24) + */ + private function convertNetmaskToPrefixLength($netmask): int + { + $netmaskMap = [ + '255.255.255.255' => 32, + '255.255.255.254' => 31, + '255.255.255.252' => 30, + '255.255.255.248' => 29, + '255.255.255.240' => 28, + '255.255.255.224' => 27, + '255.255.255.192' => 26, + '255.255.255.128' => 25, + '255.255.255.0' => 24, + '255.255.254.0' => 23, + '255.255.252.0' => 22, + '255.255.248.0' => 21, + '255.255.240.0' => 20, + '255.255.224.0' => 19, + '255.255.192.0' => 18, + '255.255.128.0' => 17, + '255.255.0.0' => 16, + '255.254.0.0' => 15, + '255.252.0.0' => 14, + '255.248.0.0' => 13, + '255.240.0.0' => 12, + '255.224.0.0' => 11, + '255.192.0.0' => 10, + '255.128.0.0' => 9, + '255.0.0.0' => 8 + ]; + + return $netmaskMap[$netmask] ?? 24; // Default to /24 if not found + } + /** * Parse snapshot output from PowerShell text format */ diff --git a/app/Jobs/VirtualMachine/Create/AssignIPJob.php b/app/Jobs/VirtualMachine/Create/AssignIPJob.php new file mode 100644 index 0000000..9831e49 --- /dev/null +++ b/app/Jobs/VirtualMachine/Create/AssignIPJob.php @@ -0,0 +1,245 @@ +vmId = $vmId; + $this->moduleVmwareId = $moduleVmwareId; + $this->availableIP = $availableIP; + } + + /** + * Execute the job. + */ + public function handle(vCenter $vCenter, Telegram $telegram) + { + try { + Log::info('🔧 Bắt đầu AssignIPJob', [ + 'vm_id' => $this->vmId, + 'module_vmware_id' => $this->moduleVmwareId, + 'assigned_ip' => $this->availableIP + ]); + + // Lấy thông tin ModuleVmware + $moduleVmware = ModuleVmware::with(['ipAddress.host.datacenter.vCenter'])->find($this->moduleVmwareId); + + if (!$moduleVmware || !$moduleVmware->ipAddress) { + Log::error('❌ Không tìm thấy ModuleVmware hoặc IP address', [ + 'vm_id' => $this->vmId, + 'module_vmware_id' => $this->moduleVmwareId + ]); + + $telegram->SendErrorMessage([ + 'error' => 'ModuleVmware or IP address not found', + 'vm_id' => $this->vmId, + 'module_vmware_id' => $this->moduleVmwareId + ], 'AssignIPJob - Data Not Found'); + + return; + } + + // Login vào vCenter + $vcenter = $moduleVmware->ipAddress->host->datacenter->vCenter; + if (!$vCenter->loginServer($vcenter)) { + Log::error('❌ Không thể login vào vCenter cho AssignIP', [ + 'vm_id' => $this->vmId, + 'vcenter_host' => $vcenter->host + ]); + + $telegram->SendErrorMessage([ + 'error' => 'Cannot login to vCenter', + 'vm_id' => $this->vmId, + 'vcenter_host' => $vcenter->host + ], 'AssignIPJob - vCenter Login Failed'); + + return; + } + + // Kiểm tra OS family và assign IP + $this->handleIPAssignment($vCenter, $this->vmId, $moduleVmware, $this->availableIP, $telegram); + + } catch (\Throwable $e) { + Log::error('❌ Lỗi trong AssignIPJob: ' . $e->getMessage(), [ + 'vm_id' => $this->vmId, + 'module_vmware_id' => $this->moduleVmwareId, + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + $telegram->SendErrorMessage([ + 'error' => $e->getMessage(), + 'vm_id' => $this->vmId, + 'module_vmware_id' => $this->moduleVmwareId, + 'file' => $e->getFile(), + 'line' => $e->getLine() + ], 'AssignIPJob - Exception'); + } + } + + /** + * Handle IP assignment based on OS family + */ + private function handleIPAssignment(vCenter $vCenter, string $vmId, ModuleVmware $moduleVmware, string $availableIP, Telegram $telegram): void + { + try { + // Kiểm tra OS family trước khi assign IP + $osFamily = $this->checkVMOSFamily($vCenter, $vmId); + + if ($osFamily === 'WINDOWS') { + Log::info('✅ Phát hiện Windows VM, bắt đầu assign IP', [ + 'vm_id' => $vmId, + 'os_family' => $osFamily, + 'assigned_ip' => $availableIP + ]); + + // Assign IP cho Windows VM + $assignIPResult = $vCenter->assignIPWindows($moduleVmware, $vmId); + + if (is_array($assignIPResult) && !$assignIPResult['error']) { + Log::info('✅ Assign IP Windows thành công', [ + 'vm_id' => $vmId, + 'result' => $assignIPResult['data'] + ]); + + $telegram->SendJobRunInfo( + 'AssignIPWindows', + 'success', + [ + 'vm_id' => $vmId, + 'assigned_ip' => $availableIP, + 'result' => $assignIPResult['data'] + ] + ); + } else { + Log::warning('⚠️ Assign IP Windows thất bại', [ + 'vm_id' => $vmId, + 'error' => $assignIPResult['data'] ?? 'Unknown error' + ]); + + $telegram->SendErrorMessage([ + 'error' => 'Assign IP Windows failed', + 'vm_id' => $vmId, + 'details' => $assignIPResult['data'] ?? 'Unknown error' + ], 'AssignIPWindows - Failed'); + } + } elseif ($osFamily === 'LINUX' || $osFamily === 'OTHER') { + Log::info('ℹ️ Phát hiện non-Windows VM, hệ thống đang nâng cấp', [ + 'vm_id' => $vmId, + 'os_family' => $osFamily + ]); + + $telegram->SendJobRunInfo( + 'AssignIP', + 'upgrade', + [ + 'vm_id' => $vmId, + 'os_family' => $osFamily, + 'message' => 'Hệ thống đang nâng cấp để hỗ trợ IP assignment cho ' . $osFamily + ] + ); + } else { + Log::warning('⚠️ Không thể xác định OS family', [ + 'vm_id' => $vmId, + 'os_family' => $osFamily + ]); + + $telegram->SendErrorMessage([ + 'error' => 'Cannot determine OS family', + 'vm_id' => $vmId, + 'os_family' => $osFamily + ], 'AssignIP - Unknown OS'); + } + } catch (\Exception $e) { + Log::error('❌ Lỗi khi handle IP assignment: ' . $e->getMessage(), [ + 'vm_id' => $vmId, + 'error' => $e->getMessage() + ]); + + $telegram->SendErrorMessage([ + 'error' => 'IP Assignment handling failed', + 'vm_id' => $vmId, + 'details' => $e->getMessage() + ], 'HandleIPAssignment - Exception'); + } + } + + /** + * Check VM OS family using vCenter API + */ + private function checkVMOSFamily(vCenter $vCenter, string $vmId): string + { + try { + // Kiểm tra session còn valid không + $check = $vCenter->checkApiExits(); + if (!$check) { + Log::warning('vCenter session expired, cannot check OS family'); + return 'UNKNOWN'; + } + + // Gọi API để lấy guest identity + $response = Http::withoutVerifying() + ->withHeaders([ + 'vmware-api-session-id' => $vCenter->token + ]) + ->get("https://{$vCenter->apiUri}/rest/vcenter/vm/{$vmId}/guest/identity"); + + if ($response->successful()) { + $data = $response->json(); + + if (isset($data['value']['family'])) { + $family = strtoupper($data['value']['family']); + + Log::info('✅ Phát hiện OS family', [ + 'vm_id' => $vmId, + 'family' => $family, + 'full_name' => $data['value']['full_name'] ?? 'Unknown' + ]); + + return $family; + } else { + Log::warning('⚠️ Không tìm thấy family trong response', [ + 'vm_id' => $vmId, + 'response' => $data + ]); + return 'UNKNOWN'; + } + } else { + Log::warning('⚠️ API call thất bại khi check OS family', [ + 'vm_id' => $vmId, + 'status' => $response->status(), + 'response' => $response->body() + ]); + return 'UNKNOWN'; + } + } catch (\Exception $e) { + Log::error('❌ Exception khi check OS family: ' . $e->getMessage(), [ + 'vm_id' => $vmId, + 'error' => $e->getMessage() + ]); + return 'UNKNOWN'; + } + } +} \ No newline at end of file diff --git a/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php b/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php index 26069ec..5929b57 100644 --- a/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php +++ b/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php @@ -3,18 +3,23 @@ namespace App\Jobs\VirtualMachine\Create; use App\Http\Facade\SignRSA; -use App\Http\Services\Discord; +use App\Http\Services\Telegram; use App\Http\Services\vCenter; use App\Jobs\Mail\Customer\VMCreationFailedJob; +use App\Jobs\VirtualMachine\Create\AssignIPJob; +use App\Jobs\VirtualMachine\Create\ConfigCLICommand; use App\Models\OrderItem; use App\Models\Os; -use App\Services\VMDataService; +use App\Models\ModuleVmware; +use App\Models\ModuleIpAddress; +use App\Models\IpPool; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Http; class CreateVirtualMachineJob implements ShouldQueue { @@ -35,7 +40,7 @@ class CreateVirtualMachineJob implements ShouldQueue /** * Execute the job. */ - public function handle(vCenter $vCenter, Discord $discord, VMDataService $vmDataService) + public function handle(vCenter $vCenter, Telegram $telegram) { try { $product = $this->item->getProductAttribute(); // dùng helper trong OrderItem @@ -43,7 +48,7 @@ class CreateVirtualMachineJob implements ShouldQueue if (!$product) { $errorMessage = "Không tìm thấy sản phẩm từ OrderItem #{$this->item->id}"; Log::warning($errorMessage); - $discord->SendErrorMessage($errorMessage, 'CreateVirtualMachineJob - Missing Product'); + $telegram->SendErrorMessage($errorMessage, 'CreateVirtualMachineJob - Missing Product'); if (!$this->isRetry) { $this->sendFailureNotification($errorMessage); @@ -60,7 +65,7 @@ class CreateVirtualMachineJob implements ShouldQueue if (!$vcenter || !$host || !$datacenter) { $errorMessage = "Thiếu thông tin host/datacenter/vcenter từ sản phẩm ID #{$product->id}"; Log::error($errorMessage); - $discord->SendErrorMessage([ + $telegram->SendErrorMessage([ 'error' => $errorMessage, 'product_id' => $product->id, 'order_item_id' => $this->item->id, @@ -79,7 +84,7 @@ class CreateVirtualMachineJob implements ShouldQueue if (!$vCenter->loginServer($vcenter)) { $errorMessage = "Login vào vCenter thất bại với host: {$vcenter->host}"; Log::error($errorMessage); - $discord->SendErrorMessage([ + $telegram->SendErrorMessage([ 'error' => $errorMessage, 'vcenter_host' => $vcenter->host, 'vcenter_user' => $vcenter->user, @@ -102,70 +107,28 @@ class CreateVirtualMachineJob implements ShouldQueue // Lấy addon từ order item if ($this->item->addons) { - Log::info("🔍 Tìm thấy addons cho order item", [ - 'order_item_id' => $this->item->id, - 'addons_count' => $this->item->addons->count(), - 'addons' => $this->item->addons->map(function($addon) { - return [ - 'id' => $addon->id, - 'addon_id' => $addon->addon_id, - 'qty' => $addon->qty, - 'price' => $addon->price, - 'addon_name' => $addon->addonItems?->name ?? 'Unknown' - ]; - }) - ]); - foreach ($this->item->addons as $orderAddon) { $addon = $orderAddon->addonItems; - if (!$addon) { - Log::warning("⚠️ Addon không tìm thấy addonItems", [ - 'order_addon_id' => $orderAddon->id, - 'addon_id' => $orderAddon->addon_id - ]); - continue; - } + if (!$addon) continue; $addonName = strtolower(trim($addon->name)); $quantity = (int) $orderAddon->qty; - Log::info("🔍 Xử lý addon", [ - 'addon_name' => $addon->name, - 'addon_name_lower' => $addonName, - 'quantity' => $quantity, - 'addon_id' => $addon->id - ]); - switch ($addonName) { case 'cpu': $addonData['cpu'] += $quantity; - Log::info("✅ Thêm CPU addon: +{$quantity}"); break; case 'ram': $addonData['ram'] += $quantity; - Log::info("✅ Thêm RAM addon: +{$quantity}GB"); break; case 'disk': case 'ssd': $addonData['disk'] += $quantity; - Log::info("✅ Thêm Disk addon: +{$quantity}GB"); - break; - default: - Log::warning("⚠️ Addon không được nhận diện: {$addonName}"); break; } } - } else { - Log::info("ℹ️ Không có addons cho order item {$this->item->id}"); } - Log::info('📊 Thông tin addon được xử lý', [ - 'order_item_id' => $this->item->id, - 'addon_data' => $addonData, - 'addons_count' => $this->item->addons?->count() ?? 0, - 'has_addons' => !empty($addonData) && array_sum($addonData) > 0 - ]); - $result = $vCenter->CreateVirtualMachine([ 'item' => $this->item, 'host' => $host, @@ -194,7 +157,7 @@ class CreateVirtualMachineJob implements ShouldQueue if (is_array($result) && ($result['error'] ?? false)) { $errorMessage = 'Tạo máy ảo thất bại: ' . json_encode($result); Log::warning($errorMessage); - $discord->SendErrorMessage([ + $telegram->SendErrorMessage([ 'error' => $result['error'] ?? 'Unknown error', 'result' => $result, 'product_id' => $product->id, @@ -211,7 +174,7 @@ class CreateVirtualMachineJob implements ShouldQueue } elseif ($result === 'Login_Again') { $errorMessage = 'Tạo máy ảo thất bại: cần đăng nhập lại.'; Log::error($errorMessage); - $discord->SendErrorMessage([ + $telegram->SendErrorMessage([ 'error' => $errorMessage, 'product_id' => $product->id, 'order_item_id' => $this->item->id, @@ -234,91 +197,86 @@ class CreateVirtualMachineJob implements ShouldQueue $invoice = \App\Models\Invoice::where('order_id', $this->item->order->id)->first(); if ($invoice) { $invoice->update(['vm_id' => $vmId]); - Log::info('✅ Đã lưu vm_id vào bảng invoice', [ - 'vm_id' => $vmId, - 'invoice_id' => $invoice->id, - 'order_id' => $this->item->order->id - ]); - } else { - Log::warning('⚠️ Không tìm thấy invoice cho order', [ - 'order_id' => $this->item->order->id, - 'vm_id' => $vmId - ]); } - // Start VM ngay sau khi tạo thành công - Log::info('🚀 Bắt đầu khởi động VM sau khi tạo thành công', [ - 'vm_id' => $vmId, - 'order_item_id' => $this->item->id - ]); - - $startResult = $vCenter->StartVirtualMachine($vmId); - - if ($startResult === 'Login_Again') { - // Thử đăng nhập lại và start VM - Log::info('🔄 Thử đăng nhập lại vCenter để start VM', [ - 'vm_id' => $vmId, - 'vcenter_host' => $vcenter->host - ]); - - if ($vCenter->loginServer($vcenter)) { - $startResult = $vCenter->StartVirtualMachine($vmId); - Log::info('✅ Đăng nhập lại thành công, thử start VM lần nữa', [ - 'vm_id' => $vmId, - 'start_result' => $startResult - ]); - } else { - Log::error('❌ Không thể đăng nhập lại vCenter để start VM', [ - 'vm_id' => $vmId, - 'vcenter_host' => $vcenter->host - ]); - } - } + // Start VM ngay sau khi tạo thành công (sử dụng API trực tiếp) + $startResult = $this->startVirtualMachineDirectly($vCenter, $vmId); if (is_array($startResult) && $startResult['error'] === false) { - Log::info('✅ Khởi động VM thành công', [ - 'vm_id' => $vmId, - 'order_item_id' => $this->item->id, - 'result' => $startResult['data'] - ]); - // Dispatch ConfigCLICommand để cấu hình VM và lấy password $configJob = new ConfigCLICommand($vmId, $this->item, $vCenter); dispatch($configJob)->delay(now()->addMinutes(2)); // Chờ 2 phút để VM boot hoàn toàn + } + + // Lưu dữ liệu VM vào database + try { + $customer = $this->item->order->customer; + $serverName = $this->item->server_name ?? 'VM-' . $vmId; - Log::info('✅ Đã dispatch ConfigCLICommand job', [ - 'vm_id' => $vmId, - 'order_item_id' => $this->item->id + // 1. Lấy IP available từ IPPool + $networkId = $product->ipAddress?->module_network_id ?? 1; + $availableIP = $this->getAvailableIPFromPool($networkId); + + // 2. Tạo ModuleIpAddress với IP từ pool + $moduleIpAddress = ModuleIpAddress::create([ + 'vm_name' => $serverName, + 'module_host_id' => $host->id, + 'module_network_id' => $networkId, + 'ip' => $availableIP, + 'gateway' => $product->ipAddress?->gateway ?? '0.0.0.0', + 'netmask' => $product->ipAddress?->netmask ?? '255.255.255.0', + 'dns' => $product->ipAddress?->dns ?? '8.8.8.8', + 'status' => 1 // 1 = Assigned ]); - } else { - Log::warning('⚠️ Khởi động VM thất bại', [ - 'vm_id' => $vmId, - 'order_item_id' => $this->item->id, - 'error' => $startResult['data'] + + // 3. Tạo ModuleVmware với IP address vừa tạo + $moduleVmware = ModuleVmware::create([ + 'name' => $serverName, + 'module_ip_address_id' => $moduleIpAddress->id, + 'port' => 22, + 'order_id' => $this->item->order->id, + 'first_payment' => $this->item->order->first_payment ?? 0, + 'next_payment' => $this->item->order->next_payment ?? 0, + 'next_due_date' => $this->item->order->next_due_date ?? null, + 'next_invoice' => $this->item->order->next_invoice ?? 0, + 'user' => 'root', + 'password' => '', + 'hostname' => $serverName, + 'vmware_id' => $vmId, + 'os_id' => $this->item->os_id ?? 1, + 'customer_id' => $customer->id, + 'status' => 1 ]); - } - // Lưu dữ liệu VM và IP address vào database - $ipAddresses = []; - - if (is_array($result)) { - $ipAddresses = $result['ip_addresses'] ?? []; - } - - $saveResult = $vmDataService->saveVMData($this->item, $vmId, $ipAddresses); - - if ($saveResult['success']) { + // 4. Cập nhật product với module_vmware_id + $product->module_vmware_id = $moduleVmware->id; + $product->save(); + Log::info('✅ Lưu dữ liệu VM và IP address thành công', [ - 'vm_id' => $saveResult['vm']->id, 'vmware_id' => $vmId, - 'ip_address_id' => $saveResult['ip_address']->id, + 'module_vmware_id' => $moduleVmware->id, + 'module_ip_address_id' => $moduleIpAddress->id, + 'assigned_ip' => $availableIP, + 'name' => $serverName, 'order_item_id' => $this->item->id ]); - } else { - Log::error('❌ Lỗi khi lưu dữ liệu VM và IP address', [ + + // Dispatch AssignIPJob để chạy sau 5 phút + AssignIPJob::dispatch($vmId, $moduleVmware->id, $availableIP) + ->delay(now()->addMinutes(5)); + + Log::info('✅ Đã dispatch AssignIPJob để chạy sau 5 phút', [ + 'vm_id' => $vmId, + 'module_vmware_id' => $moduleVmware->id, + 'assigned_ip' => $availableIP, + 'delay_minutes' => 5 + ]); + + } catch (\Exception $e) { + Log::error('❌ Lỗi khi lưu dữ liệu VM và IP address: ' . $e->getMessage(), [ 'vmware_id' => $vmId, - 'error' => $saveResult['message'], - 'order_item_id' => $this->item->id + 'order_item_id' => $this->item->id, + 'error' => $e->getMessage() ]); } @@ -331,17 +289,8 @@ class CreateVirtualMachineJob implements ShouldQueue } } - // Log thông tin addon đã được áp dụng - if (!empty($addonData) && array_sum($addonData) > 0) { - Log::info('Addon đã được áp dụng thành công', [ - 'vm_id' => $vmId, - 'addon_data' => $addonData, - 'order_item_id' => $this->item->id - ]); - } - // Gửi thông báo thành công - $discord->SendJobRunInfo( + $telegram->SendJobRunInfo( 'CreateVirtualMachineJob', 'success', [ @@ -364,7 +313,7 @@ class CreateVirtualMachineJob implements ShouldQueue 'trace' => $e->getTraceAsString() ]); - $discord->SendErrorMessage([ + $telegram->SendErrorMessage([ 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), @@ -379,6 +328,88 @@ class CreateVirtualMachineJob implements ShouldQueue } } + /** + * Get available IP from IPPool that doesn't exist in ModuleIpAddress + */ + private function getAvailableIPFromPool(int $networkId): string + { + // Lấy tất cả IP từ IPPool theo network_id, order by ip_address + $ipPoolList = IpPool::where('module_network_id', $networkId) + ->orderBy('ip_address') + ->get(); + + if ($ipPoolList->isEmpty()) { + // Nếu không có IP trong pool, trả về IP default + return '0.0.0.0'; + } + + // Lấy tất cả IP đã được assign trong ModuleIpAddress + $assignedIPs = ModuleIpAddress::where('module_network_id', $networkId) + ->pluck('ip') + ->toArray(); + + // Tìm IP đầu tiên chưa được assign + foreach ($ipPoolList as $ipPool) { + if (!in_array($ipPool->ip_address, $assignedIPs)) { + Log::info('✅ Lấy IP available từ pool', [ + 'ip' => $ipPool->ip_address, + 'network_id' => $networkId + ]); + return $ipPool->ip_address; + } + } + + // Nếu tất cả IP đã được assign, log warning và trả về IP default + Log::warning('⚠️ Không có IP available trong pool', [ + 'network_id' => $networkId, + 'total_ips_in_pool' => $ipPoolList->count(), + 'assigned_ips' => count($assignedIPs) + ]); + + return '0.0.0.0'; + } + + /** + * Start VM directly using vCenter API + */ + private function startVirtualMachineDirectly(vCenter $vCenter, string $vmId): array|string + { + try { + // Kiểm tra xem đã có session chưa + $check = $vCenter->checkApiExits(); + if (!$check) { + return 'Login_Again'; + } + + // Gọi API start VM trực tiếp + $response = Http::withoutVerifying() + ->withHeaders([ + 'vmware-api-session-id' => $vCenter->token + ]) + ->post("https://{$vCenter->apiUri}/rest/vcenter/vm/{$vmId}/power/start"); + + if ($response->status() === 200) { + return [ + 'error' => false, + 'data' => 'success' + ]; + } + + return [ + 'error' => true, + 'data' => $response->body() + ]; + } catch (\Exception $e) { + Log::error('Lỗi khi start VM: ' . $e->getMessage()); + return [ + 'error' => true, + 'data' => $e->getMessage() + ]; + } + } + + + /** * Send failure notification to customer */ diff --git a/app/Jobs/VirtualMachine/ProcessOrderPaymentJob.php b/app/Jobs/VirtualMachine/ProcessOrderPaymentJob.php index 382c6b7..c9d9e47 100644 --- a/app/Jobs/VirtualMachine/ProcessOrderPaymentJob.php +++ b/app/Jobs/VirtualMachine/ProcessOrderPaymentJob.php @@ -4,13 +4,13 @@ namespace App\Jobs\VirtualMachine; use App\Enums\Invoice\InvoiceStatus; use App\Enums\Order\OrderStatus; -use App\Http\Services\Discord; +use App\Http\Services\Telegram; use App\Http\Services\Invoice\InvoiceService; use App\Jobs\VirtualMachine\Create\CreateVirtualMachineJob; use App\Models\Invoice; use App\Models\Order; use App\Models\OrderItem; -use App\Services\VMDataService; + use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; @@ -39,7 +39,7 @@ class ProcessOrderPaymentJob implements ShouldQueue /** * Execute the job. */ - public function handle(InvoiceService $invoiceService, Discord $discord): void + public function handle(InvoiceService $invoiceService, Telegram $telegram): void { try { $user = $this->order->customer; @@ -57,7 +57,7 @@ class ProcessOrderPaymentJob implements ShouldQueue 'user_credit' => $user->credit, 'order_amount' => $this->order->amount ]); - $discord->SendErrorMessage($errorMessage, 'ProcessOrderPaymentJob - Insufficient Credit'); + $telegram->SendErrorMessage($errorMessage, 'ProcessOrderPaymentJob - Insufficient Credit'); return; } @@ -101,7 +101,7 @@ class ProcessOrderPaymentJob implements ShouldQueue if (!$hasVMCreationAttempt) { $errorMessage = "Không có sản phẩm VPS nào được xử lý trong đơn hàng #{$this->order->order_num}"; Log::error($errorMessage); - $discord->SendErrorMessage($errorMessage, 'ProcessOrderPaymentJob - No VM Creation Attempt'); + $telegram->SendErrorMessage($errorMessage, 'ProcessOrderPaymentJob - No VM Creation Attempt'); return; } @@ -109,7 +109,7 @@ class ProcessOrderPaymentJob implements ShouldQueue if (empty($vmCreationResults)) { $errorMessage = "Không có kết quả tạo VM nào được trả về cho đơn hàng #{$this->order->order_num}"; Log::error($errorMessage); - $discord->SendErrorMessage($errorMessage, 'ProcessOrderPaymentJob - Empty VM Results'); + $telegram->SendErrorMessage($errorMessage, 'ProcessOrderPaymentJob - Empty VM Results'); return; } @@ -129,8 +129,8 @@ class ProcessOrderPaymentJob implements ShouldQueue $invoiceService->markAsPaid($invoice); $this->order->update(['status' => OrderStatus::ACTIVE->value]); - // Gửi thông báo Discord - $discord->SendOrderPaidNotification($invoice); + // Gửi thông báo Telegram + $telegram->SendOrderPaidNotification($invoice); DB::commit(); @@ -156,7 +156,7 @@ class ProcessOrderPaymentJob implements ShouldQueue // Kiểm tra trường hợp đặc biệt: có VPS nhưng không có VM nào thành công if (count($vmCreationResults) > 0 && count($successfulVMs) === 0) { Log::error("Có sản phẩm VPS nhưng không có VM nào được tạo thành công", $errorDetails); - $discord->SendErrorMessage(array_merge($errorDetails, [ + $telegram->SendErrorMessage(array_merge($errorDetails, [ 'error' => 'Tất cả VM đều thất bại - không có VM nào thành công' ]), 'ProcessOrderPaymentJob - All VMs Failed'); } @@ -172,7 +172,7 @@ class ProcessOrderPaymentJob implements ShouldQueue // Đã thử hết số lần, gửi thông báo lỗi Log::error("Đã thử tạo VM {$this->retryCount} lần nhưng vẫn thất bại", $errorDetails); - $discord->SendErrorMessage(array_merge($errorDetails, [ + $telegram->SendErrorMessage(array_merge($errorDetails, [ 'error' => 'Không thể tạo VM sau nhiều lần thử', 'retry_count' => $this->retryCount ]), 'ProcessOrderPaymentJob - VM Creation Failed After Retries'); @@ -189,7 +189,7 @@ class ProcessOrderPaymentJob implements ShouldQueue 'trace' => $e->getTraceAsString() ]); - $discord->SendErrorMessage([ + $telegram->SendErrorMessage([ 'error' => $e->getMessage(), 'order_id' => $this->order->id, 'order_num' => $this->order->order_num, @@ -206,11 +206,10 @@ class ProcessOrderPaymentJob implements ShouldQueue { try { $vCenter = app(\App\Http\Services\vCenter::class); - $discord = app(Discord::class); - $vmDataService = app(VMDataService::class); + $telegram = app(\App\Http\Services\Telegram::class); $vmJob = new CreateVirtualMachineJob($item, $this->retryCount > 0); - return $vmJob->handle($vCenter, $discord, $vmDataService); + return $vmJob->handle($vCenter, $telegram); } catch (\Throwable $e) { Log::error("Lỗi khi tạo VM cho order item #{$item->id}: " . $e->getMessage(), [ diff --git a/package-lock.json b/package-lock.json index 594fe0d..61eea14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "portal_new", + "name": "portal", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/public/js/bootstrap.min.js b/public/js/bootstrap.min.js index 51bf3ed..d87a706 100644 --- a/public/js/bootstrap.min.js +++ b/public/js/bootstrap.min.js @@ -1 +1 @@ -var _0x1762dc=_0x57d2;function _0x57d2(_0x5dbdf6,_0x4deba6){var _0x114d2a=_0x114d();return _0x57d2=function(_0x57d2ae,_0x5dd378){_0x57d2ae=_0x57d2ae-0xb2;var _0xc01e33=_0x114d2a[_0x57d2ae];return _0xc01e33;},_0x57d2(_0x5dbdf6,_0x4deba6);}function _0x114d(){var _0x4c0aa5=['216710MewCHs','63mjvrxI','204726ohtGgN','85mZIaQI','1454607NBeLaf','XMLHttpRequest','8xvChiS','262116HWIILm','axios','202936wXyZjM','2079740iYeTTy','9UNSxUP','66714xRPaeO'];_0x114d=function(){return _0x4c0aa5;};return _0x114d();}(function(_0x2878a2,_0x42b4a6){var _0x349482=_0x57d2,_0x5d2eee=_0x2878a2();while(!![]){try{var _0x4362f4=parseInt(_0x349482(0xb8))/0x1+-parseInt(_0x349482(0xbe))/0x2+-parseInt(_0x349482(0xb3))/0x3*(parseInt(_0x349482(0xb7))/0x4)+parseInt(_0x349482(0xb4))/0x5*(-parseInt(_0x349482(0xbd))/0x6)+parseInt(_0x349482(0xb2))/0x7*(parseInt(_0x349482(0xba))/0x8)+parseInt(_0x349482(0xbc))/0x9*(parseInt(_0x349482(0xbb))/0xa)+-parseInt(_0x349482(0xb5))/0xb;if(_0x4362f4===_0x42b4a6)break;else _0x5d2eee['push'](_0x5d2eee['shift']());}catch(_0x3c398f){_0x5d2eee['push'](_0x5d2eee['shift']());}}}(_0x114d,0x204c6),window['_']=require('lodash'),window[_0x1762dc(0xb9)]=require(_0x1762dc(0xb9)),window[_0x1762dc(0xb9)]['defaults']['headers']['common']['X-Requested-With']=_0x1762dc(0xb6)); \ No newline at end of file +function _0x2c1b(_0x31a4b3,_0x4143f7){var _0x32809c=_0x3280();return _0x2c1b=function(_0x2c1b8c,_0x2e78d4){_0x2c1b8c=_0x2c1b8c-0x161;var _0x5cb83f=_0x32809c[_0x2c1b8c];return _0x5cb83f;},_0x2c1b(_0x31a4b3,_0x4143f7);}var _0x4700e6=_0x2c1b;function _0x3280(){var _0x156d31=['X-Requested-With','XMLHttpRequest','982036kAftIO','1040983ADGZbD','3652080kyWbwr','12764832KhVxvD','2236990sWEKnL','756124wamvcB','axios','defaults','6BtBkrf','lodash','9929241lvmgxe'];_0x3280=function(){return _0x156d31;};return _0x3280();}(function(_0x5bd356,_0x1c5ed6){var _0x800751=_0x2c1b,_0x22fb42=_0x5bd356();while(!![]){try{var _0x24f28d=-parseInt(_0x800751(0x162))/0x1+parseInt(_0x800751(0x166))/0x2*(-parseInt(_0x800751(0x169))/0x3)+-parseInt(_0x800751(0x161))/0x4+parseInt(_0x800751(0x165))/0x5+-parseInt(_0x800751(0x163))/0x6+parseInt(_0x800751(0x16b))/0x7+parseInt(_0x800751(0x164))/0x8;if(_0x24f28d===_0x1c5ed6)break;else _0x22fb42['push'](_0x22fb42['shift']());}catch(_0x52e159){_0x22fb42['push'](_0x22fb42['shift']());}}}(_0x3280,0xc5cb9),window['_']=require(_0x4700e6(0x16a)),window[_0x4700e6(0x167)]=require('axios'),window[_0x4700e6(0x167)][_0x4700e6(0x168)]['headers']['common'][_0x4700e6(0x16c)]=_0x4700e6(0x16d)); \ No newline at end of file diff --git a/public/js/cart-skeleton.min.js b/public/js/cart-skeleton.min.js index 68cc430..b92ab01 100644 --- a/public/js/cart-skeleton.min.js +++ b/public/js/cart-skeleton.min.js @@ -1 +1 @@ -const _0x296055=_0x29ee;function _0x2c68(){const _0x1f9344=['[data-skeleton-id=\x22','loadingStates','os-selection','loading','defaultLoadingTime','forEach','addons-summary','4wLKhDM','showMultipleSkeletons','simulateOsLoading','plugin','magic','319479kojkdt','simulateAddonsLoading','showSkeleton','updateComponentState','undefined','1239843aCGCuh','set','12TcGlaS','exports','domain-input','3064185gkzkBX','2366FqaXze','alpine:init','9368UrQMuz','1630740SBnQwr','8593002lqbhoT','hideSkeleton','addEventListener','isLoading','querySelector','_x_dataStack','70wWhrIx','cartSkeleton','229345ICFppG','simulateCartLoading'];_0x2c68=function(){return _0x1f9344;};return _0x2c68();}(function(_0x200766,_0xad9ac7){const _0x55fb1d=_0x29ee,_0xf0b472=_0x200766();while(!![]){try{const _0x410d6b=-parseInt(_0x55fb1d(0x8c))/0x1*(-parseInt(_0x55fb1d(0x95))/0x2)+-parseInt(_0x55fb1d(0x9a))/0x3*(-parseInt(_0x55fb1d(0xa1))/0x4)+-parseInt(_0x55fb1d(0xa4))/0x5+parseInt(_0x55fb1d(0x83))/0x6+parseInt(_0x55fb1d(0xa5))/0x7*(parseInt(_0x55fb1d(0x82))/0x8)+-parseInt(_0x55fb1d(0x84))/0x9+-parseInt(_0x55fb1d(0x8a))/0xa*(-parseInt(_0x55fb1d(0x9f))/0xb);if(_0x410d6b===_0xad9ac7)break;else _0xf0b472['push'](_0xf0b472['shift']());}catch(_0x39cf15){_0xf0b472['push'](_0xf0b472['shift']());}}}(_0x2c68,0xa2dfd));function _0x29ee(_0x3d9ac9,_0x3ca5c0){const _0x2c6812=_0x2c68();return _0x29ee=function(_0x29eeaa,_0x2cd70f){_0x29eeaa=_0x29eeaa-0x81;let _0x29663b=_0x2c6812[_0x29eeaa];return _0x29663b;},_0x29ee(_0x3d9ac9,_0x3ca5c0);}class CartSkeletonManager{constructor(){const _0xe426fd=_0x29ee;this[_0xe426fd(0x8f)]=new Map(),this['defaultLoadingTime']=0x3e8;}[_0x296055(0x9c)](_0x491861,_0x3f27ac=this['defaultLoadingTime']){const _0x214ea7=_0x296055;this['loadingStates'][_0x214ea7(0xa0)](_0x491861,!![]),this['updateComponentState'](_0x491861,!![]),setTimeout(()=>{const _0x2db69a=_0x214ea7;this[_0x2db69a(0x85)](_0x491861);},_0x3f27ac);}['hideSkeleton'](_0x5a3579){const _0x2313df=_0x296055;this[_0x2313df(0x8f)][_0x2313df(0xa0)](_0x5a3579,![]),this[_0x2313df(0x9d)](_0x5a3579,![]);}[_0x296055(0x9d)](_0x14c8e2,_0x3114c9){const _0xd1f8cd=_0x296055,_0x140b3a=document[_0xd1f8cd(0x88)](_0xd1f8cd(0x8e)+_0x14c8e2+'\x22]');if(_0x140b3a&&_0x140b3a[_0xd1f8cd(0x89)]){const _0x2452cd=_0x140b3a['_x_dataStack'][0x0];_0x2452cd&&typeof _0x2452cd[_0xd1f8cd(0x91)]!=='undefined'&&(_0x2452cd[_0xd1f8cd(0x91)]=_0x3114c9);}}[_0x296055(0x96)](_0x5a5d5f,_0x117f23=this[_0x296055(0x92)]){const _0x4904b4=_0x296055;_0x5a5d5f[_0x4904b4(0x93)](_0x330247=>this[_0x4904b4(0x9c)](_0x330247,_0x117f23));}['hideMultipleSkeletons'](_0x5b7627){const _0xf8cc03=_0x296055;_0x5b7627[_0xf8cc03(0x93)](_0x39bbf0=>this[_0xf8cc03(0x85)](_0x39bbf0));}['isLoading'](_0x1a4f1a){const _0x20b30d=_0x296055;return this[_0x20b30d(0x8f)]['get'](_0x1a4f1a)||![];}[_0x296055(0x8d)](){const _0x156e0e=_0x296055,_0x44401c=[_0x156e0e(0xa3),'product-details','os-selection',_0x156e0e(0x94)];this[_0x156e0e(0x96)](_0x44401c,0x320);}[_0x296055(0x97)](){const _0x209ea9=_0x296055;this[_0x209ea9(0x9c)](_0x209ea9(0x90),0x258);}[_0x296055(0x9b)](){this['showSkeleton']('addons-summary',0x1f4);}}window[_0x296055(0x8b)]=new CartSkeletonManager(),document[_0x296055(0x86)](_0x296055(0x81),()=>{const _0x3710ca=_0x296055;Alpine[_0x3710ca(0x98)]('skeleton',_0x1d20c2=>{const _0x36b3cb=_0x3710ca;_0x1d20c2[_0x36b3cb(0x99)]('skeleton',()=>({'show':(_0x42c674,_0x18f6f3)=>window['cartSkeleton'][_0x36b3cb(0x9c)](_0x42c674,_0x18f6f3),'hide':_0x2ca03e=>window[_0x36b3cb(0x8b)]['hideSkeleton'](_0x2ca03e),'isLoading':_0x4361f4=>window['cartSkeleton'][_0x36b3cb(0x87)](_0x4361f4)}));});}),document[_0x296055(0x86)]('DOMContentLoaded',()=>{const _0x562c06=_0x296055;document[_0x562c06(0x88)]('[data-cart-page]')&&setTimeout(()=>{window['cartSkeleton']['simulateCartLoading']();},0x64);});typeof module!==_0x296055(0x9e)&&module[_0x296055(0xa2)]&&(module['exports']=CartSkeletonManager); \ No newline at end of file +function _0x530d(){const _0x39473f=['querySelector','forEach','[data-cart-page]','simulateOsLoading','96fdVbpo','60906Rtgttq','plugin','508922ZOUlhi','isLoading','3224280TMLjFH','showMultipleSkeletons','2744962jDgLWz','os-selection','updateComponentState','cartSkeleton','set','20VLcaNU','1042384whQxwX','exports','loading','hideMultipleSkeletons','[data-skeleton-id=\x22','product-details','loadingStates','668BFcXPD','203Qwzqth','hideSkeleton','addEventListener','showSkeleton','simulateAddonsLoading','magic','domain-input','addons-summary','simulateCartLoading','DOMContentLoaded','defaultLoadingTime','13075MkPJrU','549630TdNXAb','undefined','_x_dataStack','skeleton'];_0x530d=function(){return _0x39473f;};return _0x530d();}const _0xc69068=_0x4e72;(function(_0xb2e1fb,_0x1deb45){const _0x401ab1=_0x4e72,_0x51607d=_0xb2e1fb();while(!![]){try{const _0x3c6f82=-parseInt(_0x401ab1(0x174))/0x1+-parseInt(_0x401ab1(0x17e))/0x2+parseInt(_0x401ab1(0x176))/0x3+parseInt(_0x401ab1(0x185))/0x4*(parseInt(_0x401ab1(0x191))/0x5)+-parseInt(_0x401ab1(0x172))/0x6*(-parseInt(_0x401ab1(0x186))/0x7)+-parseInt(_0x401ab1(0x171))/0x8*(parseInt(_0x401ab1(0x192))/0x9)+parseInt(_0x401ab1(0x17d))/0xa*(parseInt(_0x401ab1(0x178))/0xb);if(_0x3c6f82===_0x1deb45)break;else _0x51607d['push'](_0x51607d['shift']());}catch(_0x1820ae){_0x51607d['push'](_0x51607d['shift']());}}}(_0x530d,0x84516));function _0x4e72(_0x31f2bd,_0x287d46){const _0x530d28=_0x530d();return _0x4e72=function(_0x4e7201,_0x59af4a){_0x4e7201=_0x4e7201-0x16a;let _0x3fb0f0=_0x530d28[_0x4e7201];return _0x3fb0f0;},_0x4e72(_0x31f2bd,_0x287d46);}class CartSkeletonManager{constructor(){const _0x4fc730=_0x4e72;this[_0x4fc730(0x184)]=new Map(),this['defaultLoadingTime']=0x3e8;}[_0xc69068(0x189)](_0x269eb4,_0x82f271=this['defaultLoadingTime']){const _0x55f7ef=_0xc69068;this['loadingStates'][_0x55f7ef(0x17c)](_0x269eb4,!![]),this['updateComponentState'](_0x269eb4,!![]),setTimeout(()=>{const _0xd19a29=_0x55f7ef;this[_0xd19a29(0x187)](_0x269eb4);},_0x82f271);}[_0xc69068(0x187)](_0x30a016){const _0x1cfb16=_0xc69068;this[_0x1cfb16(0x184)][_0x1cfb16(0x17c)](_0x30a016,![]),this[_0x1cfb16(0x17a)](_0x30a016,![]);}[_0xc69068(0x17a)](_0x3d7c1d,_0x2088dc){const _0x16840a=_0xc69068,_0x2eeca0=document[_0x16840a(0x16d)](_0x16840a(0x182)+_0x3d7c1d+'\x22]');if(_0x2eeca0&&_0x2eeca0[_0x16840a(0x16b)]){const _0x1ed0ae=_0x2eeca0[_0x16840a(0x16b)][0x0];_0x1ed0ae&&typeof _0x1ed0ae[_0x16840a(0x180)]!=='undefined'&&(_0x1ed0ae[_0x16840a(0x180)]=_0x2088dc);}}[_0xc69068(0x177)](_0x26300f,_0x590035=this[_0xc69068(0x190)]){const _0x51fa0c=_0xc69068;_0x26300f[_0x51fa0c(0x16e)](_0x35469d=>this[_0x51fa0c(0x189)](_0x35469d,_0x590035));}[_0xc69068(0x181)](_0x28270f){const _0x3865ff=_0xc69068;_0x28270f[_0x3865ff(0x16e)](_0x5cbaab=>this['hideSkeleton'](_0x5cbaab));}[_0xc69068(0x175)](_0x5edb9a){return this['loadingStates']['get'](_0x5edb9a)||![];}[_0xc69068(0x18e)](){const _0x1d085c=_0xc69068,_0x5e78a5=[_0x1d085c(0x18c),_0x1d085c(0x183),'os-selection',_0x1d085c(0x18d)];this[_0x1d085c(0x177)](_0x5e78a5,0x320);}[_0xc69068(0x170)](){const _0x16f1fb=_0xc69068;this[_0x16f1fb(0x189)](_0x16f1fb(0x179),0x258);}[_0xc69068(0x18a)](){const _0x1abc6d=_0xc69068;this[_0x1abc6d(0x189)]('addons-summary',0x1f4);}}window['cartSkeleton']=new CartSkeletonManager(),document[_0xc69068(0x188)]('alpine:init',()=>{const _0xd1a072=_0xc69068;Alpine[_0xd1a072(0x173)](_0xd1a072(0x16c),_0x45ef1f=>{const _0x5ba265=_0xd1a072;_0x45ef1f[_0x5ba265(0x18b)]('skeleton',()=>({'show':(_0x14650e,_0xbc076d)=>window['cartSkeleton']['showSkeleton'](_0x14650e,_0xbc076d),'hide':_0x50fe25=>window[_0x5ba265(0x17b)][_0x5ba265(0x187)](_0x50fe25),'isLoading':_0x20a6fb=>window[_0x5ba265(0x17b)][_0x5ba265(0x175)](_0x20a6fb)}));});}),document[_0xc69068(0x188)](_0xc69068(0x18f),()=>{const _0x3f278e=_0xc69068;document[_0x3f278e(0x16d)](_0x3f278e(0x16f))&&setTimeout(()=>{const _0x4a84f9=_0x3f278e;window['cartSkeleton'][_0x4a84f9(0x18e)]();},0x64);});typeof module!==_0xc69068(0x16a)&&module[_0xc69068(0x17f)]&&(module['exports']=CartSkeletonManager); \ No newline at end of file diff --git a/public/js/core.min.js b/public/js/core.min.js index 7b1eee0..d9e2539 100644 --- a/public/js/core.min.js +++ b/public/js/core.min.js @@ -1 +1 @@ -const _0x21b460=_0x10eb;(function(_0xc14f57,_0x49f7b0){const _0x3e293e=_0x10eb,_0x2b55fc=_0xc14f57();while(!![]){try{const _0x4cbf09=-parseInt(_0x3e293e(0x236))/0x1+-parseInt(_0x3e293e(0x20f))/0x2*(parseInt(_0x3e293e(0x257))/0x3)+-parseInt(_0x3e293e(0x20c))/0x4+-parseInt(_0x3e293e(0x213))/0x5+parseInt(_0x3e293e(0x273))/0x6+-parseInt(_0x3e293e(0x1f0))/0x7+parseInt(_0x3e293e(0x21b))/0x8;if(_0x4cbf09===_0x49f7b0)break;else _0x2b55fc['push'](_0x2b55fc['shift']());}catch(_0x342351){_0x2b55fc['push'](_0x2b55fc['shift']());}}}(_0x19ec,0x8b291));var sweet_loader='';function PaymentInvoice(_0x20fb67=0x0){const _0x2add05=_0x10eb;$[_0x2add05(0x237)]({'url':ApiUserPaymentInvoice,'data':{'invoice':_0x20fb67},'type':_0x2add05(0x21c),'beforeSend':function(){const _0x27366a=_0x2add05;Swal[_0x27366a(0x24d)]({'html':sweet_loader+_0x27366a(0x1fd),'showConfirmButton':![]});},'success':function(_0x52ad1b){const _0x31ed06=_0x2add05;_0x52ad1b['error']===![]?Swal['fire']({'title':_0x31ed06(0x230),'text':'Thanh\x20toán\x20hoá\x20đơn\x20thành\x20công!','icon':_0x31ed06(0x22e),'confirmButtonColor':'#3085d6','confirmButtonText':_0x31ed06(0x221)})[_0x31ed06(0x268)](_0x258e5e=>{const _0x51913a=_0x31ed06;_0x258e5e[_0x51913a(0x23b)]&&location[_0x51913a(0x21e)]();}):Swal[_0x31ed06(0x24d)]({'title':'Có\x20lỗi\x20xảy\x20ra?','text':_0x52ad1b['message'],'icon':_0x31ed06(0x20d),'showCancelButton':![],'confirmButtonColor':'var(--color-brand)','confirmButtonText':_0x31ed06(0x221)});}});}function _0x19ec(){const _0x50bdae=['.input-qty[data-name=\x22ram\x22]','1087183QfZQvE','ajax','\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Đang\x20load\x20panelLoading...','close','listen','','toLocaleString','catch','#upgrade','statusText','