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
@@ -8,6 +8,7 @@ use App\Http\Resources\Api\Client\Ticket\ClientTicketResource;
use App\Jobs\Ticket\TicketJobs;
use App\Mail\TicketCreated;
use App\Mail\Admin\TicketAdminNotification;
use App\Models\Service;
use App\Models\Setting;
use App\Models\Ticket;
use App\Models\Notification;
@@ -69,6 +70,15 @@ class TicketController extends Controller
/**
* Create a new ticket for the authenticated customer.
*/
private function assertServiceTicketable(string $serviceUuid, int $customerId): void
{
$failed = Service::where('uuid', $serviceUuid)->where('customer_id', $customerId)->where('status', 'failed')->exists();
abort_unless($failed, 404, 'Dịch vụ không tồn tại.');
$hasOpenTicket = Ticket::where('service_uuid', $serviceUuid)->whereIn('status', Ticket::UNRESOLVED_STATUSES)->exists();
abort_if($hasOpenTicket, 422, 'Dịch vụ này đã có ticket đang được xử lý.');
}
public function store(Request $request)
{
$request->validate([
@@ -76,11 +86,17 @@ class TicketController extends Controller
'description' => ['required', 'string', 'min:20'],
'room' => ['nullable', 'string'],
'data' => ['nullable', 'array'],
'service_uuid' => ['nullable', 'uuid'],
'images' => ['nullable', 'array', 'max:5'],
'images.*' => ['image', 'mimes:jpg,jpeg,png,gif,webp', 'max:5120'],
]);
$customer = auth('client')->user();
$serviceUuid = $request->input('service_uuid');
if ($serviceUuid) {
$this->assertServiceTicketable($serviceUuid, $customer->id);
}
$ticketNum = 'TKT-' . now()->format('Ymd') . '-' . strtoupper(Str::random(5));
@@ -96,6 +112,7 @@ class TicketController extends Controller
'data' => $request->input('data') ? json_encode($request->input('data')) : null,
'gallery' => $gallery ?: null,
'customer_id' => $customer->id,
'service_uuid' => $serviceUuid,
]);
TicketJobs::dispatch($ticket, $customer);