orderQueryService->getOrdersForCustomer( (int) $request->user()->id, ClientOrderFilters::fromArray($request->only(['total_price', 'pending'])), ); return response()->json(['success' => true, 'data' => $orders]); } public function checkServerName(CheckServerNameRequest $request): JsonResponse { $result = $this->orderQueryService->checkServerName($request->string('name')->toString()); return response()->json($result['available'] ? ['available' => true] : $result); } public function getClientOrders(Request $request): JsonResponse { $orders = $this->orderRepository->getOrders((int) $request->user()->id, []); return response()->json([ 'success' => true, 'data' => OrderSummaryResource::collection($orders->getCollection()->load('invoice')), ]); } public function getClientOrderDetail(Request $request, int $id): JsonResponse { $order = $this->orderQueryService->findCustomerOrder((int) $request->user()->id, $id); if (!$order) { return response()->json(['success' => false, 'message' => 'Đơn hàng không tồn tại.'], 404); } return response()->json(['success' => true, 'data' => new OrderDetailResource($order)]); } public function storeOrder(StoreOrderRequest $request): JsonResponse { try { $customer = $request->user(); $data = $request->validated(); $product = \App\Models\Product::where('uuid', $data['product_id'])->first(); if (!$product) { return response()->json( ['success' => false, 'message' => 'Sản phẩm không tìm thấy hoặc đã bị xóa.'], 404, ); } $data['product_id'] = $product->id; $result = $this->orderService->create($data, $customer); $order = $result['order']->load(['orderItems.product', 'invoice', 'customer']); return response()->json( [ 'success' => true, 'message' => 'Tạo đơn hàng thành công.', 'notice' => 'Dịch vụ VPS sẽ được khởi tạo trong 5-10 phút sau khi thanh toán.', 'data' => [ 'order' => new OrderDetailResource($order), 'invoice' => new InvoiceDetailResource($result['invoice']->load(['customer', 'order'])), 'items' => OrderItemResource::collection($order->orderItems), ], ], 201, ); } catch (\Illuminate\Validation\ValidationException $e) { return response()->json( ['success' => false, 'message' => collect($e->errors())->flatten()->first() ?? $e->getMessage()], 422, ); } catch (\InvalidArgumentException $e) { return response()->json(['success' => false, 'message' => $e->getMessage()], 400); } catch (\Throwable $e) { \Log::error('OrderControllerRefactor::storeOrder error: ' . $e->getMessage()); return response()->json(['success' => false, 'message' => 'Có lỗi xảy ra, vui lòng thử lại'], 500); } } public function payOrder(string $orderNum, PayOrderRequest $request): JsonResponse { $order = $this->orderRepository->findByOrderNum($orderNum, (int) $request->user()->id); if (!$order) { return response()->json(['success' => false, 'message' => 'Đơn hàng không tồn tại.'], 404); } try { $this->orderService->pay($order, $request->payment_method); } catch (\InvalidArgumentException $e) { return response()->json(['success' => false, 'message' => $e->getMessage()], 422); } catch (\Throwable $e) { \Log::error('OrderControllerRefactor::payOrder error: ' . $e->getMessage()); return response()->json(['success' => false, 'message' => 'Có lỗi xảy ra, vui lòng thử lại'], 500); } $this->activityLogger->log( event: 'payment', logName: 'Order', description: "Customer {$request->user()->email} thanh toán đơn hàng #{$order->order_num} qua {$request->payment_method}", subject: $order, newValues: ['payment_method' => $request->payment_method, 'total' => $order->total], ); return response()->json(['success' => true, 'message' => 'Thanh toán thành công.']); } public function retryOrderProvisioning(Request $request, int $id): JsonResponse { $customerId = (int) $request->user()->id; $order = $this->orderRepository->findForCustomer($id, $customerId); if (!$order) { return response()->json(['success' => false, 'message' => 'Đơn hàng không tồn tại.'], 404); } $result = $this->orderQueryService->retryProvisioning($order, $customerId); if (!$result['ok']) { return response()->json(['success' => false, 'message' => $result['message']], $result['code']); } $this->activityLogger->log( event: 'retry_provisioning', logName: 'Order', description: "Customer {$request->user()->email} yêu cầu khởi tạo lại dịch vụ cho đơn hàng #{$order->order_num}", subject: $order, ); return response()->json(['success' => true, 'message' => $result['message']]); } public function getClientInvoices(Request $request): JsonResponse { $invoices = $this->orderQueryService->getCustomerInvoices((int) $request->user()->id); return response()->json(['success' => true, 'data' => InvoiceSummaryResource::collection($invoices)]); } public function getClientInvoiceDetail(Request $request, int $id): JsonResponse { $invoice = $this->orderQueryService->findCustomerInvoice((int) $request->user()->id, $id); if (!$invoice) { return response()->json(['success' => false, 'message' => 'Hóa đơn không tồn tại.'], 404); } return response()->json(['success' => true, 'data' => new InvoiceDetailResource($invoice)]); } public function getClientInvoiceDetailByOrderNum(Request $request, string $orderNumber): JsonResponse { $order = $this->orderQueryService->findCustomerInvoiceByOrderNum((int) $request->user()->id, $orderNumber); if (!$order?->invoice) { return response()->json(['success' => false, 'message' => 'Hóa đơn không tồn tại.'], 404); } $order->load('vmWare.os.osGroup', 'vmWare.virtualMachine', 'vmWare.service'); return response()->json([ 'success' => true, 'data' => new InvoiceDetailResource($order->invoice->setRelation('order', $order)), ]); } public function getClientInvoiceDetailByNumber(Request $request, string $invoiceNumber): JsonResponse { $invoice = $this->orderQueryService->findCustomerInvoiceByNumber((int) $request->user()->id, $invoiceNumber); if (!$invoice) { return response()->json(['success' => false, 'message' => 'Hóa đơn không tồn tại.'], 404); } return response()->json([ 'success' => true, 'data' => new InvoiceDetailResource($invoice), 'payment_url' => $invoice->clientPath(), ]); } public function payClientInvoiceByNumber(Request $request, string $invoiceNumber): JsonResponse { $invoice = $this->orderQueryService->findCustomerInvoiceByNumber((int) $request->user()->id, $invoiceNumber); if (!$invoice) { return response()->json(['success' => false, 'message' => 'Hóa đơn không tồn tại.'], 404); } // Bỏ trống `amount` = trả hết phần còn thiếu. Truyền số nhỏ hơn để trả từng phần khi // số dư chưa đủ — hoá đơn giữ nguyên chưa thanh toán cho tới khi thu đủ. $validated = $request->validate([ 'amount' => 'nullable|integer|min:1', ]); try { $paidInvoice = $this->invoicePaymentService->payWithBalance( $invoice, $request->user(), 'balance', $validated['amount'] ?? null, ); $this->activityLogger->log( event: 'payment', logName: 'Invoice', description: "Customer {$request->user()->email} thanh toán hóa đơn #{$paidInvoice->invoice_number}", subject: $paidInvoice, newValues: ['invoice_number' => $paidInvoice->invoice_number, 'total' => $paidInvoice->total], ); $outstanding = \App\Services\InvoicePaymentService::outstanding($paidInvoice); return response()->json([ 'success' => true, 'message' => $outstanding > 0 ? 'Đã ghi nhận thanh toán một phần. Còn thiếu ' . number_format($outstanding) . ' VNĐ để kích hoạt dịch vụ.' : 'Thanh toán hóa đơn thành công.', 'data' => new InvoiceDetailResource($paidInvoice), ]); } catch (\InvalidArgumentException $e) { return response()->json(['success' => false, 'message' => $e->getMessage()], 422); } catch (\Throwable $e) { \Log::error('OrderControllerRefactor::payClientInvoiceByNumber error: ' . $e->getMessage()); return response()->json(['success' => false, 'message' => 'Có lỗi xảy ra, vui lòng thử lại'], 500); } } public function getClientOrderDetailByOrderNum(Request $request, string $orderNum): JsonResponse { $order = $this->orderQueryService->findCustomerInvoiceByOrderNum((int) $request->user()->id, $orderNum); if (!$order) { return response()->json(['success' => false, 'message' => 'Đơn hàng không tồn tại.'], 404); } return response()->json(['success' => true, 'data' => new OrderDetailResource($order)]); } public function downloadInvoicePdfByOrderNum( Request $request, string $orderNum, InvoicePdfService $pdfService, ): Response { $order = $this->orderQueryService->findCustomerInvoiceByOrderNum((int) $request->user()->id, $orderNum); if (!$order?->invoice) { abort(404, 'Hóa đơn không tồn tại.'); } $pdf = $pdfService->generate($order->invoice); $filename = $pdfService->generateFileName($order->invoice); return response($pdf, 200, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'attachment; filename="' . $filename . '"', ]); } public function getClientServices(Request $request): JsonResponse { $services = $this->orderQueryService->getCustomerServices((int) $request->user()->id); return response()->json(['success' => true, 'data' => ServiceSummaryResource::collection($services)]); } public function updateClientServiceAutoRenew(Request $request, int $id): JsonResponse { $validated = $request->validate(['auto_renew' => ['required', 'boolean']]); $service = \App\Models\Service::query()->where('id', $id)->where('customer_id', $request->user()->id)->first(); if (!$service) { return response()->json(['success' => false, 'message' => 'Không tìm thấy dịch vụ.'], 404); } $service->update(['auto_renew' => (bool) $validated['auto_renew']]); $this->activityLogger->log( event: 'updated', logName: 'Service', description: "Customer {$request->user()->email} " . ($validated['auto_renew'] ? 'bật' : 'tắt') . " tự động gia hạn dịch vụ #{$service->id}", subject: $service, newValues: ['auto_renew' => (bool) $validated['auto_renew']], ); return response()->json([ 'success' => true, 'message' => 'Cập nhật tự động gia hạn thành công.', 'data' => ['id' => $service->id, 'auto_renew' => (bool) $service->auto_renew], ]); } public function renewService(RenewServiceRequest $request, int $id): JsonResponse { $result = $this->orderQueryService->renewService( $id, $request->user(), (int) $request->validated()['months'], ); if (!$result['ok']) { return response()->json( ['success' => false, 'message' => $result['message'], 'data' => $result['data'] ?? null], $result['code'], ); } return response()->json(['success' => true, 'message' => $result['message'], 'data' => $result['data']]); } }