type === null && $service->product_id) { $service->type = Product::query()->where('id', $service->product_id)->value('product_type'); } }); } protected $table = 'services'; public const HOSTING_ACCOUNT_RELATIONS = [ 'hostingAccount.server:id,name,ip_address', 'hostingAccount.domain:id,domain_name', ]; protected $fillable = [ 'uuid', 'customer_id', 'product_id', 'type', 'order_item_id', 'invoice_id', 'vm_id', 'server_name', 'status', 'auto_renew', 'started_at', 'expires_at', 'suspended_at', 'cancelled_at', 'refunded_at', 'retry_requested_at', 'note', 'requirements', 'feedback', 'registrar_reference', 'kyc_url', 'rejection_reason', 'registrant_type', 'registrant_info', ]; protected $casts = [ 'auto_renew' => 'boolean', 'started_at' => 'datetime', 'expires_at' => 'datetime', 'suspended_at' => 'datetime', 'cancelled_at' => 'datetime', 'refunded_at' => 'datetime', 'retry_requested_at' => 'datetime', 'registrant_info' => 'array', ]; // ------------------------------------------------------------------------- // Relationships // ------------------------------------------------------------------------- public function customer() { return $this->belongsTo(Customer::class); } public function product() { return $this->belongsTo(Product::class, 'product_id'); } /** The order item that triggered provisioning. */ public function orderItem() { return $this->belongsTo(OrderItem::class, 'order_item_id'); } /** The most recent invoice covering this service (updated on renewal). */ public function invoice() { return $this->belongsTo(Invoice::class, 'invoice_id'); } /** Configurable resources / features attached to this service. */ public function addons() { return $this->hasMany(ServiceAddon::class, 'service_id'); } /** The VPS/VM associated with this service — FK: services.vm_id → module_vmware.id */ public function vmware() { return $this->belongsTo(ModuleVmware::class, 'vm_id'); } public function resolveVmware(): ?ModuleVmware { return $this->vmware ?? $this->orderItem?->order?->vmWare?->first(); } /** The Plesk hosting account associated with this service, if type = hosting. */ public function hostingAccount() { return $this->hasOne(ModuleHostingAccount::class, 'service_id'); } // ------------------------------------------------------------------------- // Helpers // ------------------------------------------------------------------------- public function isActive(): bool { return $this->status === 'active'; } public function isExpired(): bool { return $this->expires_at !== null && $this->expires_at->isPast(); } public function getStatusLabelAttribute(): string { return match ($this->status) { 'pending' => 'Chờ kích hoạt', 'active' => 'Đang hoạt động', 'suspended' => 'Tạm ngưng', 'expired' => 'Hết hạn', 'cancelled' => 'Đã hủy', 'terminated' => 'Đã xóa', default => ucfirst($this->status), }; } }