acct_type, UserActions::ViewBlotters); } private function checkWrite(): bool { return UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ProcessBlotter); } public function index(Request $request) { if (!$this->checkRead()) return ResponseHelper::returnUnauthorized(); $query = Blotter::with(['assignedOfficer'])->orderByDesc('id'); if ($status = $request->input('status')) $query->where('status', $status); if ($type = $request->input('incident_type')) $query->where('incident_type', $type); if ($search = $request->input('search')) { $query->where(function ($q) use ($search) { $q->where('complainant_name', 'like', "%{$search}%") ->orWhere('respondent_name', 'like', "%{$search}%") ->orWhere('blotter_no', 'like', "%{$search}%"); }); } $blotters = $query->paginate((int) $request->input('per_page', 20)); return response()->json(['success' => true, 'data' => $blotters]); } public function show(Request $request) { if (!$this->checkRead()) return ResponseHelper::returnUnauthorized(); $blotter = Blotter::with(['assignedOfficer', 'hearings.officer']) ->where('hashkey', $request->input('target')) ->first(); if (!$blotter) return ResponseHelper::returnError('Blotter not found', 404); return response()->json(['success' => true, 'data' => $blotter]); } public function store(Request $request) { if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized(); $validator = Validator::make($request->all(), [ 'complainant_name' => 'required|string|max:255', 'complainant_contact' => 'nullable|string|max:30', 'complainant_address' => 'nullable|string|max:500', 'respondent_name' => 'required|string|max:255', 'respondent_contact' => 'nullable|string|max:30', 'respondent_address' => 'nullable|string|max:500', 'incident_type' => 'required|in:AMICABLE,UNLAWFUL,MINOR,OTHER', 'incident_date' => 'required|date', 'incident_location' => 'nullable|string|max:500', 'narrative' => 'required|string', 'complainant_user_id' => 'nullable|integer|exists:users,id', 'respondent_user_id' => 'nullable|integer|exists:users,id', ]); if ($validator->fails()) { return response()->json(['success' => false, 'errors' => $validator->errors()], 422); } $data = $validator->validated(); $data['hashkey'] = hash('sha256', uniqid((string) now(), true)); $data['blotter_no'] = Blotter::generateBlotterNo(); $data['status'] = BlotterStatus::FILED; $data['complaint_date'] = now()->toDateString(); $data['filed_by'] = Auth::id(); $data['is_active'] = true; $data['created_by'] = Auth::id(); $data['updated_by'] = Auth::id(); $blotter = Blotter::create($data); return response()->json(['success' => true, 'data' => $blotter, 'message' => 'Blotter filed successfully']); } public function updateStatus(Request $request) { if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized(); $blotter = Blotter::where('hashkey', $request->input('target'))->first(); if (!$blotter) return ResponseHelper::returnError('Blotter not found', 404); $newStatus = BlotterStatus::tryFrom($request->input('status')); if (!$newStatus) return ResponseHelper::returnError('Invalid status', 422); $data = ['status' => $newStatus, 'updated_by' => Auth::id()]; if ($request->input('resolution')) $data['resolution'] = $request->input('resolution'); if ($request->input('endorsed_to')) $data['endorsed_to'] = $request->input('endorsed_to'); if ($request->input('settlement_type')) $data['settlement_type'] = $request->input('settlement_type'); $blotter->update($data); return response()->json(['success' => true, 'data' => $blotter, 'message' => 'Status updated']); } public function assignOfficer(Request $request) { if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized(); $blotter = Blotter::where('hashkey', $request->input('target'))->first(); if (!$blotter) return ResponseHelper::returnError('Blotter not found', 404); $blotter->update([ 'assigned_officer_id' => $request->input('officer_id'), 'updated_by' => Auth::id(), ]); return response()->json(['success' => true, 'data' => $blotter, 'message' => 'Officer assigned']); } public function statusOptions() { $options = collect(BlotterStatus::cases())->map(fn ($s) => ['value' => $s->value, 'label' => $s->label()]); return response()->json(['success' => true, 'data' => $options]); } }