diff --git a/app/Http/Controllers/Web/Konfigurasi/UserController.php b/app/Http/Controllers/Web/Konfigurasi/UserController.php index 7d79fc1..d9bfc73 100644 --- a/app/Http/Controllers/Web/Konfigurasi/UserController.php +++ b/app/Http/Controllers/Web/Konfigurasi/UserController.php @@ -7,6 +7,7 @@ use Illuminate\Http\Request; use App\Models\User; use App\Models\Profile; use App\Enums\Role; +use App\Models\Wilayah\Provinsi; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; @@ -68,14 +69,28 @@ class UserController extends Controller } } + public function create() + { + $roles = Role::cases(); + $provinsi = Provinsi::orderBy('nama', 'asc')->get(); + + return view('konfigurasi.user.add', compact('roles', 'provinsi')); + } + public function store(Request $request) { $validator = Validator::make($request->all(), [ - 'username' => ['required', 'string', 'max:255', 'unique:users,name'], - 'name' => ['required', 'string', 'max:255'], - 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], - 'password' => ['required', 'string', 'min:8', 'confirmed'], - 'role' => ['required', 'string'], + 'username' => ['required', 'string', 'max:255', 'unique:users,username'], + 'nama' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email'], + 'password' => ['required', 'string', 'min:8', 'confirmed'], + 'role' => ['required', 'string'], + 'telepon' => ['required', 'max:13'], + 'desa_kelurahan_id' => ['required'], + 'ktp' => ['nullable', 'min:16', 'max:16'], + 'kk' => ['nullable', 'min:16', 'max:16'], + 'file_ktp' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'], + 'file_kk' => ['nullable', 'file', 'mimes:jpeg,jpg,pdf,png', 'max:2048'], ], [ 'password.confirmed' => 'Konfirmasi password tidak cocok!', 'password.min' => 'Password minimal 8 karakter!', @@ -84,14 +99,25 @@ class UserController extends Controller ]); if ($validator->fails()) { - return response()->json(['status' => 'error', 'errors' => $validator->errors()], 422); + if ($request->expectsJson()) { + return response()->json(['status' => 'error', 'errors' => $validator->errors()], 422); + } + + return back()->withErrors($validator)->withInput(); } try { DB::transaction(function () use ($request) { + $pathKtp = $request->hasFile('file_ktp') + ? $request->file('file_ktp')->store('uploads/users/ktp', 'public') + : null; + + $pathKk = $request->hasFile('file_kk') + ? $request->file('file_kk')->store('uploads/users/kk', 'public') + : null; $user = User::create([ - 'name' => $request->name, + 'name' => $request->nama, 'username' => $request->username, 'email' => $request->email, 'password' => Hash::make($request->password), @@ -104,18 +130,34 @@ class UserController extends Controller 'user_id' => $user->id, 'user_uid' => $user->uid, 'role' => $request->role, - 'nama' => $request->name, + 'nama' => $request->nama, 'email' => $request->email, + 'telepon' => $request->telepon, + 'alamat' => $request->alamat, + 'kk' => $request->kk, + 'ktp' => $request->ktp, + 'desa_kelurahan_id' => $request->desa_kelurahan_id, + 'path_kk' => $pathKk, + 'path_ktp' => $pathKtp, 'created_by' => auth()->id(), + 'updated_by' => auth()->id(), ]); }); - return response()->json([ - 'status' => 'success', - 'message' => 'User baru berhasil ditambahkan.' - ]); + if ($request->expectsJson()) { + return response()->json([ + 'status' => 'success', + 'message' => 'User baru berhasil ditambahkan.' + ]); + } + + return redirect()->route('users.index')->with('success', 'User baru berhasil ditambahkan.'); } catch (\Exception $e) { + if (!$request->expectsJson()) { + return back()->withInput()->with('error', 'Gagal menyimpan data: ' . $e->getMessage()); + } + return response()->json([ 'status' => 'error', 'message' => 'Gagal menyimpan data: ' . $e->getMessage() diff --git a/app/Http/Controllers/Web/Produktivitas/ProduksiController.php b/app/Http/Controllers/Web/Produktivitas/ProduksiController.php index d7e387b..9b13876 100644 --- a/app/Http/Controllers/Web/Produktivitas/ProduksiController.php +++ b/app/Http/Controllers/Web/Produktivitas/ProduksiController.php @@ -4,38 +4,40 @@ namespace App\Http\Controllers\Web\Produktivitas; use App\Http\Controllers\Controller; use App\Enums\Role; +use App\Models\Map\Lahan; +use App\Models\Map\Panen; +use App\Models\Map\PanenTanaman; use App\Models\Pertanian\Komoditas; -use App\Models\Pertanian\Lahan; -use App\Models\Pertanian\Produksi; use App\Models\Profile; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; use Illuminate\Validation\Rule; class ProduksiController extends Controller { public function index(Request $request) { - $query = Produksi::with(['profile', 'lahan', 'komoditas']) + $query = Panen::with(['petani', 'lahan', 'panenTanaman']) + ->orderBy('harvest_date', 'desc') ->orderBy('created_at', 'desc'); if ($request->filled('search')) { $query->where(function ($q) use ($request) { $search = '%' . $request->search . '%'; - $q->where('kode_produksi', 'like', $search) - ->orWhere('periode', 'like', $search) - ->orWhereHas('profile', fn ($profile) => $profile->where('nama', 'like', $search)) + $q->where('title', 'like', $search) + ->orWhere('notes', 'like', $search) + ->orWhereHas('petani', fn ($profile) => $profile->where('nama', 'like', $search)) ->orWhereHas('lahan', fn ($lahan) => $lahan->where('nama', 'like', $search)) - ->orWhereHas('komoditas', fn ($komoditas) => $komoditas->where('nama', 'like', $search)); + ->orWhereHas('panenTanaman', fn ($detail) => $detail->where('commodity_name', 'like', $search)); }); } - if ($request->filled('status_panen')) { - $query->where('status_panen', $request->status_panen); - } - - if ($request->filled('komoditas_id')) { - $query->where('komoditas_id', $request->komoditas_id); + if ($request->filled('komoditas')) { + $query->whereHas('panenTanaman', function ($detail) use ($request) { + $detail->where('commodity_name', $request->komoditas); + }); } $produksi = $query->paginate($request->per_page ?? 10); @@ -57,24 +59,28 @@ class ProduksiController extends Controller return back()->withErrors($validator)->withInput(); } - Produksi::create($this->payload($request) + [ - 'created_by' => auth()->id(), - 'updated_by' => auth()->id(), - ]); + DB::transaction(function () use ($request) { + $panen = Panen::create($this->panenPayload($request) + [ + 'created_by' => auth()->id(), + 'updated_by' => auth()->id(), + ]); + + $this->savePanenDetail($panen, $request); + }); return redirect()->route('produksi.index')->with('success', 'Data hasil panen berhasil ditambahkan.'); } public function show($id) { - $produksi = Produksi::with(['profile', 'lahan', 'komoditas'])->findOrFail($id); + $produksi = Panen::with(['petani', 'lahan', 'panenTanaman'])->findOrFail($id); return view('produktivitas.produksi.view', compact('produksi')); } public function edit($id) { - $produksi = Produksi::findOrFail($id); + $produksi = Panen::with('panenTanaman')->findOrFail($id); return view('produktivitas.produksi.edit', $this->formData() + compact('produksi')); } @@ -87,19 +93,24 @@ class ProduksiController extends Controller return back()->withErrors($validator)->withInput(); } - $produksi = Produksi::findOrFail($id); - $produksi->update($this->payload($request) + [ - 'updated_by' => auth()->id(), - ]); + DB::transaction(function () use ($request, $id) { + $panen = Panen::findOrFail($id); + $panen->update($this->panenPayload($request) + [ + 'updated_by' => auth()->id(), + ]); + + $this->savePanenDetail($panen, $request); + }); return redirect()->route('produksi.index')->with('success', 'Data hasil panen berhasil diperbarui.'); } public function destroy($id) { - $produksi = Produksi::findOrFail($id); - $produksi->update(['deleted_by' => auth()->id()]); - $produksi->delete(); + $panen = Panen::findOrFail($id); + $panen->panenTanaman()->delete(); + $panen->update(['deleted_by' => auth()->id()]); + $panen->delete(); return response()->json(['status' => 'success', 'message' => 'Data hasil panen berhasil dihapus.']); } @@ -108,9 +119,7 @@ class ProduksiController extends Controller { return [ 'profiles' => Profile::where('role', Role::PETANI->value)->orderBy('nama')->get(), - 'lahan' => Lahan::whereHas('profile', function ($query) { - $query->where('role', Role::PETANI->value); - })->orderBy('nama')->get(), + 'lahan' => Lahan::whereNotNull('profile_id')->orderBy('nama')->get(), 'komoditas' => Komoditas::orderBy('nama')->get(), ]; } @@ -118,47 +127,56 @@ class ProduksiController extends Controller private function validator(Request $request) { return Validator::make($request->all(), [ - 'kode_produksi' => ['nullable', 'string', 'max:255'], - 'profile_id' => [ + 'farmer_id' => [ 'required', Rule::exists('profiles', 'id')->where('role', Role::PETANI->value), ], - 'lahan_id' => [ + 'land_id' => [ 'required', - Rule::exists('map_lahan', 'id')->where('profile_id', $request->profile_id), + Rule::exists('map_lahan', 'id')->where('profile_id', $request->farmer_id), ], - 'komoditas_id' => ['required', 'exists:master_komoditas,id'], - 'periode' => ['nullable', 'string', 'max:255'], - 'tanggal_panen' => ['required', 'date'], - 'luas_tanam' => ['nullable', 'numeric', 'min:0'], - 'luas_panen' => ['nullable', 'numeric', 'min:0'], - 'jumlah_panen' => ['required', 'numeric', 'min:0'], - 'satuan' => ['required', 'string', 'max:20'], - 'status_panen' => ['nullable', 'in:panen_sebagian,selesai'], - 'catatan' => ['nullable', 'string'], + 'commodity_name' => ['required', 'string', 'max:255'], + 'harvest_date' => ['required', 'date'], + 'weight_kg' => ['required', 'numeric', 'min:0'], + 'satuan' => ['required', 'in:kg,kuintal,ton'], + 'land_description' => ['nullable', 'string'], + 'notes' => ['nullable', 'string'], ]); } - private function payload(Request $request): array + private function panenPayload(Request $request): array { - $luasPanen = (float) $request->luas_panen; - $jumlahPanen = (float) $request->jumlah_panen; - return [ - 'kode_produksi' => $request->kode_produksi, - 'profile_id' => $request->profile_id, - 'lahan_id' => $request->lahan_id, - 'tanaman_id' => null, - 'komoditas_id' => $request->komoditas_id, - 'periode' => $request->periode, - 'tanggal_panen' => $request->tanggal_panen, - 'luas_tanam' => $request->luas_tanam, - 'luas_panen' => $request->luas_panen, - 'jumlah_panen' => $request->jumlah_panen, - 'satuan' => $request->satuan, - 'produktivitas' => $luasPanen > 0 ? round($jumlahPanen / $luasPanen, 2) : null, - 'status_panen' => $request->status_panen ?? 'selesai', - 'catatan' => $request->catatan, + 'uid' => $request->uid ?: 'PN-' . Str::uuid(), + 'title' => $request->title ?: 'Panen ' . $request->commodity_name, + 'land_id' => $request->land_id, + 'farmer_id' => $request->farmer_id, + 'land_description' => $request->land_description, + 'harvest_date' => $request->harvest_date, + 'notes' => $request->notes, + 'sync_status' => 'synced', ]; } + + private function savePanenDetail(Panen $panen, Request $request): void + { + $detail = $panen->panenTanaman()->first() ?: new PanenTanaman(['panen_id' => $panen->id]); + $detail->fill([ + 'panen_id' => $panen->id, + 'tanaman_id' => null, + 'commodity_name' => $request->commodity_name, + 'weight_kg' => $this->toKilograms((float) $request->weight_kg, $request->satuan), + 'sync_status' => 'synced', + ]); + $detail->save(); + } + + private function toKilograms(float $value, string $unit): float + { + return match ($unit) { + 'ton' => $value * 1000, + 'kuintal' => $value * 100, + default => $value, + }; + } } diff --git a/app/Models/Map/Panen.php b/app/Models/Map/Panen.php index 47386c3..8061b2a 100644 --- a/app/Models/Map/Panen.php +++ b/app/Models/Map/Panen.php @@ -29,6 +29,9 @@ class Panen extends Model 'harvest_date', 'notes', 'sync_status', + 'created_by', + 'updated_by', + 'deleted_by', ]; protected $casts = [ @@ -65,4 +68,4 @@ class Panen extends Model { return $this->hasMany(PanenTanaman::class, 'panen_id', 'id'); } -} \ No newline at end of file +} diff --git a/database/migrations/2026_06_06_134032_create_panen_tanamen_table.php b/database/migrations/2026_06_06_134032_create_panen_tanamen_table.php index 9ab2c9a..e55dfdd 100644 --- a/database/migrations/2026_06_06_134032_create_panen_tanamen_table.php +++ b/database/migrations/2026_06_06_134032_create_panen_tanamen_table.php @@ -15,10 +15,10 @@ return new class extends Migration $bluePrint->id(); $bluePrint->foreignId('panen_id') - ->constrained('panen') + ->constrained('map_panen') ->onDelete('cascade'); - $bluePrint->unsignedBigInteger('tanaman_id'); + $bluePrint->unsignedBigInteger('tanaman_id')->nullable(); $bluePrint->string('commodity_name'); $bluePrint->string('sync_status', 50)->nullable()->default('synced'); $bluePrint->decimal('weight_kg', 10, 2); // Menggunakan decimal agar mendukung angka pecahan (misal: 10.5 kg) @@ -33,6 +33,6 @@ return new class extends Migration */ public function down(): void { - Schema::dropIfExists('panen_tanamen'); + Schema::dropIfExists('panen_tanaman'); } }; diff --git a/resources/views/konfigurasi/user/add.blade.php b/resources/views/konfigurasi/user/add.blade.php index 640a69c..52ddf16 100644 --- a/resources/views/konfigurasi/user/add.blade.php +++ b/resources/views/konfigurasi/user/add.blade.php @@ -1,56 +1,286 @@ -