300 lines
11 KiB
PHP
300 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\BioCabinet;
|
|
use App\BioRack;
|
|
use App\BioSpecimen;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Request;
|
|
use Session;
|
|
use Validator;
|
|
|
|
class BiorepositoryController extends Controller
|
|
{
|
|
public function index()
|
|
{
|
|
if (Session::get('previlage') == '') {
|
|
return redirect('/login');
|
|
}
|
|
|
|
$data = [];
|
|
$data['cabinetOptions'] = BioCabinet::orderBy('name', 'ASC')->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('rack_number', 'ASC')->orderBy('code', '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:4|max:6',
|
|
'capacity' => 'required|integer|min:16|max:20',
|
|
'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();
|
|
}
|
|
|
|
$nextRackNumber = ((int) BioRack::where('cabinet_id', $request->input('cabinet_id'))->max('rack_number')) + 1;
|
|
|
|
BioRack::create([
|
|
'cabinet_id' => $request->input('cabinet_id'),
|
|
'code' => $request->input('code'),
|
|
'name' => $request->input('name'),
|
|
'level' => $request->input('level'),
|
|
'rack_number' => $nextRackNumber,
|
|
'box_number' => 1,
|
|
'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' => 'nullable|max:200',
|
|
'strain' => 'nullable|in:Gram Negatif,Gram Positif',
|
|
'stored_at' => 'required|date',
|
|
'volume' => 'nullable|numeric|min:0',
|
|
'volume_ambil' => 'nullable|numeric|min:0',
|
|
'existing_specimen_id' => 'nullable|integer',
|
|
]);
|
|
|
|
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('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('shelfnomor') < 1 || (int) $request->input('shelfnomor') > (int) $rack->level) {
|
|
return back()->withErrors(['shelfnomor' => 'Shelf melebihi konfigurasi rack.'])->withInput();
|
|
}
|
|
|
|
if ((int) $request->input('tubenomor') < 1 || (int) $request->input('tubenomor') > (int) $rack->capacity) {
|
|
return back()->withErrors(['tubenomor' => 'Nomor tube melebihi kapasitas box pada shelf ini.'])->withInput();
|
|
}
|
|
|
|
$slotTaken = BioSpecimen::where('rack_id', $rack->id)
|
|
->where('shelf_number', $request->input('shelfnomor'))
|
|
->where('tube_number', $request->input('tubenomor'))
|
|
->first();
|
|
|
|
if ($slotTaken) {
|
|
$existingId = (int) $request->input('existing_specimen_id');
|
|
if ($existingId !== (int) $slotTaken->id) {
|
|
return back()->withErrors(['tubenomor' => 'Posisi tube pada shelf ini sudah terisi spesimen.'])->withInput();
|
|
}
|
|
|
|
$volumeAmbil = (float) $request->input('volume_ambil');
|
|
if ($volumeAmbil <= 0) {
|
|
return back()->withErrors(['volume_ambil' => 'Isi volume yang diambil dari spesimen.'])->withInput();
|
|
}
|
|
|
|
$volumeSekarang = (float) ($slotTaken->volume ?? 0);
|
|
if ($volumeAmbil > $volumeSekarang) {
|
|
return back()->withErrors(['volume_ambil' => 'Volume diambil melebihi sisa volume spesimen.'])->withInput();
|
|
}
|
|
|
|
$slotTaken->volume = (string) ($volumeSekarang - $volumeAmbil);
|
|
$slotTaken->save();
|
|
|
|
return redirect('/biorepository')->with('success', 'Pengambilan volume berhasil. Sisa volume diperbarui.');
|
|
}
|
|
|
|
if (!$request->filled('nmbakteri') || !$request->filled('strain')) {
|
|
return back()->withErrors(['nmbakteri' => 'Nama bakteri dan strain wajib diisi untuk spesimen baru.'])->withInput();
|
|
}
|
|
|
|
if (!$request->filled('volume')) {
|
|
return back()->withErrors(['volume' => 'Volume awal spesimen wajib diisi.'])->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('shelfnomor'),
|
|
'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')),
|
|
'volume' => (string) $request->input('volume'),
|
|
'notes' => $request->input('notes'),
|
|
]);
|
|
|
|
return redirect('/biorepository')->with('success', 'Spesimen berhasil disimpan ke slot terpilih.');
|
|
}
|
|
|
|
public function deleteSpecimen($id)
|
|
{
|
|
if (Session::get('previlage') == '') {
|
|
return redirect('/login');
|
|
}
|
|
|
|
$specimen = BioSpecimen::find($id);
|
|
if (!$specimen) {
|
|
return redirect('/biorepository')->withErrors(['specimen' => 'Data spesimen tidak ditemukan.']);
|
|
}
|
|
|
|
$specimen->delete();
|
|
|
|
return redirect('/biorepository')->with('success', 'Spesimen berhasil dihapus.');
|
|
}
|
|
|
|
public function deleteRack($id)
|
|
{
|
|
if (Session::get('previlage') == '') {
|
|
return redirect('/login');
|
|
}
|
|
|
|
$rack = BioRack::find($id);
|
|
if (!$rack) {
|
|
return redirect('/biorepository')->withErrors(['rack' => 'Data rack tidak ditemukan.']);
|
|
}
|
|
|
|
BioSpecimen::where('rack_id', $rack->id)->delete();
|
|
$rack->delete();
|
|
|
|
return redirect('/biorepository')->with('success', 'Rack dan semua spesimennya berhasil dihapus.');
|
|
}
|
|
|
|
public function deleteCabinet($id)
|
|
{
|
|
if (Session::get('previlage') == '') {
|
|
return redirect('/login');
|
|
}
|
|
|
|
$cabinet = BioCabinet::find($id);
|
|
if (!$cabinet) {
|
|
return redirect('/biorepository')->withErrors(['cabinet' => 'Data lemari tidak ditemukan.']);
|
|
}
|
|
|
|
$rackIds = BioRack::where('cabinet_id', $cabinet->id)->pluck('id')->toArray();
|
|
if (!empty($rackIds)) {
|
|
BioSpecimen::whereIn('rack_id', $rackIds)->delete();
|
|
BioRack::whereIn('id', $rackIds)->delete();
|
|
}
|
|
$cabinet->delete();
|
|
|
|
return redirect('/biorepository')->with('success', 'Lemari beserta rack dan spesimennya berhasil dihapus.');
|
|
}
|
|
|
|
private function mapStorageCondition($category)
|
|
{
|
|
$mapping = [
|
|
'A' => 'Suhu Ruang',
|
|
'B' => '4 Derajat',
|
|
'C' => '20 Derajat',
|
|
'D' => '80 Derajat',
|
|
];
|
|
|
|
return $mapping[$category] ?? 'Tidak Diketahui';
|
|
}
|
|
}
|