revisi semhas

This commit is contained in:
ninavirgiana 2026-05-04 12:18:09 +07:00
parent dc36c6fa51
commit c297a81116
20 changed files with 736 additions and 129 deletions

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\MutasiAyam;
use App\Models\JenisMutasi;
use App\Models\Kandang;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -13,7 +14,8 @@ class AyamController extends Controller
{
public function index(Request $request)
{
$query = MutasiAyam::with('kandang');
$query = MutasiAyam::with(['kandang', 'jenisMutasi']);
$jenisMutasi = JenisMutasi::all();
/** @var \App\Models\User $user */
$user = Auth::user();
@ -45,32 +47,33 @@ public function index(Request $request)
->select('id', 'nama_kandang')
->selectSub(function ($q) {
$q->from('mutasi_ayam')
->join('jenis_mutasi', 'mutasi_ayam.jenis_mutasi_id', '=', 'jenis_mutasi.id')
->whereColumn('mutasi_ayam.kandang_id', 'kandang.id')
->selectRaw("
COALESCE(SUM(
CASE
WHEN jenis_mutasi = 'masuk' THEN jumlah
WHEN jenis_mutasi IN ('mati','afkir','pindah') THEN -jumlah
WHEN jenis_mutasi.tipe = 'tambah' THEN jumlah
WHEN jenis_mutasi.tipe = 'kurang' THEN -jumlah
WHEN jenis_mutasi.tipe = 'transfer' THEN -jumlah
ELSE 0
END
), 0)
),0)
");
}, 'jumlah_ayam_terakhir')
->get();
return view('inventori-ayam', compact('data', 'kandang'));
}
return view('inventori-ayam', compact('data', 'kandang', 'jenisMutasi'));
}
public function store(Request $request)
{
$request->validate([
'jenis_mutasi' => 'required|in:masuk,mati,afkir,pindah',
'jumlah' => 'required|integer|min:1|max:9999',
'jenis_mutasi_id' => 'required|exists:jenis_mutasi,id',
'jumlah' => 'required|integer|min:1|max:9999',
'tanggal' => 'required|date|before_or_equal:today',
'keterangan' => 'required_if:jenis_mutasi,masuk,mati,afkir|string|max:255',
], [
'jenis_mutasi.required' => 'Jenis mutasi wajib dipilih.',
'jenis_mutasi.in' => 'Jenis mutasi tidak valid.',
'keterangan' => 'nullable|string|max:255',
], [
'jenis_mutasi_id.required' => 'Jenis mutasi wajib dipilih.',
'jenis_mutasi_id.exists' => 'Jenis mutasi tidak valid.',
'jumlah.required' => 'Jumlah ayam wajib diisi.',
'jumlah.integer' => 'Jumlah ayam harus berupa angka.',
@ -87,10 +90,14 @@ public function store(Request $request)
DB::transaction(function () use ($request) {
// PINDAH
if ($request->jenis_mutasi === 'pindah') {
// ✅ ambil jenis mutasi dari tabel master
$jenisPindah = JenisMutasi::where('nama', 'pindah')->first();
$jenisMasuk = JenisMutasi::where('nama', 'masuk')->first();
$request->validate([
// PINDAH
$jenis = JenisMutasi::findOrFail($request->jenis_mutasi_id);
if ($jenis->nama === 'pindah'){ $request->validate([
'kandang_asal_id' => 'required|exists:kandang,id|different:kandang_tujuan_id',
'kandang_tujuan_id' => 'required|exists:kandang,id',
], [
@ -103,14 +110,17 @@ public function store(Request $request)
$kandangTujuan = Kandang::findOrFail($request->kandang_tujuan_id);
$stokAsal = $kandangAsal->mutasiAyam()
->join('jenis_mutasi', 'mutasi_ayam.jenis_mutasi_id', '=', 'jenis_mutasi.id')
->selectRaw("
COALESCE(SUM(
CASE
WHEN jenis_mutasi='masuk' THEN jumlah
WHEN jenis_mutasi IN ('mati','afkir','pindah') THEN -jumlah
ELSE 0 END
),0) as stok
")->value('stok');
COALESCE(SUM(
CASE
WHEN jenis_mutasi.tipe = 'tambah' THEN jumlah
WHEN jenis_mutasi.tipe IN ('kurang','transfer') THEN -jumlah
ELSE 0
END
),0) as stok
")
->value('stok');
if ($stokAsal <= 0) {
throw \Illuminate\Validation\ValidationException::withMessages([
@ -127,8 +137,8 @@ public function store(Request $request)
MutasiAyam::create([
'kandang_id' => $request->kandang_asal_id,
'user_id' => Auth::id(),
'jenis_mutasi' => 'pindah',
'jumlah' => $request->jumlah,
'jenis_mutasi_id' => $jenisPindah->id,
'jumlah' => $request->jumlah,
'tanggal' => $request->tanggal,
'keterangan' => 'Pindah ke ' . $kandangTujuan->nama_kandang,
]);
@ -136,8 +146,8 @@ public function store(Request $request)
MutasiAyam::create([
'kandang_id' => $request->kandang_tujuan_id,
'user_id' => Auth::id(),
'jenis_mutasi' => 'masuk',
'jumlah' => $request->jumlah,
'jenis_mutasi_id' => $jenisMasuk->id,
'jumlah' => $request->jumlah,
'tanggal' => $request->tanggal,
'keterangan' => 'Pindahan dari ' . $kandangAsal->nama_kandang,
]);
@ -152,22 +162,24 @@ public function store(Request $request)
'kandang_id.required' => 'Nama kandang wajib dipilih.',
'kandang_id.exists' => 'Kandang tidak ditemukan.',
]);
$kandang = Kandang::findOrFail($request->kandang_id);
$stok = $kandang->mutasiAyam()->selectRaw("
COALESCE(SUM(
CASE
WHEN jenis_mutasi='masuk' THEN jumlah
WHEN jenis_mutasi IN ('mati','afkir','pindah') THEN -jumlah
ELSE 0 END
),0) as stok
")->value('stok');
$stok = $kandang->mutasiAyam()
->join('jenis_mutasi', 'mutasi_ayam.jenis_mutasi_id', '=', 'jenis_mutasi.id')
->selectRaw("
COALESCE(SUM(
CASE
WHEN jenis_mutasi.tipe = 'tambah' THEN jumlah
WHEN jenis_mutasi.tipe IN ('kurang','transfer') THEN -jumlah
ELSE 0
END
),0) as stok
")
->value('stok'); // ← WAJIB
$jenis = JenisMutasi::findOrFail($request->jenis_mutasi_id);
// Kalau mutasi keluar/mati/afkir → cek stok
if (in_array($request->jenis_mutasi, ['mati', 'afkir'])) {
if ($stok <= 0) {
if (in_array($jenis->nama, ['mati', 'afkir'])) {
if ($stok <= 0) {
throw \Illuminate\Validation\ValidationException::withMessages([
'jumlah' => 'Stok ayam di kandang ini sudah habis.'
]);
@ -183,8 +195,8 @@ public function store(Request $request)
MutasiAyam::create([
'kandang_id' => $request->kandang_id,
'user_id' => Auth::id(),
'jenis_mutasi' => $request->jenis_mutasi,
'jumlah' => $request->jumlah,
'jenis_mutasi_id' => $request->jenis_mutasi_id,
'jumlah' => $request->jumlah,
'tanggal' => $request->tanggal,
'keterangan' => $request->keterangan,
]);
@ -200,8 +212,8 @@ public function update(Request $request, $id)
$mutasi = MutasiAyam::findOrFail($id);
// CEGAH EDIT DATA PINDAH
if (
$mutasi->jenis_mutasi === 'pindah' ||
str_contains($mutasi->keterangan, 'Pindahan dari')
$mutasi->jenisMutasi->nama === 'pindah' ||
str_contains($mutasi->keterangan, 'Pindahan dari')
) {
abort(403, 'Data hasil pindahan tidak boleh diedit.');
}
@ -214,16 +226,16 @@ public function update(Request $request, $id)
// VALIDASI MANUAL
$validator = Validator::make($request->all(), [
'kandang_id' => 'required|exists:kandang,id',
'jenis_mutasi' => 'required|in:masuk,mati,afkir',
'jumlah' => 'required|integer|min:1|max:9999',
'jenis_mutasi_id' => 'required|exists:jenis_mutasi,id',
'jumlah' => 'required|integer|min:1|max:9999',
'tanggal' => 'required|date|before_or_equal:today',
'keterangan' => 'required_if:jenis_mutasi,masuk,mati,afkir|string|max:255',
'keterangan' => 'nullable|string|max:255',
], [
'kandang_id.required' => 'Nama kandang wajib dipilih.',
'kandang_id.exists' => 'Kandang tidak ditemukan.',
'jenis_mutasi.required' => 'Jenis mutasi wajib dipilih.',
'jenis_mutasi.in' => 'Jenis mutasi tidak valid.',
'jenis_mutasi_id.required' => 'Jenis mutasi wajib dipilih.',
'jenis_mutasi_id.exists' => 'Jenis mutasi tidak valid.',
'jumlah.required' => 'Jumlah ayam wajib diisi.',
'jumlah.integer' => 'Jumlah ayam harus berupa angka.',
'jumlah.min' => 'Jumlah ayam minimal 1 ekor.',
@ -241,29 +253,30 @@ public function update(Request $request, $id)
->withInput()
->with('edit_id', $mutasi->id);
}
$jenis = JenisMutasi::findOrFail($request->jenis_mutasi_id);
// HITUNG STOK
$kandang = Kandang::findOrFail($request->kandang_id);
$stok = $kandang->mutasiAyam()
->where('id', '!=', $mutasi->id)
->join('jenis_mutasi', 'mutasi_ayam.jenis_mutasi_id', '=', 'jenis_mutasi.id')
->selectRaw("
COALESCE(SUM(
CASE
WHEN jenis_mutasi='masuk' THEN jumlah
WHEN jenis_mutasi IN ('mati','afkir','pindah') THEN -jumlah
ELSE 0 END
),0) as stok
")->value('stok');
COALESCE(SUM(
CASE
WHEN jenis_mutasi.tipe = 'tambah' THEN jumlah
WHEN jenis_mutasi.tipe IN ('kurang','transfer') THEN -jumlah
ELSE 0
END
),0) as stok
")
->value('stok'); // ✅ WAJIB
// kembalikan stok lama jika mutasi lama adalah pengurang
if (in_array($mutasi->jenis_mutasi, ['mati', 'afkir', 'pindah'])) {
if (in_array($mutasi->jenisMutasi->nama, ['mati', 'afkir', 'pindah'])) {
$stok += $mutasi->jumlah;
}
// CEK STOK
if (in_array($request->jenis_mutasi, ['mati', 'afkir'])) {
if ($stok <= 0) {
if (in_array($jenis->nama, ['mati', 'afkir'])) {
if ($stok <= 0) {
throw \Illuminate\Validation\ValidationException::withMessages([
'jumlah' => 'Stok ayam di kandang ini sudah habis.'
]);
@ -279,8 +292,8 @@ public function update(Request $request, $id)
// UPDATE DATA
$mutasi->update([
'kandang_id' => $request->kandang_id,
'jenis_mutasi' => $request->jenis_mutasi,
'jumlah' => $request->jumlah,
'jenis_mutasi_id' => $request->jenis_mutasi_id,
'jumlah' => $request->jumlah,
'tanggal' => $request->tanggal,
'keterangan' => $request->keterangan,
]);
@ -300,8 +313,8 @@ public function destroy($id)
$mutasi = MutasiAyam::findOrFail($id);
if (
$mutasi->jenis_mutasi === 'pindah' ||
str_contains($mutasi->keterangan, 'Pindahan dari')
$mutasi->jenisMutasi->nama === 'pindah'||
str_contains($mutasi->keterangan, 'Pindahan dari')
) {
abort(403, 'Data hasil pindahan tidak boleh dihapus.');
}

View File

@ -23,9 +23,17 @@ public function index()
/* STAT UMUM */
$jumlahMasuk = MutasiAyam::where('jenis_mutasi', 'masuk')->sum('jumlah');
$jumlahKeluar = MutasiAyam::whereIn('jenis_mutasi', ['keluar', 'mati', 'afkir', 'pindah'])->sum('jumlah');
$jumlahAyam = $jumlahMasuk - $jumlahKeluar;
$jumlahAyam = MutasiAyam::join('jenis_mutasi', 'mutasi_ayam.jenis_mutasi_id', '=', 'jenis_mutasi.id')
->selectRaw("
COALESCE(SUM(
CASE
WHEN jenis_mutasi.tipe = 'tambah' THEN jumlah
WHEN jenis_mutasi.tipe IN ('kurang','transfer') THEN -jumlah
ELSE 0
END
),0) as total
")
->value('total');
$produksiHariIni = ProduksiTelur::whereDate('tanggal_produksi', $today)
->sum(DB::raw('berat_telur_layak + berat_telur_rusak'));

View File

@ -0,0 +1,58 @@
<?php
namespace App\Http\Controllers;
use App\Models\JenisMutasi;
use Illuminate\Http\Request;
class JenisMutasiController extends Controller
{
public function index()
{
$data = JenisMutasi::orderBy('id', 'desc')->get();
return view('jenis-mutasi', compact('data'));
}
public function store(Request $request)
{
$request->validate([
'nama' => 'required|string|max:255',
'tipe' => 'required|in:tambah,kurang,transfer',
]);
JenisMutasi::create([
'nama' => $request->nama,
'tipe' => $request->tipe,
]);
return redirect()->route('jenis-mutasi')
->with('success', 'Jenis mutasi berhasil ditambahkan.');
}
public function update(Request $request, $id)
{
$data = JenisMutasi::findOrFail($id);
$request->validate([
'nama' => 'required|string|max:255',
'tipe' => 'required|in:tambah,kurang,transfer',
]);
$data->update([
'nama' => $request->nama,
'tipe' => $request->tipe,
]);
return redirect()->route('jenis-mutasi')
->with('success', 'Jenis mutasi berhasil diperbarui.');
}
public function destroy($id)
{
$data = JenisMutasi::findOrFail($id);
$data->delete();
return redirect()->route('jenis-mutasi')
->with('success', 'Jenis mutasi berhasil dihapus.');
}
}

View File

@ -28,7 +28,7 @@ public function index(Request $request)
}
$perPage = in_array($request->perPage, [10, 25, 50]) ? $request->perPage : 10;
$data = $query
->orderBy('created_at', 'desc')
->paginate($perPage)
@ -41,8 +41,8 @@ public function store(Request $request)
{
$request->validate(
[
'nama_karyawan' => 'required|string|min:3|max:100',
'no_hp' => ['required', 'regex:/^08[0-9]{8,11}$/'],
'nama_karyawan' => ['required', 'string', 'min:3', 'max:100', 'regex:/^[A-Za-z\s]+$/'],
'no_hp' => ['required', 'regex:/^08[0-9]{8,11}$/'],
'alamat' => 'required|string|max:255',
'status_karyawan' => 'required|in:aktif,nonaktif',
],
@ -51,6 +51,7 @@ public function store(Request $request)
'nama_karyawan.string' => 'Nama karyawan harus berupa teks',
'nama_karyawan.min' => 'Nama karyawan minimal 3 karakter',
'nama_karyawan.max' => 'Nama karyawan maksimal 100 karakter',
'nama_karyawan.regex' => 'Nama hanya boleh berisi huruf dan spasi',
'no_hp.required' => 'Nomor HP wajib diisi',
'no_hp.regex' => 'Nomor HP harus 1013 digit, diawali 08, dan hanya angka.',
@ -112,8 +113,8 @@ public function update(Request $request, $id)
{
$request->validate(
[
'nama_karyawan' => 'required|string|min:3|max:100',
'no_hp' => ['required', 'regex:/^08[0-9]{8,11}$/'],
'nama_karyawan' => ['required', 'string', 'min:3', 'max:100', 'regex:/^[A-Za-z\s]+$/'],
'no_hp' => ['required', 'regex:/^08[0-9]{8,11}$/'],
'alamat' => 'required|string|max:255',
],
[
@ -121,6 +122,7 @@ public function update(Request $request, $id)
'nama_karyawan.string' => 'Nama karyawan harus berupa teks',
'nama_karyawan.min' => 'Nama karyawan minimal 3 karakter',
'nama_karyawan.max' => 'Nama karyawan maksimal 100 karakter',
'nama_karyawan.regex' => 'Nama hanya boleh berisi huruf dan spasi',
'no_hp.required' => 'Nomor HP wajib diisi',
'no_hp.regex' => 'Nomor HP harus 1013 digit, diawali 08, dan hanya angka.',

View File

@ -79,8 +79,13 @@ public function index(Request $request)
$min = $batasMinimum[$item->nama_barang] ?? 5;
return $item->stok <= $min;
});
$stokAman = $stok->filter(function ($item) use ($batasMinimum) {
$min = $batasMinimum[$item->nama_barang] ?? 5;
return $item->stok > $min;
});
return view('inventori-pakan', compact('data', 'stokMenipis'));
// return view('inventori-pakan', compact('data', 'stokMenipis'));
return view('inventori-pakan', compact('data', 'stokMenipis', 'stokAman'));
}
public function store(Request $request)

View File

@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class JenisMutasi extends Model
{
protected $table = 'jenis_mutasi';
protected $fillable = [
'nama',
'tipe',
];
public function mutasiAyam()
{
return $this->hasMany(MutasiAyam::class, 'jenis_mutasi_id');
}
}

View File

@ -14,7 +14,7 @@ class MutasiAyam extends Model
protected $fillable = [
'kandang_id',
'user_id',
'jenis_mutasi',
'jenis_mutasi_id', // ✅ ganti ini
'jumlah',
'tanggal',
'keterangan',
@ -33,4 +33,10 @@ public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
// ✅ RELASI BARU
public function jenisMutasi()
{
return $this->belongsTo(JenisMutasi::class, 'jenis_mutasi_id');
}
}

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('jenis_mutasi', function (Blueprint $table) {
$table->id();
$table->string('nama')->unique();
$table->enum('tipe', ['tambah', 'kurang', 'transfer']);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('jenis_mutasi');
}
};

View File

@ -0,0 +1,64 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// 1. Tambah kolom baru
Schema::table('mutasi_ayam', function (Blueprint $table) {
$table->unsignedBigInteger('jenis_mutasi_id')->nullable()->after('user_id');
});
// 2. Mapping data lama (enum → id)
$data = DB::table('mutasi_ayam')->get();
foreach ($data as $item) {
$jenis = DB::table('jenis_mutasi')
->where('nama', $item->jenis_mutasi)
->first();
if ($jenis) {
DB::table('mutasi_ayam')
->where('id', $item->id)
->update([
'jenis_mutasi_id' => $jenis->id
]);
}
}
// 3. Tambahkan foreign key
Schema::table('mutasi_ayam', function (Blueprint $table) {
$table->foreign('jenis_mutasi_id')
->references('id')
->on('jenis_mutasi')
->cascadeOnDelete();
});
// 4. (JANGAN DIHAPUS DULU)
// Nanti kalau semua sudah aman baru aktifkan ini
/*
Schema::table('mutasi_ayam', function (Blueprint $table) {
$table->dropColumn('jenis_mutasi');
});
*/
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('mutasi_ayam', function (Blueprint $table) {
$table->dropForeign(['jenis_mutasi_id']);
$table->dropColumn('jenis_mutasi_id');
});
}
};

View File

@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
Schema::table('mutasi_ayam', function (Blueprint $table) {
if (Schema::hasColumn('mutasi_ayam', 'jenis_mutasi')) {
$table->dropColumn('jenis_mutasi');
}
});
}
public function down(): void
{
Schema::table('mutasi_ayam', function (Blueprint $table) {
if (!Schema::hasColumn('mutasi_ayam', 'jenis_mutasi')) {
$table->enum('jenis_mutasi', ['masuk', 'keluar', 'mati', 'afkir', 'pindah'])
->after('jenis_mutasi_id')
->nullable();
}
});
}
};

View File

@ -11,6 +11,7 @@ public function run(): void
$this->call([
UserSeeder::class,
KandangSeeder::class,
JenisMutasiSeeder::class,
KaryawanSeeder::class,
GajiKaryawanSeeder::class,
InventoriKandangSeeder::class,

View File

@ -0,0 +1,39 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class JenisMutasiSeeder extends Seeder
{
public function run(): void
{
DB::table('jenis_mutasi')->insert([
[
'nama' => 'masuk',
'tipe' => 'tambah',
'created_at' => now(),
'updated_at' => now(),
],
[
'nama' => 'mati',
'tipe' => 'kurang',
'created_at' => now(),
'updated_at' => now(),
],
[
'nama' => 'afkir',
'tipe' => 'kurang',
'created_at' => now(),
'updated_at' => now(),
],
[
'nama' => 'pindah',
'tipe' => 'transfer',
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}

View File

@ -12,7 +12,7 @@ public function run(): void
MutasiAyam::create([
'kandang_id' => 1,
'user_id' => 1,
'jenis_mutasi' => 'masuk',
'jenis_mutasi_id' => 1,
'jumlah' => 7000,
'tanggal' => now(),
'keterangan' => 'DOC baru'

View File

@ -505,4 +505,21 @@ @media (max-width: 768px) {
letter-spacing: .5px;
background: #f8f9fb;
}
.info-card {
background: #fff;
border: 1px solid #e5e7eb;
border-left: 4px solid #ccc;
border-radius: 10px;
padding: 12px 14px;
height: 100%;
}
.info-card.warning {
border-left-color: #f59e0b;
/* soft orange */
}
.info-card.success {
border-left-color: #10b981;
/* soft green */
}

View File

@ -141,7 +141,7 @@ class="form-control form-control-sm">
<td>{{ number_format($item->jumlah, 0, ',', '.') }}</td>
<td>
{{ ucfirst($item->jenis_mutasi ?? '-') }}
{{ $item->jenisMutasi->nama ?? '-' }}
</td>
<td>{{ $item->keterangan ?? '-' }}</td>
@ -154,8 +154,8 @@ class="form-control form-control-sm">
@php
$isPindahan =
$item->jenis_mutasi === 'pindah' ||
str_contains($item->keterangan, 'Pindahan dari');
optional($item->jenisMutasi)->nama === 'pindah' ||
str_contains($item->keterangan ?? '', 'Pindahan dari');
@endphp
{{-- TOMBOL EDIT --}}
@ -165,7 +165,7 @@ class="btn btn-warning btn-sm {{ $isPindahan ? 'disabled opacity-50' : '' }}"
data-target="#modalEdit" @endif
data-id="{{ $item->id }}" data-kandang="{{ $item->kandang_id }}"
data-jumlah="{{ $item->jumlah }}"
data-jenis="{{ $item->jenis_mutasi }}"
data-jenis="{{ $item->jenis_mutasi_id }}"
data-keterangan="{{ $item->keterangan }}"
data-tanggal="{{ $item->tanggal }}"
style="{{ $isPindahan ? 'pointer-events: none;' : '' }}"
@ -249,19 +249,17 @@ class="btn btn-danger btn-sm {{ $isPindahan ? 'disabled opacity-50' : '' }}"
{{-- ================= JENIS MUTASI ================= --}}
<div class="p-3 mb-3 border rounded bg-light">
<label class="fw-bold">1. Pilih Jenis Mutasi</label>
<select name="jenis_mutasi" id="jenisMutasi"
class="form-control mt-2 @error('jenis_mutasi') is-invalid @enderror">
<select name="jenis_mutasi_id" id="jenisMutasi"
class="form-control mt-2 @error('jenis_mutasi_id') is-invalid @enderror">
<option value="">-- Pilih Jenis Mutasi --</option>
<option value="masuk" {{ old('jenis_mutasi') == 'masuk' ? 'selected' : '' }}>Masuk (DOC)
</option>
<option value="mati" {{ old('jenis_mutasi') == 'mati' ? 'selected' : '' }}>Mati</option>
<option value="afkir" {{ old('jenis_mutasi') == 'afkir' ? 'selected' : '' }}>Afkir
</option>
<option value="pindah" {{ old('jenis_mutasi') == 'pindah' ? 'selected' : '' }}>Pindah
Kandang</option>
@foreach ($jenisMutasi as $jm)
<option value="{{ $jm->id }}" data-nama="{{ $jm->nama }}"
{{ old('jenis_mutasi_id') == $jm->id ? 'selected' : '' }}>
{{ ucfirst($jm->nama) }}
</option>
@endforeach
</select>
@error('jenis_mutasi')
@error('jenis_mutasi_id')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
@ -425,16 +423,16 @@ class="form-control @error('tanggal') is-invalid @enderror"
<div class="form-group">
<label>Jenis Mutasi</label>
<select name="jenis_mutasi" class="form-control @error('jenis_mutasi') is-invalid @enderror">
<option value="masuk" {{ old('jenis_mutasi') == 'masuk' ? 'selected' : '' }}>Masuk
</option>
<option value="mati" {{ old('jenis_mutasi') == 'mati' ? 'selected' : '' }}>Mati</option>
<option value="afkir" {{ old('jenis_mutasi') == 'afkir' ? 'selected' : '' }}>Afkir
</option>
<select name="jenis_mutasi_id" class="form-control">
@foreach ($jenisMutasi as $jm)
<option value="{{ $jm->id }}"
{{ old('jenis_mutasi_id') == $jm->id ? 'selected' : '' }}>
{{ ucfirst($jm->nama) }}
</option>
@endforeach
</select>
@error('jenis_mutasi')
@error('jenis_mutasi_id')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
@ -506,6 +504,8 @@ class="form-control @error('tanggal') is-invalid @enderror"
<script>
const baseUrl = "{{ route('ayam') }}";
$(document).ready(function() {
$('#jenisMutasi').trigger('change');
/* =============================
HANDLE MODAL EDIT NORMAL
============================= */
@ -523,7 +523,7 @@ class="form-control @error('tanggal') is-invalid @enderror"
$('#formEdit [name=kandang_id]').val(btn.data('kandang'));
$('#formEdit [name=jumlah]').val(btn.data('jumlah'));
$('#formEdit [name=jenis_mutasi]').val(btn.data('jenis'));
$('#formEdit [name=jenis_mutasi_id]').val(btn.data('jenis'));
$('#formEdit [name=tanggal]').val(btn.data('tanggal'));
$('#formEdit [name=keterangan]').val(btn.data('keterangan'));
});
@ -537,7 +537,7 @@ class="form-control @error('tanggal') is-invalid @enderror"
$('#formEdit [name=kandang_id]').val("{{ old('kandang_id') }}");
$('#formEdit [name=jumlah]').val("{{ old('jumlah') }}");
$('#formEdit [name=jenis_mutasi]').val("{{ old('jenis_mutasi') }}");
$('#formEdit [name=jenis_mutasi_id]').val("{{ old('jenis_mutasi_id') }}");
$('#formEdit [name=tanggal]').val("{{ old('tanggal') }}");
$('#formEdit [name=keterangan]').val(@json(old('keterangan')));
@ -577,19 +577,19 @@ class="form-control @error('tanggal') is-invalid @enderror"
/* =============================
TOGGLE PINDAH
============================== */
if ($('#jenisMutasi').length) {
$('#jenisMutasi').on('change', function() {
$('#jenisMutasi').on('change', function() {
if ($(this).val() === 'pindah') {
$('#groupKandang').slideUp(200);
$('#groupPindah').slideDown(200);
} else {
$('#groupPindah').slideUp(200);
$('#groupKandang').slideDown(200);
}
let nama = $(this).find(':selected').data('nama');
});
}
if (nama === 'pindah') {
$('#groupKandang').slideUp(200);
$('#groupPindah').slideDown(200);
} else {
$('#groupPindah').slideUp(200);
$('#groupKandang').slideDown(200);
}
});
});
</script>

View File

@ -8,6 +8,47 @@
<div class="mb-4">
<h4 class="mb-1 fw-bold">Manajemen Pakan</h4>
</div>
@if (auth()->user()->isAdmin() &&
((isset($stokMenipis) && $stokMenipis->count()) || (isset($stokAman) && $stokAman->count())))
<div class="mb-3 row">
{{-- STOK MENIPIS --}}
@if (isset($stokMenipis) && $stokMenipis->count())
<div class="col-md-6">
<div class="info-card warning">
<div class="d-flex align-items-start">
<div class="me-2"></div>
<div>
<div class="fw-semibold">Stok Menipis</div>
<small class="text-muted">
{{ $stokMenipis->map(fn($s) => $s->nama_barang . ' (' . number_format($s->stok, 0, ',', '.') . ')')->join(', ') }}
</small>
</div>
</div>
</div>
</div>
@endif
{{-- STOK AMAN --}}
@if (isset($stokAman) && $stokAman->count())
<div class="col-md-6">
<div class="info-card success">
<div class="d-flex align-items-start">
<div class="me-2"></div>
<div>
<div class="fw-semibold">Stok Aman</div>
<small class="text-muted">
{{ $stokAman->map(fn($s) => $s->nama_barang . ' (' . number_format($s->stok, 0, ',', '.') . ')')->join(', ') }}
</small>
</div>
</div>
</div>
</div>
@endif
</div>
@endif
<div class="shadow-sm card table-card operasional-page">
<!-- FILTER BAR -->
<form method="GET" id="formFilter">
@ -88,9 +129,10 @@ class="form-control form-control-sm">
</div>
</form>
@if (auth()->user()->isAdmin() && isset($stokMenipis) && $stokMenipis->count())
<div class="alert alert-warning">
<strong> Stok Menipis</strong>
{{-- @if (auth()->user()->isAdmin() && isset($stokMenipis) && $stokMenipis->count())
<div class="alert-custom warning">
<strong> Stok Menipis</strong>
<ul class="mb-0">
@foreach ($stokMenipis as $s)
<li>
@ -101,7 +143,13 @@ class="form-control form-control-sm">
</ul>
</div>
@endif
@if (auth()->user()->isAdmin() && isset($stokAman) && $stokAman->count())
<div class="alert-custom success">
<strong> Stok Aman:</strong>
{{ $stokAman->map(fn($s) => $s->nama_barang . ' (' . number_format($s->stok, 0, ',', '.') . ')')->join(', ') }}
karung
</div>
@endif --}}
@if ($errors->has('delete'))
<div class="alert alert-danger">
@ -662,7 +710,7 @@ function hitungEdit() {
let harga = parseInt(btn.data('harga')) || 0;
$('#hargaEdit').val(harga ? formatRupiah(harga.toString()) : '');
// tanggal
$('#tanggalEdit').val(btn.data('tanggal'));

View File

@ -0,0 +1,251 @@
@extends('template')
@section('title', 'Jenis Mutasi')
@section('content')
<div class="main-panel">
<div class="content">
<div class="container-fluid">
<h4 class="mb-3">Kelola Jenis Mutasi</h4>
<!-- TAMBAH -->
{{-- <button class="mb-3 btn btn-primary btn-sm" data-toggle="modal" data-target="#modalTambah">
+ Tambah Jenis
</button> --}}
<!-- TABLE -->
<div class="shadow-sm card table-card">
<div class="card-body border-bottom">
<div class="d-flex justify-content-between align-items-center">
{{-- <h5 class="mb-0 fw-bold">
Jenis Mutasi
</h5> --}}
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#modalTambah">
<i class="la la-plus"></i> Tambah
</button>
</div>
</div>
<div class="p-0 card-body">
<div class="table-responsive">
<table class="table mb-0 table-standard">
<thead>
<tr>
<th width="60" class="text-center">No</th>
<th>Nama</th>
<th>Tipe</th>
<th width="120" class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@forelse($data as $i => $item)
<tr>
<td class="text-center">{{ $i + 1 }}</td>
<td>{{ $item->nama }}</td>
<td>
<span class="badge badge-secondary">
{{ ucfirst($item->tipe) }}
</span>
</td>
<td class="text-center">
{{-- EDIT --}}
<button class="btn btn-warning btn-sm"
data-toggle="modal"
data-target="#modalEdit"
data-id="{{ $item->id }}"
data-nama="{{ $item->nama }}"
data-tipe="{{ $item->tipe }}"
title="Edit">
<i class="la la-edit"></i>
</button>
{{-- DELETE --}}
<button class="btn btn-danger btn-sm"
data-toggle="modal"
data-target="#modalHapus"
data-id="{{ $item->id }}"
title="Hapus">
<i class="la la-trash"></i>
</button>
</td>
</tr>
@empty
<tr>
<td colspan="4" class="py-4 text-center text-muted">
Belum ada data jenis mutasi
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{{-- MODAL TAMBAH --}}
<div class="modal fade" id="modalTambah" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<form method="POST" action="{{ route('jenis-mutasi.store') }}">
@csrf
<div class="modal-header modal-header-clean">
<h6 class="modal-title">
<i class="mr-1 la la-plus-circle text-muted"></i>
Tambah Jenis Mutasi
</h6>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Nama Jenis</label>
<input type="text" name="nama" class="form-control" placeholder="Contoh: Panen / Mati">
</div>
<div class="form-group">
<label>Tipe</label>
<select name="tipe" class="form-control">
<option value="tambah">Tambah</option>
<option value="kurang">Kurang</option>
<option value="transfer">Transfer</option>
</select>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button class="btn btn-primary">
<i class="la la-save"></i> Simpan
</button>
</div>
</form>
</div>
</div>
</div>
{{-- MODAL EDIT --}}
<div class="modal fade" id="modalEdit" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<form method="POST" id="formEdit">
@csrf
@method('PUT')
<div class="modal-header modal-header-clean">
<h6 class="modal-title">
<i class="la la-edit"></i> Edit Jenis Mutasi
</h6>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Nama Jenis</label>
<input type="text" name="nama" id="editNama" class="form-control">
</div>
<div class="form-group">
<label>Tipe</label>
<select name="tipe" id="editTipe" class="form-control">
<option value="tambah">Tambah</option>
<option value="kurang">Kurang</option>
<option value="transfer">Transfer</option>
</select>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button class="btn btn-primary">
<i class="la la-save"></i> Update
</button>
</div>
</form>
</div>
</div>
</div>
{{-- MODAL HAPUS --}}
<div class="modal fade" id="modalHapus" tabindex="-1">
<div class="modal-dialog modal-sm modal-dialog-centered">
<div class="modal-content">
<form method="POST" id="formHapus">
@csrf
@method('DELETE')
<div class="modal-header modal-header-clean">
<h6 class="modal-title">
<i class="la la-trash"></i> Hapus Data
</h6>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="text-center modal-body">
<p class="mb-0">Yakin ingin menghapus data ini?</p>
</div>
<div class="modal-footer justify-content-center">
<button class="btn btn-secondary btn-sm" data-dismiss="modal">Batal</button>
<button class="btn btn-danger btn-sm">
<i class="la la-trash"></i> Hapus
</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@section('scripts')
<script>
$('#modalEdit').on('show.bs.modal', function(e){
let btn = $(e.relatedTarget);
$('#formEdit').attr('action', '/jenis-mutasi/' + btn.data('id'));
$('#editNama').val(btn.data('nama'));
$('#editTipe').val(btn.data('tipe'));
});
$('#modalHapus').on('show.bs.modal', function(e){
let btn = $(e.relatedTarget);
$('#formHapus').attr('action', '/jenis-mutasi/' + btn.data('id'));
});
</script>
@endsection

View File

@ -181,16 +181,18 @@ class="d-inline">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Nama Lengkap</label>
<input type="text" name="nama_karyawan" value="{{ old('nama_karyawan') }}"
class="form-control @error('nama_karyawan') is-invalid @enderror">
<div class="form-group">
<label>Nama Lengkap</label>
<input type="text" name="nama_karyawan"
value="{{ old('nama_karyawan') }}"
oninput="this.value = this.value.replace(/[^A-Za-z\s]/g,'')"
class="form-control @error('nama_karyawan') is-invalid @enderror">
@error('nama_karyawan')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
</div>
@error('nama_karyawan')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
</div>
<div class="col-md-6">
<div class="form-group">

View File

@ -134,6 +134,13 @@ class="d-none d-sm-inline font-weight-bold text-dark">{{ auth()->user()->name }}
<span class="sub-item">Populasi Ayam</span>
</a>
</li>
@if (auth()->user()->role === 'admin')
<li class="{{ Route::is('jenis-mutasi') ? 'active' : '' }}">
<a href="{{ route('jenis-mutasi') }}">
<span class="sub-item">Kelola Jenis Mutasi Ayam</span>
</a>
</li>
@endif
</ul>
</div>
</li>

View File

@ -12,7 +12,9 @@
KeuanganController,
LaporanController,
ProfilController,
LaporanExportController
LaporanExportController,
JenisMutasiController
};
use App\Http\Middleware\CheckRole;
@ -97,6 +99,14 @@
Route::get('/laporan', [LaporanController::class, 'index'])->name('laporan');
Route::get('/laporan/export', [LaporanController::class, 'export'])->name('laporan.export');
// JENIS MUTASI (MASTER DATA)
Route::prefix('jenis-mutasi')->group(function () {
Route::get('/', [JenisMutasiController::class, 'index'])->name('jenis-mutasi');
Route::post('/', [JenisMutasiController::class, 'store'])->name('jenis-mutasi.store');
Route::put('/{id}', [JenisMutasiController::class, 'update'])->name('jenis-mutasi.update');
Route::delete('/{id}', [JenisMutasiController::class, 'destroy'])->name('jenis-mutasi.delete');
});
});
});
Route::fallback(function () {