ProductStatus::class, ]; } // 3. Scope (grouped by column, then alphabetical) // Column Group: status #[Scope] protected function active(Builder $query): void { $query->where('status', ProductStatus::ACTIVE); } #[Scope] protected function inactive(Builder $query): void { $query->where('status', ProductStatus::INACTIVE); } #[Scope] protected function draft(Builder $query): void { $query->where('status', ProductStatus::DRAFT); } // 4. Attribute public function totalRejectStockFormatted(): Attribute { return Attribute::make( get: function () { $allVariants = $this->getAttribute('all_variants'); return $allVariants !== null ? number_format($allVariants->sum('reject_stock'), 0, ',', '.') : '-'; }, ); } public function totalRetailStockFormatted(): Attribute { return Attribute::make( get: function () { $allVariants = $this->getAttribute('all_variants'); return $allVariants !== null ? number_format($allVariants->sum('retail_stock'), 0, ',', '.') : '-'; }, ); } public function totalStockFormatted(): Attribute { return Attribute::make( get: function () { $allVariants = $this->getAttribute('all_variants'); return $allVariants !== null ? number_format($allVariants->sum('stock'), 0, ',', '.') : '-'; }, ); } // 5. Other Methods public static function getActiveWithVariantsAndCategories(): Collection { return self::query() ->active() ->with([ 'categories', 'variants' => fn ($query) => $query ->with('media'), ]) ->get(); } // 6. Relation public function categories(): BelongsToMany { return $this->belongsToMany(Category::class, 'product_categories'); } public function ownerVerificationRequests(): MorphMany { return $this->morphMany(OwnerVerificationRequest::class, 'subject'); } public function pendingOwnerVerificationRequest(): MorphOne { return $this->morphOne(OwnerVerificationRequest::class, 'subject') ->where('status', OwnerVerificationStatus::PENDING) ->latestOfMany(); } public function variants(): HasMany { return $this->hasMany(ProductVariant::class)->orderBy('name'); } }