get(); $data['totalCabinets'] = BioCabinet::count(); $data['totalRacks'] = BioRack::count(); $data['totalSpecimens'] = BioSpecimen::count(); $data['specimenRows'] = BioSpecimen::with(['cabinet', 'rack']) ->orderBy('stored_at', 'DESC') ->orderBy('id', 'DESC') ->get(); $data['cabinets'] = BioCabinet::with([ 'racks' => function ($query) { $query->orderBy('level', 'ASC')->orderBy('rack_number', 'ASC'); }, 'racks.specimens' => function ($query) { $query->orderBy('stored_at', 'ASC'); }, ])->orderBy('name', 'ASC')->get(); $data['oldestSpecimen'] = BioSpecimen::with(['cabinet', 'rack']) ->whereNotNull('stored_at') ->orderBy('stored_at', 'ASC') ->first(); $data['oldestStorageDays'] = 0; if ($data['oldestSpecimen']) { $data['oldestStorageDays'] = Carbon::parse($data['oldestSpecimen']->stored_at)->diffInDays(Carbon::now()); } return view('admin.biorepository', $data); } public function storeCabinet(Request $request) { $validator = Validator::make($request->all(), [ 'code' => 'required|max:50|unique:bio_cabinets,code', 'name' => 'required|max:150', 'location' => 'nullable|max:200', 'notes' => 'nullable', ]); if ($validator->fails()) { return back()->withErrors($validator)->withInput(); } BioCabinet::create([ 'code' => $request->input('code'), 'name' => $request->input('name'), 'location' => $request->input('location'), 'notes' => $request->input('notes'), ]); return redirect('/biorepository')->with('success', 'Lemari biorepository berhasil ditambahkan.'); } public function storeRack(Request $request) { $validator = Validator::make($request->all(), [ 'cabinet_id' => 'required|exists:bio_cabinets,id', 'code' => 'required|max:50', 'name' => 'required|max:150', 'level' => 'required|integer|min:1', 'rack_number' => 'required|integer|min:1', 'box_number' => 'required|integer|min:1', 'capacity' => 'required|integer|min:1', 'notes' => 'nullable', ]); if ($validator->fails()) { return back()->withErrors($validator)->withInput(); } $exists = BioRack::where('cabinet_id', $request->input('cabinet_id')) ->where('code', $request->input('code')) ->exists(); if ($exists) { return back()->withErrors(['code' => 'Kode rack sudah dipakai pada lemari ini.'])->withInput(); } BioRack::create([ 'cabinet_id' => $request->input('cabinet_id'), 'code' => $request->input('code'), 'name' => $request->input('name'), 'level' => $request->input('level'), 'rack_number' => $request->input('rack_number'), 'box_number' => $request->input('box_number'), 'capacity' => $request->input('capacity'), 'notes' => $request->input('notes'), ]); return redirect('/biorepository')->with('success', 'Rack berhasil ditambahkan.'); } public function storeSpecimen(Request $request) { $validator = Validator::make($request->all(), [ 'rack_id' => 'required|exists:bio_racks,id', 'kategorisimpan' => 'required|in:A,B,C,D', 'shelfnomor' => 'required|integer|min:1', 'raknomor' => 'required|integer|min:1', 'slotnomor' => 'required|integer|min:1', 'boxnomor' => 'required|integer|min:1', 'tubenomor' => 'required|integer|min:1', 'nmbakteri' => 'required|max:200', 'strain' => 'required|in:Gram Negatif,Gram Positif', 'stored_at' => 'required|date', ]); if ($validator->fails()) { return back()->withErrors($validator)->withInput(); } $rack = BioRack::find($request->input('rack_id')); $expectedRackNo = $rack->rack_number ?: $rack->id; $expectedBoxNo = $rack->box_number ?: 1; if ((int) $request->input('shelfnomor') !== (int) $rack->level || (int) $request->input('raknomor') !== (int) $expectedRackNo || (int) $request->input('boxnomor') !== (int) $expectedBoxNo) { return back()->withErrors(['slotnomor' => 'Posisi slot tidak sesuai dengan konfigurasi rack.'])->withInput(); } if ((int) $request->input('slotnomor') > (int) $rack->capacity) { return back()->withErrors(['slotnomor' => 'Slot melebihi kapasitas rack.'])->withInput(); } $slotTaken = BioSpecimen::where('rack_id', $rack->id) ->where('slot_number', $request->input('slotnomor')) ->exists(); if ($slotTaken) { return back()->withErrors(['slotnomor' => 'Slot ini sudah terisi spesimen.'])->withInput(); } $atccByUser = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', Session::get('nama', 'UNKNOWN'))); if ($atccByUser === '') { $atccByUser = 'UNKNOWN'; } $generatedCode = implode('-', [ $request->input('kategorisimpan'), $request->input('shelfnomor'), $request->input('raknomor'), $request->input('slotnomor'), $request->input('boxnomor'), $request->input('tubenomor'), ]); $baseCode = $generatedCode; $counter = 1; while (BioSpecimen::where('specimen_code', $generatedCode)->exists()) { $counter++; $generatedCode = $baseCode.'-'.$counter; } BioSpecimen::create([ 'cabinet_id' => $rack->cabinet_id, 'rack_id' => $rack->id, 'specimen_code' => $generatedCode, 'specimen_name' => $request->input('nmbakteri'), 'category_storage' => $request->input('kategorisimpan'), 'shelf_number' => $request->input('shelfnomor'), 'rack_number' => $request->input('raknomor'), 'slot_number' => $request->input('slotnomor'), 'box_number' => $request->input('boxnomor'), 'tube_number' => $request->input('tubenomor'), 'bacteria_name' => $request->input('nmbakteri'), 'strain' => $request->input('strain'), 'atcc' => $atccByUser, 'input_by' => Session::get('nama'), 'stored_at' => $request->input('stored_at'), 'storage_condition' => $this->mapStorageCondition($request->input('kategorisimpan')), 'notes' => $request->input('notes'), ]); return redirect('/biorepository')->with('success', 'Spesimen berhasil disimpan ke slot terpilih.'); } private function mapStorageCondition($category) { $mapping = [ 'A' => 'Suhu Ruang', 'B' => '4 Derajat', 'C' => '20 Derajat', 'D' => '80 Derajat', ]; return $mapping[$category] ?? 'Tidak Diketahui'; } }