'boolean', 'is_unlimited' => 'boolean', 'published_at' => 'date', 'gallery' => 'array', 'product_type' => 'string', ]; protected static function boot() { parent::boot(); static::saving(function ($product) { if ($product->product_categories_id) { $category = ProductCategories::find($product->product_categories_id); if ($category && $category->type) { $product->product_type = $category->type; } } }); } /** * Relationship: Product belongs to a Category */ public function category() { return $this->belongsTo(ProductCategories::class, 'product_categories_id'); } /** * Relationship: Product has many OS versions (pivot table: os_product) */ public function osVersions() { return $this->belongsToMany(Os::class, 'os_product', 'product_id', 'os_id') ->withTimestamps(); } /** * Relationship: Product has many OS via product_os table (VPS OS selection) */ public function operatingSystems() { return $this->belongsToMany(Os::class, 'os_product', 'product_id', 'os_id') ->withTimestamps(); } /** * Relationship: Product has many Control Panels (for Hosting) */ public function controlPanels() { return $this->belongsToMany(ControlPanel::class, 'product_control_panel') ->withPivot(['price_modifier', 'is_default']) ->withTimestamps(); } /** * Relationship: Product has many pricings */ public function pricings() { return $this->hasMany(ProductPricings::class, 'product_id'); } /** * Relationship: Product has many order items */ public function orderItems() { return $this->hasMany(OrderItem::class, 'product_id'); } /** * Relationship: Product has many orders through order items */ public function orders() { return $this->hasManyThrough(Order::class, OrderItem::class, 'product_id', 'id', 'id', 'order_id'); } /** * Legacy: Many-to-many categories (if still needed) */ public function categories() { return $this->belongsToMany(ProductCategories::class, 'product_product_category', 'product_id', 'product_category_id'); } /** * Relationship: Product has many addons (through product type) * Addons are linked via type in product_addon table */ public function ipAddress() { return $this->belongsTo(ModuleIpAddress::class, 'module_ip_address'); } public function provisioningHost() { return $this->belongsTo(\App\Models\ModuleHost::class, 'module_host_id'); } public function provisioningDatastore() { return $this->belongsTo(\App\Models\ModuleDatastore::class, 'module_datastore_id'); } public function addons() { return $this->hasMany(Addon::class, 'type', 'product_type') ->orderBy('sort_order'); } /** * Get monthly pricing (or first available pricing) */ public function getMonthlyPricingAttribute() { $pricings = $this->pricings; return $pricings->firstWhere('billing_cycle', 'monthly') ?? $pricings->where('is_active', 1)->sortBy('price')->first(); } /** * Get display price (sale price if available, otherwise regular price) */ public function getPriceAttribute() { $pricing = $this->monthlyPricing; return $pricing ? $pricing->price : 0; } public function getPriceSaleAttribute() { $pricing = $this->monthlyPricing; return $pricing ? $pricing->price_sale : null; } }