orderRepo->hasPendingOrder($customer->id)) { throw new Exception('Bạn có đơn hàng chưa thanh toán. Vui lòng thanh toán trước khi tạo đơn mới.'); } $product = $this->productRepo->find($data['product_id']); if (!$product) { throw new Exception('Sản phẩm không tồn tại'); } $price = $this->productRepo->getPricing($product->id, $data['billing_cycle']); if (is_null($price)) { throw new Exception('Không tìm thấy giá cho sản phẩm này'); } // Tính tổng tiền bao gồm addons $addonsPrice = 0; if (!empty($data['addons'])) { foreach ($data['addons'] as $addonData) { $addon = \App\Models\Addon::find($addonData['addon_id']); if ($addon) { $addonsPrice += $addon->price * ($addonData['qty'] ?? 1); } } } $totalPrice = $price + $addonsPrice; // Kiểm tra số dư tài khoản (cột total) trước khi tạo đơn if ($customer->total < $totalPrice) { throw new Exception('Số dư không đủ để đặt hàng. Vui lòng nạp thêm tiền. Số dư hiện tại: ' . number_format($customer->total) . ' VNĐ, cần: ' . number_format($totalPrice) . ' VNĐ'); } return DB::transaction(function () use ($data, $customer, $product, $price, $totalPrice) { $order = $this->orderRepo->create([ 'order_num' => \App\Helpers\OrderHelper::generateOrderNumber(), 'customer_id' => $customer->id, 'amount' => $price, 'status' => OrderStatus::PENDING->value ]); $this->orderRepo->createItem($order->id, [ 'product_id' => $product->id, 'billing_cycle' => $data['billing_cycle'], 'server_name' => $data['server_name'] ?? null, 'os_id' => $data['os_id'] ?? null, 'price' => $price, 'addons' => $data['addons'] ?? [] ]); $invoice = $this->invoiceRepo->createFromOrder($order); return [ 'order' => $order, 'invoice' => $invoice ]; }); } public function pay($order, string $method) { if (in_array($order->status, [OrderStatus::ACTIVE->value, OrderStatus::PROCESSING->value], true)) { throw new Exception('Đơn hàng đã được thanh toán hoặc đang xử lý.'); } return DB::transaction(function () use ($order, $method) { $customer = $order->customer; // Kiểm tra số dư và trừ tiền if ($customer->total < $order->amount) { throw new Exception('Số dư không đủ để thanh toán. Vui lòng nạp thêm tiền. Số dư hiện tại: ' . number_format($customer->total) . ' VNĐ, cần: ' . number_format($order->amount) . ' VNĐ'); } $customer->total -= $order->amount; $customer->save(); CustomerLog::create([ 'agent' => 'api', 'client_ip' => request()?->ip(), 'customer_id' => $customer->id, 'description' => 'Thanh toán đơn hàng #' . $order->order_num . ' thành công. Số tiền: ' . number_format((int) $order->amount) . ' VNĐ' . '. Số dư sau thanh toán: ' . number_format((int) $customer->total) . ' VNĐ', ]); // Cho phép thanh toán lại đơn đã hủy bằng cách đưa về pending trước khi process. if ($order->status === OrderStatus::CANCELLED->value) { $order->status = OrderStatus::PENDING->value; $order->save(); } $processedOrder = $this->orderRepo->processPayment($order, $method); // Sau khi thanh toán, tạo module_vmware rồi dispatch CreateVMJobs. foreach ($order->orderItems as $item) { if (empty($item->product_id) || empty($item->os_id)) { Log::warning('Skip VM job: product_id/os_id is missing', [ 'order_id' => $order->id, 'order_item_id' => $item->id, 'product_id' => $item->product_id, 'os_id' => $item->os_id, ]); continue; } try { $os = Os::with('osGroup.host')->find($item->os_id); if (!$os || !$os->osGroup || !$os->osGroup->module_host_id) { Log::warning('Skip VM job: không tìm thấy OS/OsGroup/Host', [ 'order_id' => $order->id, 'order_item_id' => $item->id, 'os_id' => $item->os_id, ]); continue; } $ip = ModuleIpAddress::where('module_host_id', $os->osGroup->module_host_id) ->where('status', 0) ->lockForUpdate() ->first(); if (!$ip) { Log::warning('Skip VM job: không còn IP khả dụng', [ 'order_id' => $order->id, 'module_host_id' => $os->osGroup->module_host_id, ]); continue; } $ip->update(['status' => 1, 'vm_name' => $item->server_name ?? 'VM-' . $order->id]); $moduleVmware = ModuleVmware::create([ 'name' => $item->server_name ?? 'VM-' . $order->id, 'module_ip_address_id' => $ip->id, 'port' => 22, 'order_id' => $order->id, 'first_payment' => $order->amount, 'next_payment' => $order->amount, 'next_due_date' => null, 'next_invoice' => 0, 'user' => 'Administrator', 'password' => '', 'hostname' => $item->server_name ?? 'vm-' . $order->id, 'vmware_id' => null, 'os_id' => $item->os_id, 'customer_id' => $order->customer_id, 'status' => 0, ]); dispatch(new CreateVMJobs($moduleVmware->id))->delay(now()->addSeconds(10)); Log::info('Dispatched CreateVMJobs', [ 'order_id' => $order->id, 'module_vmware_id' => $moduleVmware->id, 'ip' => $ip->ip, ]); } catch (\Exception $e) { Log::error('Lỗi khi tạo module_vmware hoặc dispatch job', [ 'order_id' => $order->id, 'order_item_id' => $item->id, 'error' => $e->getMessage(), ]); } } return $processedOrder; }); } }