'bool', 'exclude_from_stock' => 'bool', 'pos' => 'int', 'default_factor' => 'decimal:2', 'min_stock_alert' => 'decimal:2', 'density' => 'decimal:4', 'delivery_time_days' => 'integer', ]; protected $fillable = [ 'name', 'trans_name', 'alt_name', 'inci', 'trans_inci', 'effect', 'trans_effect', 'active', 'pos', 'default_factor', 'min_stock_alert', 'density', 'exclude_from_stock', 'material_quality_id', 'tax_rate_id', 'delivery_time', 'delivery_time_days', 'storage_room_id', 'storage_shelf_id', 'storage_slot_id', ]; /** * @return BelongsTo */ public function materialQuality(): BelongsTo { return $this->belongsTo(MaterialQuality::class); } /** * @return BelongsTo */ public function taxRate(): BelongsTo { return $this->belongsTo(TaxRate::class); } /** * @return BelongsToMany */ public function suppliers(): BelongsToMany { return $this->belongsToMany(Supplier::class, 'ingredient_supplier') ->withPivot(['preferred', 'supplier_sku', 'url']) ->withTimestamps(); } public function products() { return $this->belongsToMany(Product::class, 'product_ingredients') ->withPivot('id', 'pos', 'gram', 'factor') ->withTimestamps() ->orderByPivot('pos'); } public function product_ingredients() { return $this->hasMany(ProductIngredient::class, 'ingredient_id'); } /** * @return BelongsTo */ public function storageRoom(): BelongsTo { return $this->belongsTo(StorageRoom::class); } /** * @return BelongsTo */ public function storageShelf(): BelongsTo { return $this->belongsTo(StorageShelf::class); } /** * @return BelongsTo */ public function storageSlot(): BelongsTo { return $this->belongsTo(StorageSlot::class); } /** * Lagerort-Anzeige im Schema „Raum 1 | Regal 3 | A" (nur gepflegte Teile). */ public function storageLabel(): ?string { $parts = array_filter([ $this->storageRoom?->label, $this->storageShelf?->label, $this->storageSlot?->label, ]); return $parts === [] ? null : implode(' | ', $parts); } /** * Nur INCI, die in der Hersteller-Rezeptur mindestens eines aktiven Produkts vorkommen * (fachlich „aktiv" laut Kunde — nicht zu verwechseln mit `ingredients.active`). * * @param Builder $query * @return Builder */ public function scopeUsedInActiveRecipes($query) { return $query->whereHas('product_ingredients', function ($q) { $q->where('recipe_type', 'manufacturer') ->whereHas('product', fn ($p) => $p->where('active', true)); }); } }