feat(vm): hoàn tiền khi cấp VM lỗi, theo dõi job queue, uuid dịch vụ cho ticket, chuẩn hoá RAM addon

- VmProvisionException/VmProvisionRefund xử lý lỗi cấp phát VM
- QueueJobInspector + QueueMonitorController xem chi tiết job
- Thêm service uuid cho ticket, thời lượng cho activity_logs
- Migration chuẩn hoá RAM addon sang MB, trạng thái deleting cho snapshot

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-30 11:54:05 +07:00
co-authored by Claude Sonnet 5.5
parent 7136bec265
commit 62596d9063
32 changed files with 514 additions and 107 deletions
+20
View File
@@ -4,6 +4,7 @@ namespace App\Services\Api\Order;
use App\Enums\Invoice\InvoiceStatus;
use App\Enums\Order\OrderStatus;
use App\Enums\Product\ProductTypeEnums;
use App\Helpers\OrderHelper;
use App\Models\Order;
use App\Models\Product;
@@ -13,6 +14,7 @@ use App\Repositories\Api\Service\ServiceRepository;
use App\Services\InvoicePaymentService;
use App\Services\AdminPaymentNotifier;
use App\Services\Coupon\CouponService;
use App\Services\VirtualMachine\VmIpReservationService;
use App\Support\AddonQuantityValidator;
use Illuminate\Support\Facades\DB;
@@ -25,6 +27,7 @@ class OrderService
protected InvoicePaymentService $invoicePaymentService,
protected AdminPaymentNotifier $adminPaymentNotifier,
protected CouponService $couponService,
protected VmIpReservationService $vmIpReservation,
) {}
// =========================================================================
@@ -46,6 +49,8 @@ class OrderService
['product' => $product, 'base_price' => $basePrice, 'addons_meta' => $addonsMeta, 'sub_total' => $subTotal] = $this->quote($data);
$couponCode = $data['coupon_code'] ?? null;
$this->assertInfrastructureAvailable([$product]);
$expectedTotal = $couponCode
? $subTotal - $this->couponService->preview($couponCode, $customer, $product, $data['billing_cycle'], $subTotal)['discount']
: $subTotal;
@@ -100,6 +105,19 @@ class OrderService
});
}
private function assertInfrastructureAvailable(iterable $products): void
{
$needsVm = collect($products)->contains(fn ($product) => in_array(
ProductTypeEnums::tryFrom($product?->category?->type ?? ''),
[ProductTypeEnums::VPS, ProductTypeEnums::CLOUD],
true
));
if ($needsVm && !$this->vmIpReservation->hasFreeIp()) {
throw new \InvalidArgumentException('Hiện tại hạ tầng đang đầy vui lòng liên hệ quản trị viên');
}
}
/**
* Giá niêm yết (chu kỳ + addon) tính phía server; nguồn duy nhất cho create() và preview mã giảm giá.
*
@@ -143,6 +161,8 @@ class OrderService
throw new \InvalidArgumentException('Đơn hàng đã được thanh toán hoặc đang xử lý.');
}
$this->assertInfrastructureAvailable($order->orderItems->map->product);
$processedOrder = DB::transaction(function () use ($order, $method) {
$customer = $order->customer;