'date', 'qty' => 'float', 'created_at' => 'datetime', ]; } /** * Relasi ke model Category */ public function category(): BelongsTo { return $this->belongsTo(Category::class, 'category_id'); } /** * Logic Otomatisasi & Integritas Data */ protected static function booted() { static::saving(function ($supply) { // 1. OTOMATIS GENERATE SLUG if ($supply->isDirty('nama_perlengkapan') || empty($supply->slug)) { $supply->slug = Str::slug($supply->nama_perlengkapan) . '-' . Str::lower(Str::random(5)); } // 2. AUTO-CATEGORIZATION (SMART LOGIC) // Jalankan jika category_id kosong atau nama perlengkapan berubah if (empty($supply->category_id) || $supply->isDirty('nama_perlengkapan')) { $name = strtolower($supply->nama_perlengkapan); $categories = Category::whereNotNull('keywords')->get(); $found = false; foreach ($categories as $cat) { $keywordsArray = explode(',', strtolower($cat->keywords)); foreach ($keywordsArray as $keyword) { $cleanKeyword = trim($keyword); if (!empty($cleanKeyword) && str_contains($name, $cleanKeyword)) { $supply->category_id = $cat->id; $supply->kategori = $cat->name; $found = true; break 2; // Berhenti mencari jika sudah ketemu } } } // 3. FALLBACK LOGIC if (!$found && empty($supply->category_id)) { $default = Category::where('name', 'LIKE', '%Pasir%') ->orWhere('name', 'Umum') ->first(); if ($default) { $supply->category_id = $default->id; $supply->kategori = $default->name; } else { $supply->kategori = $supply->kategori ?: 'Umum'; } } } // 4. SINKRONISASI TEKS KATEGORI // Jika ID kategori diubah manual di form, update teks kolom 'kategori' if ($supply->isDirty('category_id') && !empty($supply->category_id)) { $supply->kategori = $supply->category?->name ?? $supply->kategori; } }); } /** * Accessor: Membantu pengecekan expired di Blade secara rapi * Contoh: @if($supply->is_expired) ... @endif */ public function getIsExpiredAttribute(): bool { return $this->expired_at ? $this->expired_at->isPast() : false; } }