load(['registrations.association', 'registrations.documents']); $associations = CatAssociation::where('is_active', true)->orderBy('code')->get(); return view('pages.cats.pedigree', compact('cat', 'associations')); } public function store(Request $request, Cat $cat) { Gate::authorize('check-access', ['cats', 'update']); $validated = $this->validateRegistration($request, $cat); return DB::transaction(function () use ($request, $validated, $cat) { $associationId = $this->resolveAssociation($request); if ($cat->registrations()->where('association_id', $associationId)->exists()) { return back()->withErrors(['association_id' => 'Asosiasi ini sudah terdaftar untuk kucing tersebut.']); } if ($request->boolean('is_primary')) { $cat->registrations()->update(['is_primary' => false]); } $registration = $cat->registrations()->create(array_merge($validated, [ 'association_id' => $associationId, 'is_primary' => $request->boolean('is_primary') || !$cat->registrations()->exists(), ])); $this->storeDocumentIfPresent($request, $registration); $this->logAction('CAT_REGISTRATION_CREATED', $cat, 'Menambahkan registrasi pedigree pada ' . $registration->association->code, 'Cat'); return back()->with('success', 'Registrasi pedigree berhasil ditambahkan.'); }); } public function update(Request $request, Cat $cat, CatRegistration $registration) { Gate::authorize('check-access', ['cats', 'update']); abort_unless($registration->cat_id === $cat->id, 404); $validated = $this->validateRegistration($request, $cat, $registration); if ($request->boolean('is_primary')) { $cat->registrations()->whereKeyNot($registration->id)->update(['is_primary' => false]); } $registration->update(array_merge($validated, ['is_primary' => $request->boolean('is_primary')])); return back()->with('success', 'Registrasi pedigree berhasil diperbarui.'); } public function destroy(Cat $cat, CatRegistration $registration) { Gate::authorize('check-access', ['cats', 'update']); abort_unless($registration->cat_id === $cat->id, 404); $wasPrimary = $registration->is_primary; $registration->delete(); if ($wasPrimary && ($next = $cat->registrations()->oldest()->first())) { $next->update(['is_primary' => true]); } return back()->with('success', 'Registrasi pedigree berhasil dihapus.'); } public function storeDocument(Request $request, Cat $cat, CatRegistration $registration) { Gate::authorize('check-access', ['cats', 'update']); abort_unless($registration->cat_id === $cat->id, 404); $request->validate([ 'document' => 'required|file|mimes:pdf,jpg,jpeg,png|max:10240', 'label' => 'nullable|string|max:120', 'document_type' => ['nullable', Rule::in(['pedigree','registration','ownership','title','other'])], 'issued_at' => 'nullable|date', ]); $this->storeDocumentIfPresent($request, $registration, 'document'); return back()->with('success', 'Dokumen berhasil ditambahkan.'); } public function showDocument(Cat $cat, CatRegistration $registration, CatRegistrationDocument $document) { Gate::authorize('check-access', ['cats', 'read']); abort_unless($registration->cat_id === $cat->id && $document->cat_registration_id === $registration->id, 404); abort_unless(Storage::disk('public')->exists($document->file_path), 404); return response()->file(Storage::disk('public')->path($document->file_path), [ 'Content-Disposition' => 'inline; filename="' . basename($document->file_path) . '"', ]); } public function downloadDocument(Cat $cat, CatRegistration $registration, CatRegistrationDocument $document) { Gate::authorize('check-access', ['cats', 'read']); abort_unless($registration->cat_id === $cat->id && $document->cat_registration_id === $registration->id, 404); abort_unless(Storage::disk('public')->exists($document->file_path), 404); $extension = pathinfo($document->file_path, PATHINFO_EXTENSION); $filename = str($document->label ?: 'pedigree')->slug('_') . ($extension ? '.' . $extension : ''); return Storage::disk('public')->download($document->file_path, $filename); } public function destroyDocument(Cat $cat, CatRegistration $registration, CatRegistrationDocument $document) { Gate::authorize('check-access', ['cats', 'update']); abort_unless($registration->cat_id === $cat->id && $document->cat_registration_id === $registration->id, 404); Storage::disk('public')->delete($document->file_path); $document->delete(); return back()->with('success', 'Dokumen berhasil dihapus.'); } private function validateRegistration(Request $request, Cat $cat, ?CatRegistration $registration = null): array { return $request->validate([ 'registration_number' => 'nullable|string|max:100', 'pedigree_number' => 'nullable|string|max:100', 'certificate_number' => 'nullable|string|max:100', 'issue_date' => 'nullable|date', 'title' => 'nullable|string|max:120', 'ownership_status' => ['nullable', Rule::in(['milik_sendiri','co_own','transfer','lainnya'])], 'notes' => 'nullable|string|max:1000', 'is_primary' => 'nullable|boolean', 'association_id' => $registration ? 'nullable' : 'required', 'association_code' => 'nullable|string|max:30', 'association_name' => 'nullable|string|max:120', 'certificate_file' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:10240', ]); } private function resolveAssociation(Request $request): int { if ($request->association_id !== 'custom') { return (int) CatAssociation::whereKey($request->association_id)->where('is_active', true)->firstOrFail()->id; } $request->validate(['association_code' => 'required|string|max:30', 'association_name' => 'required|string|max:120']); return CatAssociation::firstOrCreate( ['code' => strtoupper(trim($request->association_code))], ['name' => trim($request->association_name), 'is_active' => true] )->id; } private function storeDocumentIfPresent(Request $request, CatRegistration $registration, string $field = 'certificate_file'): void { if (!$request->hasFile($field)) return; $path = $request->file($field)->store('cat-registrations/' . $registration->cat_id, 'public'); $registration->documents()->create([ 'label' => $request->input('label') ?: 'Sertifikat Pedigree', 'document_type' => $request->input('document_type') ?: 'pedigree', 'file_path' => $path, 'issued_at' => $request->input('issued_at') ?: $request->input('issue_date'), ]); } }