initial commit
This commit is contained in:
+106
-44
@@ -16,7 +16,6 @@ class Cat extends Model
|
||||
|
||||
/**
|
||||
* SINKRONISASI TOTAL: 22 Kolom Database
|
||||
* Memasukkan berat_terakhir, lokasi, dan kolom identitas lainnya.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'nama_kucing', 'ras', 'registry', 'jenis_kelamin', 'tanggal_lahir',
|
||||
@@ -24,9 +23,38 @@ class Cat extends Model
|
||||
'jadwal_vaksin', 'jadwal_obat_cacing', 'jadwal_obat_kutu',
|
||||
'jadwal_grooming', 'induk_jantan_id', 'induk_betina_id',
|
||||
'lokasi_kandang', 'pic_id', 'berat_badan',
|
||||
'pedigree', 'microchip', 'status', 'kode_ems' // Kolom tambahan dari UI Anda
|
||||
'pedigree','sertifikat_ped_file', 'microchip', 'status', 'kode_ems','treatment_status'
|
||||
];
|
||||
|
||||
/**
|
||||
* Logic Otomatisasi (Booted)
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
// A. Sebelum simpan: Sinkronisasi berat_terakhir
|
||||
static::saving(function ($cat) {
|
||||
if ($cat->isDirty('berat_badan')) {
|
||||
$cat->berat_terakhir = $cat->berat_badan;
|
||||
}
|
||||
});
|
||||
|
||||
// B. Setelah update berhasil: Catat ke tabel history
|
||||
static::updated(function ($cat) {
|
||||
if ($cat->wasChanged('berat_badan')) {
|
||||
// Kita gunakan try-catch agar jika tabel history bermasalah, update kucing tidak ikut mati
|
||||
try {
|
||||
$cat->weightHistories()->create([
|
||||
'berat' => $cat->berat_badan,
|
||||
'tanggal_timbang' => now(), // Pastikan kolom ini ada di migrasi Anda
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
// Log error diam-diam agar user tidak melihat Error 500
|
||||
\Illuminate\Support\Facades\Log::error("Gagal mencatat history berat: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Casting Laravel 11/12 Style
|
||||
*/
|
||||
@@ -38,7 +66,7 @@ class Cat extends Model
|
||||
'jadwal_obat_cacing' => 'date',
|
||||
'jadwal_obat_kutu' => 'date',
|
||||
'jadwal_grooming' => 'date',
|
||||
'registry' => 'array',
|
||||
'registry' => 'array', // Otomatis mengurus JSON di DB
|
||||
'berat_badan' => 'decimal:2',
|
||||
'berat_terakhir' => 'decimal:2',
|
||||
];
|
||||
@@ -48,10 +76,10 @@ class Cat extends Model
|
||||
/* RELATIONS */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
public function treatments(): HasMany
|
||||
{
|
||||
return $this->hasMany(Treatment::class);
|
||||
}
|
||||
public function treatments()
|
||||
{
|
||||
return $this->hasMany(Treatment::class, 'cat_id');
|
||||
}
|
||||
|
||||
public function weightHistories(): HasMany
|
||||
{
|
||||
@@ -89,26 +117,38 @@ class Cat extends Model
|
||||
]);
|
||||
}
|
||||
|
||||
public function registrations(): HasMany
|
||||
{
|
||||
return $this->hasMany(CatRegistration::class)->orderByDesc('is_primary')->orderBy('id');
|
||||
}
|
||||
|
||||
public function primaryRegistration()
|
||||
{
|
||||
return $this->hasOne(CatRegistration::class)->where('is_primary', true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* ACCESSORS */
|
||||
/* ACCESSORS (Penyempurnaan Null-Safety & Logic) */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
protected function genderIcon(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
// Database menggunakan enum 'Jantan'/'Betina' (Case Sensitive)
|
||||
get: fn () => strtolower($this->jenis_kelamin) === 'jantan'
|
||||
? '<i class="fas fa-mars text-indigo-500"></i>'
|
||||
: '<i class="fas fa-venus text-rose-500"></i>'
|
||||
get: fn () => strtolower($this->jenis_kelamin ?? '') === 'jantan'
|
||||
? '<i class="fas fa-mars text-indigo-500" title="Jantan"></i>'
|
||||
: '<i class="fas fa-venus text-rose-500" title="Betina"></i>'
|
||||
);
|
||||
}
|
||||
|
||||
protected function fotoUrl(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->foto
|
||||
? Storage::url($this->foto)
|
||||
: asset('images/default-cat.png')
|
||||
get: function () {
|
||||
if ($this->foto && Storage::disk('public')->exists($this->foto)) {
|
||||
return Storage::url($this->foto);
|
||||
}
|
||||
return asset('images/default-cat.png');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -126,57 +166,79 @@ class Cat extends Model
|
||||
);
|
||||
}
|
||||
|
||||
// Usia presisi untuk laporan medis (Tahun, Bulan, Hari)
|
||||
protected function usiaDetail(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
if (!$this->tanggal_lahir) return 'Data N/A';
|
||||
$diff = $this->tanggal_lahir->diff(now());
|
||||
return "{$diff->y} Thn, {$diff->m} Bln, {$diff->d} Hari";
|
||||
return "{$diff->y}th {$diff->m}bln {$diff->d}hr";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function registryLabel(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->registry ?? 'NON-PED'
|
||||
);
|
||||
}
|
||||
|
||||
// Badges untuk registry
|
||||
/**
|
||||
* Badge Registry yang disempurnakan (lebih bersih)
|
||||
*/
|
||||
protected function registryBadges(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
// Jika tidak ada registry
|
||||
if (empty($this->registry)) {
|
||||
return '<span class="text-[9px] text-slate-400 font-bold italic tracking-widest">NON-PED</span>';
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
$registries = $this->registry;
|
||||
|
||||
// Jika kosong atau eksplisit memilih NON-PED
|
||||
if (empty($registries) || (is_array($registries) && in_array('NON-PED', $registries))) {
|
||||
return '<span class="px-2 py-0.5 bg-slate-100 text-slate-400 border border-slate-200 rounded-lg text-[8px] font-black uppercase tracking-tighter">NON-PED</span>';
|
||||
}
|
||||
|
||||
// Mapping warna untuk setiap federasi
|
||||
$config = [
|
||||
'ICA' => ['bg' => 'bg-blue-50', 'text' => 'text-blue-700', 'border' => 'border-blue-100'],
|
||||
'CFA' => ['bg' => 'bg-rose-50', 'text' => 'text-rose-700', 'border' => 'border-rose-100'],
|
||||
'WCF' => ['bg' => 'bg-emerald-50', 'text' => 'text-emerald-700', 'border' => 'border-emerald-100'],
|
||||
'FFF' => ['bg' => 'bg-amber-50', 'text' => 'text-amber-700', 'border' => 'border-amber-100'],
|
||||
'ICA' => 'bg-blue-50 text-blue-700 border-blue-100',
|
||||
'CFA' => 'bg-rose-50 text-rose-700 border-rose-100',
|
||||
'WCF' => 'bg-emerald-50 text-emerald-700 border-emerald-100',
|
||||
'FFF' => 'bg-amber-50 text-amber-700 border-amber-100',
|
||||
];
|
||||
|
||||
$html = '<div class="flex flex-wrap gap-1">';
|
||||
$registries = is_array($this->registry) ? $this->registry : [$this->registry];
|
||||
$list = is_array($registries) ? $registries : [$registries];
|
||||
|
||||
foreach ($registries as $reg) {
|
||||
$style = $config[$reg] ?? ['bg' => 'bg-slate-50', 'text' => 'text-slate-600', 'border' => 'border-slate-200'];
|
||||
|
||||
$html .= "<span class='px-2 py-0.5 {$style['bg']} {$style['text']} {$style['border']} border rounded-lg text-[8px] font-black uppercase tracking-tighter shadow-sm'>";
|
||||
$html .= $reg;
|
||||
$html .= "</span>";
|
||||
foreach ($list as $reg) {
|
||||
if($reg === 'NON-PED') continue; // Skip jika tercampur (opsional)
|
||||
$uReg = strtoupper($reg);
|
||||
$style = $config[$uReg] ?? 'bg-slate-50 text-slate-600 border-slate-200';
|
||||
$html .= "<span class='px-2 py-0.5 border rounded-lg text-[8px] font-black uppercase tracking-tighter shadow-sm {$style}'>{$uReg}</span>";
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function medicalRecords()
|
||||
{
|
||||
// Mengambil riwayat, terbaru diletakkan paling atas
|
||||
return $this->hasMany(MedicalRecord::class)->orderBy('date_given', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sinkronkan kolom status perawatan dari treatment yang masih aktif.
|
||||
* Nilai 1 = dalam perawatan, 2 = sehat.
|
||||
*/
|
||||
public function updateTreatmentStatus(): void
|
||||
{
|
||||
$status = $this->treatments()->where('status_perawatan', 1)->exists() ? 1 : 2;
|
||||
$this->forceFill(['treatment_status' => $status])->saveQuietly();
|
||||
}
|
||||
/**
|
||||
* Scope untuk filter kucing yang sedang sakit (Under Treatment)
|
||||
*/
|
||||
public function scopeUnderTreatment($query)
|
||||
{
|
||||
// Hapus logika whereHas lama, ganti dengan ini:
|
||||
return $query->where('treatment_status', 1);
|
||||
}
|
||||
|
||||
public function scopeHealthy($query)
|
||||
{
|
||||
return $query->where('treatment_status', 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user