*/ use HasFactory, LogsPartHistory; protected $fillable = [ 'part_number', 'name', 'description', 'manufacturer', 'category', 'cost_price', 'sell_price', 'quantity_on_hand', 'minimum_stock_level', 'maximum_stock_level', 'location', 'supplier_id', 'supplier_part_number', 'lead_time_days', 'status', 'barcode', 'weight', 'dimensions', 'warranty_period', 'image', ]; protected $casts = [ 'cost_price' => 'decimal:2', 'sell_price' => 'decimal:2', 'quantity_on_hand' => 'integer', 'minimum_stock_level' => 'integer', 'maximum_stock_level' => 'integer', 'lead_time_days' => 'integer', 'weight' => 'decimal:2', ]; public function serviceOrders(): BelongsToMany { return $this->belongsToMany(ServiceOrder::class, 'service_items') ->withPivot(['quantity', 'price', 'total']) ->withTimestamps(); } public function supplier(): BelongsTo { return $this->belongsTo(Supplier::class); } public function stockMovements(): HasMany { return $this->hasMany(StockMovement::class); } public function purchaseOrderItems(): HasMany { return $this->hasMany(PurchaseOrderItem::class); } public function histories(): HasMany { return $this->hasMany(PartHistory::class); } public function isLowStock(): bool { return $this->quantity_on_hand <= $this->minimum_stock_level; } public function getMarkupPercentageAttribute() { if ($this->cost_price > 0) { return round((($this->sell_price - $this->cost_price) / $this->cost_price) * 100, 2); } return 0; } public function getStockStatusAttribute(): string { if ($this->quantity_on_hand <= 0) { return 'out_of_stock'; } elseif ($this->quantity_on_hand <= $this->minimum_stock_level) { return 'low_stock'; } elseif ($this->quantity_on_hand >= $this->maximum_stock_level) { return 'overstock'; } return 'in_stock'; } public function getStockStatusColorAttribute(): string { return match($this->stock_status) { 'out_of_stock' => 'text-red-600 dark:text-red-400', 'low_stock' => 'text-orange-600 dark:text-orange-400', 'overstock' => 'text-purple-600 dark:text-purple-400', 'in_stock' => 'text-green-600 dark:text-green-400', default => 'text-gray-600 dark:text-gray-400', }; } public function getStockValueAttribute(): float { return $this->quantity_on_hand * $this->cost_price; } public function needsReorder(): bool { return $this->quantity_on_hand <= $this->minimum_stock_level; } public function scopeLowStock($query) { return $query->whereColumn('quantity_on_hand', '<=', 'minimum_stock_level'); } public function scopeOutOfStock($query) { return $query->where('quantity_on_hand', '<=', 0); } public function scopeByCategory($query, $category) { return $query->where('category', $category); } public function scopeActive($query) { return $query->where('status', 'active'); } }