orderBy('name'); }); } // 2. Casting protected function casts(): array { return [ 'reject_stock' => 'integer', 'stock' => 'integer', 'retail_stock' => 'integer', ]; } // 4. Attribute public function rejectStockFormatted(): Attribute { return Attribute::make( get: fn () => number_format($this->reject_stock, 0, ',', '.'), ); } public function stockFormatted(): Attribute { return Attribute::make( get: fn () => number_format($this->stock, 0, ',', '.'), ); } public function retailStockFormatted(): Attribute { return Attribute::make( get: fn () => number_format($this->retail_stock, 0, ',', '.'), ); } // 5. Other Methods public static function mediaModuleName(): string { return 'product'; } public static function minStock(): int { return self::MIN_STOCK; } public function registerMediaCollections(): void { $this->addMediaCollection('images'); } // 6. Relation public function cuttingResults(): HasMany { return $this->hasMany(CuttingResult::class); } public function orderItems(): HasMany { return $this->hasMany(OrderItem::class); } public function prices(): HasMany { return $this->hasMany(ProductPrice::class, 'variant_id'); } public function product(): BelongsTo { return $this->belongsTo(Product::class)->withTrashed(); } public function stockMutations(): MorphMany { return $this->morphMany(StockMutation::class, 'stockable'); } }