update rm deadcode

This commit is contained in:
baodev0
2026-09-27 11:42:40 +07:00
parent 82a71244ca
commit 3af59bd9c5
129 changed files with 5194 additions and 2698 deletions
@@ -2,15 +2,22 @@
namespace App\Http\Controllers\Api\Service;
use App\Enums\Invoice\InvoiceStatus;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Service\Concerns\ResolvesVm;
use App\Http\Services\vCenter;
use App\Helpers\OrderHelper;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\Service;
use App\Services\ActivityLogger;
use App\Services\InvoicePaymentService;
use App\Services\VirtualMachine\Rebuild\VmRebuildService;
use App\Support\AddonQuantityValidator;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Throwable;
class VmRebuildController extends Controller
@@ -103,7 +110,7 @@ class VmRebuildController extends Controller
return response()->json([
'error' => true,
'message' => 'Không thể gửi yêu cầu rebuild: ' . $e->getMessage(),
'message' => 'Không thể gửi yêu cầu rebuild, vui lòng thử lại sau.',
], 400);
}
@@ -179,7 +186,9 @@ class VmRebuildController extends Controller
]);
}
public function upgradeAddons(Request $request, vCenter $serviceVCenter): JsonResponse
private const INVOICE_TYPE_UPGRADE = 3;
public function upgradeAddons(Request $request): JsonResponse
{
$customer = $request->user();
$payload = $request->validate([
@@ -188,7 +197,7 @@ class VmRebuildController extends Controller
'ram' => ['nullable', 'integer', 'min:0'],
'disk' => ['nullable', 'integer', 'min:0'],
'bandwidth' => ['nullable', 'integer', 'min:0'],
'gpu' => ['nullable'],
'gpu' => ['nullable', 'integer', 'min:0'],
]);
$vm = $this->resolveVmById($payload['product'], $request);
@@ -196,49 +205,160 @@ class VmRebuildController extends Controller
return $vm;
}
$vm->loadMissing(['vCenter', 'ipAddress.host.datacenter.vCenter']);
$vm->loadMissing(['order.orderItems.product']);
$vcenter = $vm->vCenter ?? $vm->ipAddress?->host?->datacenter?->vCenter;
if (!$vcenter || !$serviceVCenter->loginServer($vcenter)) {
return response()->json(['error' => true, 'message' => 'Không thể đăng nhập vCenter'], 400);
$orderItem = $vm->order?->orderItems?->first();
$product = $orderItem?->product;
if (!$orderItem || !$product) {
return response()->json(['error' => true, 'message' => 'Không tìm thấy product của dịch vụ hiện tại'], 404);
}
$applied = [];
$service = Service::where('order_item_id', $orderItem->id)->first();
if (!$service) {
return response()->json(['error' => true, 'message' => 'Không tìm thấy dịch vụ hiện tại'], 404);
}
if (isset($payload['cpu']) && $payload['cpu'] > 0) {
$res = $serviceVCenter->UpgradeCPUVirtualMachine($vm->vmware_id, (int) $payload['cpu']);
if (is_array($res) && !($res['error'] ?? true)) {
$applied[] = 'cpu';
}
$requestedQtyByCode = array_filter([
'cpu' => (int) ($payload['cpu'] ?? 0),
'ram' => (int) ($payload['ram'] ?? 0),
'disk' => (int) ($payload['disk'] ?? 0),
'bandwidth' => (int) ($payload['bandwidth'] ?? 0),
'gpu' => (int) ($payload['gpu'] ?? 0),
], fn ($qty) => $qty > 0);
if (empty($requestedQtyByCode)) {
return response()->json(['error' => true, 'message' => 'Vui lòng chọn ít nhất một addon để nâng cấp'], 422);
}
if (isset($payload['ram']) && $payload['ram'] > 0) {
$res = $serviceVCenter->UpgradeMemoryVirtualMachine($vm->vmware_id, (int) $payload['ram']);
if (is_array($res) && !($res['error'] ?? true)) {
$applied[] = 'ram';
$activeAddons = $product->addons()->where('status', true)->get()->keyBy('id');
$addonsByCode = $activeAddons->keyBy(fn ($addon) => strtolower((string) $addon->code));
$raw = [];
foreach ($requestedQtyByCode as $code => $qty) {
$addon = $addonsByCode->get($code);
if (!$addon) {
return response()->json(['error' => true, 'message' => "Addon \"{$code}\" không áp dụng cho sản phẩm này"], 422);
}
$raw[] = ['addon_id' => $addon->id, 'qty' => $qty];
}
if (isset($payload['disk']) && $payload['disk'] > 0) {
$res = $serviceVCenter->UpgradeDiskVirtualMachine($vm, (int) $payload['disk']);
if (is_array($res) && !($res['error'] ?? true)) {
$applied[] = 'disk';
}
$existingQtyByAddonId = collect(is_array($orderItem->addons_meta) ? $orderItem->addons_meta : [])
->mapWithKeys(fn ($entry) => [(int) ($entry['addon_id'] ?? 0) => (int) ($entry['qty'] ?? 0)])
->all();
try {
$resolved = AddonQuantityValidator::resolve($raw, $activeAddons, $existingQtyByAddonId);
} catch (ValidationException $e) {
return response()->json([
'error' => true,
'message' => collect($e->errors())->flatten()->first() ?? 'Yêu cầu nâng cấp không hợp lệ',
], 422);
}
$existingInvoice = Invoice::where('service_id', $service->id)
->where('invoice_type', self::INVOICE_TYPE_UPGRADE)
->whereIn('status', InvoicePaymentService::PAYABLE_STATUSES)
->first();
if ($existingInvoice) {
return response()->json([
'error' => false,
'message' => 'Dịch vụ đã có hóa đơn nâng cấp đang chờ thanh toán.',
'data' => $this->invoiceResponse($existingInvoice, $vm->order?->order_num),
]);
}
$cycleMonths = OrderHelper::cycleToMonths($orderItem->billing_cycle);
$cycleDays = max(1, $cycleMonths * 30);
$remainingDays = $service->expires_at && $service->expires_at->isFuture()
? now()->diffInDays($service->expires_at)
: 0;
$remainingDays = (int) max(1, min($cycleDays, $remainingDays));
try {
$invoice = DB::transaction(function () use ($service, $orderItem, $resolved, $remainingDays, $cycleDays) {
$total = 0;
$lines = [];
foreach ($resolved as $entry) {
$unitPrice = $this->prorateUnitPrice((float) $entry['price'], $remainingDays, $cycleDays);
$totalPrice = $unitPrice * $entry['qty'];
$total += $totalPrice;
$lines[] = [
'product_id' => $orderItem->product_id,
'addon_id' => $entry['addon_id'],
'type' => 'upgrade',
'description' => 'Nâng cấp addon: ' . $entry['name'] . ' x' . $entry['qty'],
'months' => 0,
'quantity' => $entry['qty'],
'unit_price' => $unitPrice,
'total_price' => $totalPrice,
];
}
$invoice = Invoice::create([
'invoice_number' => OrderHelper::generateOrderNumber('INV'),
'customer_id' => $service->customer_id,
'order_id' => $orderItem->order_id,
'service_id' => $service->id,
'invoice_type' => self::INVOICE_TYPE_UPGRADE,
'sub_total' => $total,
'discount_amount' => 0,
'tax' => 0,
'total' => $total,
'status' => InvoiceStatus::UNPAID->value,
'due_date' => now()->addDays(3)->toDateString(),
]);
foreach ($lines as $line) {
InvoiceItem::create($line + ['invoice_id' => $invoice->id]);
}
return $invoice;
});
} catch (Throwable $e) {
Log::error('VmRebuildController: upgradeAddons invoice creation failed', [
'module_vmware_id' => $vm->id,
'service_id' => $service->id,
'error' => $e->getMessage(),
]);
return response()->json(['error' => true, 'message' => 'Không thể tạo yêu cầu nâng cấp, vui lòng thử lại sau.'], 500);
}
$this->activityLogger->log(
event: 'upgrade_addons',
event: 'upgrade_addons_requested',
logName: 'VM',
description: "Customer {$customer->email} nâng cấp addons VM: {$vm->name} - áp dụng: " . implode(', ', $applied ?: ['none']),
description: "Customer {$customer->email} yêu cầu nâng cấp addons VM: {$vm->name}, hóa đơn #{$invoice->invoice_number}",
subject: $vm,
newValues: array_filter(['cpu' => $payload['cpu'] ?? null, 'ram' => $payload['ram'] ?? null, 'disk' => $payload['disk'] ?? null]),
newValues: ['invoice_id' => $invoice->id, 'addons' => $resolved],
);
return response()->json([
'error' => false,
'message' => 'Đã gửi yêu cầu nâng cấp addons',
'data' => [
'applied' => $applied,
'note' => 'bandwidth/gpu hiện được ghi nhận yêu cầu, chưa có luồng tự động áp vào VM',
],
'message' => 'Đã tạo hóa đơn nâng cấp. Vui lòng thanh toán để áp dụng vào VM.',
'data' => $this->invoiceResponse($invoice, $vm->order?->order_num),
]);
}
private function prorateUnitPrice(float $price, int $remainingDays, int $cycleDays): int
{
$raw = $price * $remainingDays / $cycleDays;
return (int) (ceil($raw / 1000) * 1000);
}
private function invoiceResponse(Invoice $invoice, ?string $orderNum): array
{
return [
'order_id' => $invoice->order_id,
'order_num' => $orderNum,
'invoice_id' => $invoice->id,
'invoice_number' => $invoice->invoice_number,
'total' => (float) $invoice->total,
'status' => $invoice->status,
'payment_url' => $orderNum ? '/hoa-don/' . $orderNum : null,
];
}
}