isKaryawan()) { $query->where('user_id', $user->id); } /* SEARCH */ if ($request->search) { $s = $request->search; $query->where(function ($q) use ($s) { $q->where('nama_barang', 'like', "%$s%") ->orWhere('jenis_transaksi', 'like', "%$s%") ->orWhereRaw("CAST(jumlah AS CHAR) LIKE ?", ["%$s%"]); }); } /* FILTER */ if ($request->jenis) { $query->where('jenis_transaksi', $request->jenis); } if ($request->bulan) { $query->whereMonth('tanggal', $request->bulan); } if ($request->tahun) { $query->whereYear('tanggal', $request->tahun); } $perPage = $request->perPage ?? 10; // DATA TABEL $data = $query ->orderBy('tanggal', 'desc') ->orderBy('id', 'desc') ->paginate($perPage) ->withQueryString(); // HITUNG STOK (GLOBAL) $stok = InventoriKandang::selectRaw(" nama_barang, SUM(CASE WHEN jenis_transaksi = 'masuk' THEN jumlah ELSE 0 END) - SUM(CASE WHEN jenis_transaksi = 'keluar' THEN jumlah ELSE 0 END) AS stok ") ->groupBy('nama_barang') ->get(); // BATAS MINIMUM $batasMinimum = [ 'Jagung' => 5, 'Katul' => 5, 'Konsentrat' => 5, 'Pakan Layer' => 5, 'Pakan Starter' => 5, ]; $stokMenipis = $stok->filter(function ($item) use ($batasMinimum) { $min = $batasMinimum[$item->nama_barang] ?? 5; return $item->stok <= $min; }); return view('inventori-pakan', compact('data', 'stokMenipis')); } public function store(Request $request) { /** @var User $user */ $user = Auth::user(); $request->merge([ 'harga_satuan' => $request->harga_satuan ? str_replace('.', '', $request->harga_satuan) : null ]); // karyawan TIDAK BOLEH input barang masuk if ($user->isKaryawan() && $request->jenis_transaksi === 'masuk') { abort(403, 'Karyawan tidak diizinkan mencatat barang masuk.'); } $namaBarang = ucfirst(strtolower(trim($request->nama_barang))); $request->validate([ 'tanggal' => 'required|date|before_or_equal:today', 'nama_barang' => 'required|string|max:100', 'jenis_transaksi' => 'required|in:masuk,keluar', 'jumlah' => 'required|numeric|min:1|max:999999', // 'satuan' => 'required|string|max:50|in:karung', 'harga_satuan' => $request->jenis_transaksi === 'masuk' ? 'required|numeric|min:1|max:999999999' : 'nullable', ], [ 'tanggal.required' => 'Tanggal wajib diisi.', 'tanggal.date' => 'Format tanggal tidak valid.', 'nama_barang.required' => 'Nama barang wajib diisi.', 'nama_barang.string' => 'Nama barang harus berupa teks.', 'nama_barang.max' => 'Nama barang maksimal 100 karakter.', 'jenis_transaksi.required' => 'Jenis transaksi wajib dipilih.', 'jenis_transaksi.in' => 'Jenis transaksi tidak valid.', 'jumlah.required' => 'Jumlah wajib diisi.', 'jumlah.numeric' => 'Jumlah harus berupa angka.', 'jumlah.min' => 'Jumlah minimal 1.', 'jumlah.max' => 'Jumlah terlalu besar.', // 'satuan.required' => 'Satuan wajib diisi.', // 'satuan.string' => 'Satuan harus berupa teks.', // 'satuan.max' => 'Satuan maksimal 50 karakter.', 'harga_satuan.required' => 'Harga satuan wajib diisi untuk transaksi masuk.', 'harga_satuan.numeric' => 'Harga satuan harus berupa angka.', 'harga_satuan.min' => 'Harga satuan minimal 1.', 'harga_satuan.max' => 'Harga satuan terlalu besar.', ]); $total = null; if ($request->jenis_transaksi === 'masuk') { $total = $request->jumlah * $request->harga_satuan; } // CEK STOK JIKA BARANG KELUAR if ($request->jenis_transaksi === 'keluar') { $stokSekarang = InventoriKandang::where('nama_barang', $namaBarang) ->selectRaw(" SUM(CASE WHEN jenis_transaksi = 'masuk' THEN jumlah ELSE 0 END) - SUM(CASE WHEN jenis_transaksi = 'keluar' THEN jumlah ELSE 0 END) AS stok ") ->value('stok') ?? 0; if ($request->jumlah > $stokSekarang) { return back()->withErrors([ 'jumlah' => 'Stok ' . $namaBarang . ' tidak mencukupi. Sisa stok: ' . $stokSekarang ])->withInput(); } } InventoriKandang::create([ 'user_id' => $user->id, 'tanggal' => $request->tanggal, 'nama_barang' => $namaBarang, 'jenis_transaksi' => $request->jenis_transaksi, 'jumlah' => $request->jumlah, 'satuan' => 'karung', 'harga_satuan' => $request->jenis_transaksi === 'masuk' ? $request->harga_satuan : null, 'total_harga' => $total, ]); return redirect()->route('pakan')->with('success', 'Transaksi berhasil disimpan'); } public function update(Request $request, $id) { /** @var User $user */ $user = Auth::user(); $request->merge([ 'harga_satuan' => $request->harga_satuan ? str_replace('.', '', $request->harga_satuan) : null ]); if ($user->isKaryawan()) { abort(403, 'Anda tidak memiliki izin mengedit data.'); } $namaBarang = ucfirst(strtolower(trim($request->nama_barang))); $request->validate([ 'tanggal' => 'required|date|before_or_equal:today', 'nama_barang' => 'required|string|max:100', 'jenis_transaksi' => 'required|in:masuk,keluar', 'jumlah' => 'required|numeric|min:1|max:999999', // 'satuan' => 'required|string|max:50|in:karung', 'harga_satuan' => $request->jenis_transaksi === 'masuk' ? 'required|numeric|min:1|max:999999999' : 'nullable', ], [ 'tanggal.required' => 'Tanggal wajib diisi.', 'tanggal.date' => 'Format tanggal tidak valid.', 'nama_barang.required' => 'Nama barang wajib diisi.', 'nama_barang.string' => 'Nama barang harus berupa teks.', 'nama_barang.max' => 'Nama barang maksimal 100 karakter.', 'jenis_transaksi.required' => 'Jenis transaksi wajib dipilih.', 'jenis_transaksi.in' => 'Jenis transaksi tidak valid.', 'jumlah.required' => 'Jumlah wajib diisi.', 'jumlah.numeric' => 'Jumlah harus berupa angka.', 'jumlah.min' => 'Jumlah minimal 1.', 'jumlah.max' => 'Jumlah terlalu besar.', // 'satuan.required' => 'Satuan wajib diisi.', // 'satuan.string' => 'Satuan harus berupa teks.', // 'satuan.max' => 'Satuan maksimal 50 karakter.', 'harga_satuan.required' => 'Harga satuan wajib diisi untuk transaksi masuk.', 'harga_satuan.numeric' => 'Harga satuan harus berupa angka.', 'harga_satuan.min' => 'Harga satuan minimal 1.', 'harga_satuan.max' => 'Harga satuan terlalu besar.', ]); try { DB::transaction(function () use ($request, $id, $namaBarang) { $item = InventoriKandang::findOrFail($id); $total = null; if ($request->jenis_transaksi === 'masuk') { $total = $request->jumlah * $request->harga_satuan; } // CEK STOK JIKA KELUAR if ($request->jenis_transaksi === 'keluar') { $stokSekarang = InventoriKandang::where('nama_barang', $namaBarang) ->where('id', '!=', $id) ->selectRaw(" SUM(CASE WHEN jenis_transaksi = 'masuk' THEN jumlah ELSE 0 END) - SUM(CASE WHEN jenis_transaksi = 'keluar' THEN jumlah ELSE 0 END) AS stok ") ->value('stok') ?? 0; if ($request->jumlah > $stokSekarang) { throw new \Exception('Stok tidak mencukupi. Sisa stok: ' . $stokSekarang); } } $item->update([ 'tanggal' => $request->tanggal, 'nama_barang' => $namaBarang, 'jenis_transaksi' => $request->jenis_transaksi, 'jumlah' => $request->jumlah, 'satuan' => 'karung', 'harga_satuan' => $request->jenis_transaksi === 'masuk' ? $request->harga_satuan : null, 'total_harga' => $total, ]); }); } catch (\Exception $e) { return back() ->withErrors([ 'jumlah' => $e->getMessage() ]) ->withInput(); } return redirect()->route('pakan')->with('success', 'Transaksi berhasil diupdate'); } public function destroy($id) { /** @var \App\Models\User $user */ $user = Auth::user(); // hanya admin boleh hapus if ($user->isKaryawan()) { abort(403, 'Anda tidak memiliki izin menghapus data.'); } $item = InventoriKandang::findOrFail($id); // Cek jika yang dihapus adalah transaksi masuk if ($item->jenis_transaksi === 'masuk') { $stokSekarang = InventoriKandang::where('nama_barang', $item->nama_barang) ->selectRaw(" SUM(CASE WHEN jenis_transaksi = 'masuk' THEN jumlah ELSE 0 END) - SUM(CASE WHEN jenis_transaksi = 'keluar' THEN jumlah ELSE 0 END) AS stok ") ->value('stok') ?? 0; // jika setelah dihapus stok jadi minus if (($stokSekarang - $item->jumlah) < 0) { return redirect() ->route('pakan') ->withErrors([ 'delete' => 'Transaksi tidak bisa dihapus karena akan menyebabkan stok menjadi minus.' ]); } } $item->delete(); return redirect() ->route('pakan') ->with('success', 'Transaksi berhasil dihapus'); } }