259 lines
9.7 KiB
PHP
259 lines
9.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\{Cat, User, Matting};
|
|
use App\Traits\LogsActivity;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\View\View;
|
|
use Illuminate\Support\Facades\{Storage, DB, Gate}; // Tambahkan Gate
|
|
use Illuminate\Support\Carbon;
|
|
use Barryvdh\DomPDF\Facade\Pdf;
|
|
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
|
use Intervention\Image\Laravel\Facades\Image;
|
|
|
|
class CatController extends Controller
|
|
{
|
|
use LogsActivity;
|
|
|
|
/**
|
|
* Menampilkan daftar kucing dengan filter cerdas.
|
|
*/
|
|
public function index(Request $request): View
|
|
{
|
|
// Proteksi Akses: Read
|
|
Gate::authorize('check-access', ['cats', 'read']);
|
|
|
|
$query = Cat::query()->with(['pic', 'sire', 'dam']);
|
|
|
|
// 1. Pencarian Global
|
|
if ($request->filled('search')) {
|
|
$search = $request->search;
|
|
$query->where(function($q) use ($search) {
|
|
$q->where('nama_kucing', 'like', "%{$search}%")
|
|
->orWhere('ras', 'like', "%{$search}%")
|
|
->orWhere('microchip', 'like', "%{$search}%")
|
|
->orWhere('pedigree', 'like', "%{$search}%")
|
|
->orWhere('kode_ems', 'like', "%{$search}%");
|
|
});
|
|
}
|
|
|
|
// 2. Filter Spesifik
|
|
if ($request->filled('status')) $query->where('status', $request->status);
|
|
if ($request->filled('ras')) $query->where('ras', $request->ras);
|
|
if ($request->filled('gender')) $query->where('jenis_kelamin', $request->gender);
|
|
|
|
$cats = $query->latest()->paginate(15)->withQueryString();
|
|
|
|
// 3. Statistik Dashboard (Tetap Utuh)
|
|
$totalCats = Cat::count();
|
|
$safeWords = ['sehat', 'normal', 'aktif', 'sembuh', '-', 'tidak ada', 'clean'];
|
|
$sickCats = Cat::whereNotNull('riwayat_sakit_terakhir')
|
|
->where(function($q) use ($safeWords) {
|
|
foreach ($safeWords as $word) {
|
|
$q->where('riwayat_sakit_terakhir', 'NOT LIKE', "%{$word}%");
|
|
}
|
|
})->count();
|
|
|
|
$breeds = Cat::distinct()->pluck('ras');
|
|
|
|
return view('pages.cats.index', compact('cats', 'totalCats', 'sickCats', 'breeds'));
|
|
}
|
|
|
|
public function create(): View
|
|
{
|
|
// Proteksi Akses: Create
|
|
Gate::authorize('check-access', ['cats', 'create']);
|
|
|
|
$sires = Cat::where('jenis_kelamin', 'Jantan')->get(['id', 'nama_kucing']);
|
|
$dams = Cat::where('jenis_kelamin', 'Betina')->get(['id', 'nama_kucing']);
|
|
$users = User::all(['id', 'name']);
|
|
|
|
return view('pages.cats.create', compact('sires', 'dams', 'users'));
|
|
}
|
|
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
Gate::authorize('check-access', ['cats', 'create']);
|
|
|
|
$validated = $this->validateCat($request);
|
|
|
|
return DB::transaction(function () use ($request, $validated) {
|
|
if ($request->hasFile('foto')) {
|
|
$validated['foto'] = $this->handleImageUpload($request->file('foto'));
|
|
}
|
|
|
|
if (isset($validated['berat_badan'])) {
|
|
$validated['berat_terakhir'] = $validated['berat_badan'];
|
|
}
|
|
|
|
if (empty($validated['status'])) {
|
|
$validated['status'] = ($request->induk_jantan_id || $request->induk_betina_id) ? 'Kitten' : 'Active';
|
|
}
|
|
|
|
// Memastikan registry disimpan sebagai JSON jika model tidak melakukan casting
|
|
if (isset($validated['registry'])) {
|
|
$validated['registry'] = $validated['registry'];
|
|
}
|
|
|
|
$cat = Cat::create($validated);
|
|
$this->logAction('CREATED', $cat, "Mendaftarkan pasien baru: {$cat->nama_kucing}", 'Cat');
|
|
|
|
return redirect()->route('cats.index')->with('success', "{$cat->nama_kucing} berhasil didaftarkan.");
|
|
});
|
|
}
|
|
|
|
public function show(Cat $cat): View
|
|
{
|
|
Gate::authorize('check-access', ['cats', 'read']);
|
|
|
|
$cat->load([
|
|
'treatments' => fn($q) => $q->latest(),
|
|
'sire', 'dam', 'pic',
|
|
'weightHistories' => fn($q) => $q->latest()->limit(12)
|
|
]);
|
|
return view('pages.cats.show', compact('cat'));
|
|
}
|
|
|
|
public function edit(Cat $cat): View
|
|
{
|
|
// Proteksi: Akses Update
|
|
Gate::authorize('check-access', ['cats', 'update']);
|
|
|
|
$sires = Cat::where('jenis_kelamin', 'Jantan')->where('id', '!=', $cat->id)->get(['id', 'nama_kucing']);
|
|
$dams = Cat::where('jenis_kelamin', 'Betina')->where('id', '!=', $cat->id)->get(['id', 'nama_kucing']);
|
|
$users = User::all(['id', 'name']);
|
|
|
|
return view('pages.cats.edit', compact('cat', 'sires', 'dams', 'users'));
|
|
}
|
|
|
|
public function update(Request $request, Cat $cat): RedirectResponse
|
|
{
|
|
Gate::authorize('check-access', ['cats', 'update']);
|
|
|
|
$validated = $this->validateCat($request, $cat->id);
|
|
|
|
return DB::transaction(function () use ($request, $validated, $cat) {
|
|
if ($request->hasFile('foto')) {
|
|
if ($cat->foto) Storage::disk('public')->delete($cat->foto);
|
|
$validated['foto'] = $this->handleImageUpload($request->file('foto'));
|
|
}
|
|
|
|
if ($request->filled('berat_badan')) {
|
|
$validated['berat_terakhir'] = $request->berat_badan;
|
|
if ($cat->berat_badan != $request->berat_badan) {
|
|
$cat->weightHistories()->create(['berat' => $request->berat_badan]);
|
|
}
|
|
}
|
|
|
|
$cat->update($validated);
|
|
$this->logAction('UPDATED', $cat, "Update data medis/profil: {$cat->nama_kucing}", 'Cat');
|
|
|
|
return redirect()->route('cats.index')->with('success', 'Data berhasil diperbarui.');
|
|
});
|
|
}
|
|
|
|
public function destroy(Cat $cat): RedirectResponse
|
|
{
|
|
Gate::authorize('check-access', ['cats', 'delete']);
|
|
|
|
$isParent = Matting::where('sire_id', $cat->id)->orWhere('dam_id', $cat->id)->exists();
|
|
|
|
if ($isParent) {
|
|
return back()->with('error', "Gagal! {$cat->nama_kucing} tidak bisa dihapus karena sudah menjadi Induk.");
|
|
}
|
|
|
|
return DB::transaction(function () use ($cat) {
|
|
$name = $cat->nama_kucing;
|
|
if ($cat->foto) Storage::disk('public')->delete($cat->foto);
|
|
|
|
$this->logAction('DELETED', $cat, "Menghapus data permanen: {$name}", 'Cat');
|
|
$cat->delete();
|
|
|
|
return redirect()->route('cats.index')->with('success', "Data {$name} telah dihapus.");
|
|
});
|
|
}
|
|
|
|
public function getCatData($id): JsonResponse
|
|
{
|
|
$cat = Cat::find($id);
|
|
if (!$cat) return response()->json(['error' => 'Not found'], 404);
|
|
|
|
return response()->json([
|
|
'tgl_lahir' => $cat->tanggal_lahir ? $cat->tanggal_lahir->format('Y-m-d') : '',
|
|
'pedigree' => $cat->pedigree ?? '',
|
|
'microchip' => $cat->microchip ?? '',
|
|
'kode_ems' => $cat->kode_ems ?? '',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* PDF ID Card / Medical Pass
|
|
* PENYEMPURNAAN: Perbaikan Barcode (Base64 SVG)
|
|
*/
|
|
public function downloadPdf(Cat $cat)
|
|
{
|
|
Gate::authorize('check-access', ['cats', 'read']);
|
|
|
|
$cat->load(['pic', 'sire', 'dam']);
|
|
|
|
// FIX: Konversi SVG ke Base64 agar tampil di domPDF tanpa Imagick
|
|
$qrCodeRaw = QrCode::format('svg')
|
|
->size(150)
|
|
->margin(1)
|
|
->generate(route('cats.show', $cat->id));
|
|
|
|
$qrCode = base64_encode($qrCodeRaw);
|
|
|
|
$pdf = Pdf::loadView('pages.cats.pdf-card', [
|
|
'cat' => $cat,
|
|
'qrCode' => $qrCode, // Dikirim sebagai Base64
|
|
'printedAt' => Carbon::now()->translatedFormat('d F Y H:i')
|
|
]);
|
|
|
|
return $pdf->setPaper([0, 0, 300, 500], 'portrait')
|
|
->stream('MEDICAL_PASS_' . strtoupper($cat->nama_kucing) . '.pdf');
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* HELPERS (TETAP UTUH) */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
private function validateCat(Request $request, $id = null)
|
|
{
|
|
return $request->validate([
|
|
'nama_kucing' => 'required|string|max:255',
|
|
'ras' => 'required|string',
|
|
'jenis_kelamin' => 'required|in:Jantan,Betina',
|
|
'tanggal_lahir' => 'nullable|date',
|
|
'foto' => 'nullable|image|mimes:jpg,jpeg,png|max:3072',
|
|
'registry' => 'nullable|array',
|
|
'registry.*' => 'string',
|
|
'pedigree' => 'nullable|string|max:255',
|
|
'microchip' => 'nullable|string|max:255',
|
|
'kode_ems' => 'nullable|string|max:255',
|
|
'status' => 'nullable|string',
|
|
'induk_jantan_id' => 'nullable|exists:cats,id',
|
|
'induk_betina_id' => 'nullable|exists:cats,id',
|
|
'lokasi_kandang' => 'nullable|string',
|
|
'pic_id' => 'nullable|exists:users,id',
|
|
'berat_badan' => 'nullable|numeric|min:0',
|
|
'riwayat_sakit_terakhir' => 'nullable|string',
|
|
'jadwal_vaksin' => 'nullable|date',
|
|
'jadwal_obat_cacing' => 'nullable|date',
|
|
'jadwal_obat_kutu' => 'nullable|date',
|
|
'jadwal_grooming' => 'nullable|date',
|
|
]);
|
|
}
|
|
|
|
private function handleImageUpload($file): string
|
|
{
|
|
$filename = 'cat_' . uniqid() . '.png';
|
|
$path = 'cats/' . $filename;
|
|
$img = Image::read($file)->cover(500, 500, 'center')->toPng();
|
|
Storage::disk('public')->put($path, (string) $img);
|
|
return $path;
|
|
}
|
|
} |