Update Map Tanaman & User

This commit is contained in:
2026-06-03 09:53:16 +07:00
parent 751f14cb02
commit 17d384acf9
15 changed files with 3486 additions and 5 deletions
@@ -10,6 +10,7 @@ use App\Enums\Role;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class UserController extends Controller
{
@@ -70,6 +71,7 @@ class UserController extends Controller
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'],
@@ -90,14 +92,17 @@ class UserController extends Controller
$user = User::create([
'name' => $request->name,
'username' => $request->username,
'email' => $request->email,
'password' => Hash::make($request->password),
'role' => $request->role,
'uid' => Str::random(10),
'created_by' => auth()->id(),
]);
Profile::create([
'user_id' => $user->id,
'user_uid' => $user->uid,
'role' => $request->role,
'nama' => $request->name,
'email' => $request->email,
@@ -44,6 +44,16 @@ class VarietasController extends Controller
));
}
public function getByJenisKomoditas($jenisKomoditasId)
{
$varietas = Varietas::where('jenis_komoditas_id', $jenisKomoditasId)->get();
return response()->json([
'status' => 'success',
'data' => $varietas,
]);
}
public function store(Request $request)
{
$komoditasTable = (new Komoditas)->getTable();
@@ -10,6 +10,7 @@ use App\Models\Pertanian\Adat;
use App\Models\Wilayah\Provinsi;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class LahanController extends Controller
{
@@ -76,6 +77,25 @@ class LahanController extends Controller
return view('produktivitas.lahan.index', compact('lahan', 'provinsi', 'profiles', 'adat', 'kabupaten', 'kecamatan', 'desa'));
}
public function getByProfile(Request $request, $profileId)
{
$desaKelurahanId = $request->get('desa_kelurahan_id');
$lahan = Lahan::with('profile')
->where('profile_id', $profileId)
->when($desaKelurahanId, function ($query) use ($desaKelurahanId) {
$query->where('desa_kelurahan_id', $desaKelurahanId);
})
->orderBy('created_at', 'desc')
->get(['id', 'nama', 'path', 'profile_id', 'desa_kelurahan_id']);
return response()->json([
'status' => 'success',
'data' => $lahan,
]);
}
public function create()
{
$provinsi = Provinsi::orderBy('nama', 'asc')->get();
@@ -112,8 +132,12 @@ class LahanController extends Controller
return response()->json(['status' => 'error', 'message' => 'Format koordinat (path) bukan JSON array yang valid.'], 422);
}
}
$userUID = Profile::where('id', $request->profile_id)->value('user_uid');
$userUID = substr($userUID, 2);
Lahan::create([
'uid' => 'LH' . $userUID . '-' . strtoupper(Str::random(10)),
'nama' => $request->nama,
'status_kepemilikan' => $request->status_kepemilikan,
'profile_id' => $request->profile_id,
@@ -0,0 +1,421 @@
<?php
namespace App\Http\Controllers\Web\Produktivitas;
use App\Http\Controllers\Controller;
use App\Models\Pertanian\Tanaman;
use App\Models\Profile;
use App\Models\Pertanian\Komoditas;
use App\Models\Master\JenisKomoditas;
use App\Models\Master\Varietas;
use App\Models\Pertanian\Lahan;
use App\Models\Wilayah\Provinsi;
use App\Models\Wilayah\KabupatenKota;
use App\Models\Wilayah\Kecamatan;
use App\Models\Wilayah\DesaKelurahan;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class MapTanamanController extends Controller
{
public function index(Request $request)
{
$perPage = $request->get('per_page', 10);
$search = $request->get('search');
$tanaman = Tanaman::query()
->select([
DB::raw('MIN(id) as id'),
'profile_id',
'lahan_id',
'komoditas_id',
'jenis_komoditas_id',
'varietas_id',
DB::raw('COUNT(*) as total_tanaman'),
DB::raw("SUM(CASE WHEN kondisi_tanaman = 'sehat' THEN 1 ELSE 0 END) as total_sehat"),
DB::raw("SUM(CASE WHEN kondisi_tanaman = 'sakit' THEN 1 ELSE 0 END) as total_sakit"),
DB::raw("SUM(CASE WHEN kondisi_tanaman = 'mati' THEN 1 ELSE 0 END) as total_mati"),
DB::raw('MAX(created_at) as max_created_at'),
])
->with([
'profile',
'lahan.desaKelurahan.kecamatan.kabupatenkota.provinsi',
'komoditas',
'jenisKomoditas',
'varietas',
])
->when($search, function ($query) use ($search) {
$query->where(function ($q) use ($search) {
$q->whereHas('profile', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('lahan', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('komoditas', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('jenisKomoditas', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('varietas', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('lahan.desaKelurahan', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('lahan.desaKelurahan.kecamatan', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('lahan.desaKelurahan.kecamatan.kabupatenkota', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"))
->orWhereHas('lahan.desaKelurahan.kecamatan.kabupatenkota.provinsi', fn ($q) => $q->where('nama', 'ILIKE', "%{$search}%"));
});
})
->groupBy([
'profile_id',
'lahan_id',
'komoditas_id',
'jenis_komoditas_id',
'varietas_id',
])
->orderByDesc('max_created_at')
->paginate($perPage);
return view('produktivitas.mapTanaman.index', compact('tanaman'));
}
private function getTanamanGroupByRepresentativeId($id)
{
$representative = Tanaman::findOrFail($id);
$points = Tanaman::with([
'profile',
'lahan.desaKelurahan.kecamatan.kabupatenkota.provinsi',
'komoditas',
'jenisKomoditas',
'varietas',
])
->where('profile_id', $representative->profile_id)
->where('lahan_id', $representative->lahan_id)
->where('komoditas_id', $representative->komoditas_id)
->where('jenis_komoditas_id', $representative->jenis_komoditas_id)
->where('varietas_id', $representative->varietas_id)
->orderBy('id')
->get();
return [
'representative' => $representative,
'points' => $points,
];
}
public function create()
{
$provinsi = Provinsi::select('id', 'nama', 'path')
->orderBy('nama')
->get();
$komoditas = Komoditas::orderBy('nama')->get();
$profiles = Profile::orderBy('nama')->get();
return view('produktivitas.mapTanaman.add', compact(
'provinsi',
'komoditas',
'profiles'
));
}
public function store(Request $request)
{
$desaKelurahanTable = (new DesaKelurahan)->getTable();
$profileTable = (new Profile)->getTable();
$lahanTable = (new Lahan)->getTable();
$komoditasTable = (new Komoditas)->getTable();
$jenisKomoditasTable = (new JenisKomoditas)->getTable();
$varietasTable = (new Varietas)->getTable();
$validated = $request->validate([
'desa_kelurahan_id' => [
'required',
'integer',
Rule::exists($desaKelurahanTable, 'id'),
],
'profile_id' => [
'required',
'integer',
Rule::exists($profileTable, 'id'),
],
'lahan_id' => [
'required',
'integer',
Rule::exists($lahanTable, 'id')
->where('profile_id', $request->profile_id)
->where('desa_kelurahan_id', $request->desa_kelurahan_id),
],
'komoditas_id' => [
'required',
'integer',
Rule::exists($komoditasTable, 'id'),
],
'jenis_komoditas_id' => [
'required',
'integer',
Rule::exists($jenisKomoditasTable, 'id')
->where('komoditas_id', $request->komoditas_id),
],
'varietas_id' => [
'required',
'integer',
Rule::exists($varietasTable, 'id')
->where('jenis_komoditas_id', $request->jenis_komoditas_id),
],
'points' => [
'required',
'array',
'min:1',
],
'points.*.latitude' => [
'required',
'numeric',
],
'points.*.longitude' => [
'required',
'numeric',
],
'points.*.kondisi_tanaman' => [
'required',
Rule::in(['sehat', 'sakit', 'mati']),
],
'metode_pengumpulan' => [
'nullable',
'string',
'max:50',
],
'deskripsi' => [
'nullable',
'string',
],
], [
'points.required' => 'Minimal tambahkan satu titik tanaman pada peta.',
'points.min' => 'Minimal tambahkan satu titik tanaman pada peta.',
'points.*.latitude.required' => 'Latitude titik tanaman wajib ada.',
'points.*.longitude.required' => 'Longitude titik tanaman wajib ada.',
'points.*.kondisi_tanaman.required' => 'Kondisi tanaman wajib dipilih.',
]);
try {
DB::beginTransaction();
$lahan = Lahan::findOrFail($validated['lahan_id']);
$komoditas = Komoditas::findOrFail($validated['komoditas_id']);
$profile = Profile::findOrFail($validated['profile_id']);
if (!$lahan->uid) {
throw new \Exception('UID lahan tidak ditemukan.');
}
$profileName = str_replace(' ', '', $profile->nama);
$lahanUidPart = substr($lahan->uid, 2);
$existingCount = Tanaman::where('lahan_id', $validated['lahan_id'])
->where('komoditas_id', $validated['komoditas_id'])
->where('jenis_komoditas_id', $validated['jenis_komoditas_id'])
->where('varietas_id', $validated['varietas_id'])
->count();
$createdTanaman = [];
foreach ($validated['points'] as $index => $point) {
$number = $existingCount + $index + 1;
$createdTanaman[] = Tanaman::create([
'uid' => 'TM' . $lahanUidPart . '-' . strtoupper(Str::random(10)),
'nama' => $komoditas->nama . ' - ' . $profileName . ' - ' . $number,
'desa_kelurahan_id' => $validated['desa_kelurahan_id'],
'profile_id' => $validated['profile_id'],
'lahan_id' => $validated['lahan_id'],
'komoditas_id' => $validated['komoditas_id'],
'jenis_komoditas_id' => $validated['jenis_komoditas_id'],
'varietas_id' => $validated['varietas_id'],
'latitude' => $point['latitude'],
'longitude' => $point['longitude'],
'kondisi_tanaman' => $point['kondisi_tanaman'],
'metode_pengumpulan' => $validated['metode_pengumpulan'] ?? 'manual',
'deskripsi' => $validated['deskripsi'] ?? null,
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
]);
}
DB::commit();
return response()->json([
'status' => 'success',
'message' => count($createdTanaman) . ' data tanaman berhasil disimpan.',
'redirect' => route('map-tanaman.index'),
'data' => $createdTanaman,
]);
} catch (\Throwable $e) {
DB::rollBack();
Log::error('Gagal menyimpan tanaman bulk', [
'error' => $e->getMessage(),
'request' => $request->all(),
]);
return response()->json([
'status' => 'error',
'message' => 'Gagal menyimpan data: ' . $e->getMessage(),
], 500);
}
}
public function show(string $id)
{
$group = $this->getTanamanGroupByRepresentativeId($id);
$tanaman = $group['representative']->load([
'profile',
'lahan.desaKelurahan.kecamatan.kabupatenkota.provinsi',
'komoditas',
'jenisKomoditas',
'varietas',
]);
$points = $group['points'];
return view('produktivitas.mapTanaman.view', compact(
'tanaman',
'points'
));
}
public function edit(string $id)
{
$group = $this->getTanamanGroupByRepresentativeId($id);
$tanaman = $group['representative']->load([
'profile',
'lahan.desaKelurahan.kecamatan.kabupatenkota.provinsi',
'komoditas',
'jenisKomoditas',
'varietas',
]);
$points = $group['points'];
return view('produktivitas.mapTanaman.edit', compact(
'tanaman',
'points'
));
}
public function update(Request $request, string $id)
{
$group = $this->getTanamanGroupByRepresentativeId($id);
$representative = $group['representative'];
$validated = $request->validate([
'points' => ['required', 'array', 'min:1'],
'points.*.id' => ['nullable', 'integer', 'exists:map_tanaman,id'],
'points.*.latitude' => ['required', 'numeric'],
'points.*.longitude' => ['required', 'numeric'],
'points.*.kondisi_tanaman' => [
'required',
Rule::in(['sehat', 'sakit', 'mati']),
],
'points.*._delete' => ['nullable'],
]);
try {
DB::beginTransaction();
foreach ($validated['points'] as $point) {
if (!empty($point['_delete']) && !empty($point['id'])) {
$tanaman = Tanaman::where('id', $point['id'])
->where('profile_id', $representative->profile_id)
->where('lahan_id', $representative->lahan_id)
->where('komoditas_id', $representative->komoditas_id)
->where('jenis_komoditas_id', $representative->jenis_komoditas_id)
->where('varietas_id', $representative->varietas_id)
->first();
if ($tanaman) {
$tanaman->deleted_by = auth()->id();
$tanaman->save();
$tanaman->delete();
}
continue;
}
if (!empty($point['id'])) {
$tanaman = Tanaman::where('id', $point['id'])
->where('profile_id', $representative->profile_id)
->where('lahan_id', $representative->lahan_id)
->where('komoditas_id', $representative->komoditas_id)
->where('jenis_komoditas_id', $representative->jenis_komoditas_id)
->where('varietas_id', $representative->varietas_id)
->firstOrFail();
$tanaman->update([
'latitude' => $point['latitude'],
'longitude' => $point['longitude'],
'kondisi_tanaman' => $point['kondisi_tanaman'],
'updated_by' => auth()->id(),
]);
}
}
DB::commit();
return response()->json([
'status' => 'success',
'message' => 'Data titik tanaman berhasil diperbarui.',
'redirect' => route('map-tanaman.index'),
]);
} catch (\Throwable $e) {
DB::rollBack();
return response()->json([
'status' => 'error',
'message' => 'Gagal memperbarui data: ' . $e->getMessage(),
], 500);
}
}
public function destroy(string $id)
{
try {
DB::beginTransaction();
$group = $this->getTanamanGroupByRepresentativeId($id);
$points = $group['points'];
foreach ($points as $point) {
$point->update([
'deleted_by' => auth()->id(),
]);
$point->delete();
}
DB::commit();
return response()->json([
'status' => 'success',
'message' => $points->count() . ' titik tanaman berhasil dihapus.',
]);
} catch (\Throwable $e) {
DB::rollBack();
return response()->json([
'status' => 'error',
'message' => 'Gagal menghapus data: ' . $e->getMessage(),
], 500);
}
}
}
@@ -30,6 +30,25 @@ class ProfileController extends Controller
return view('master.profile.index', compact('profiles', 'provinsi'));
}
public function getByDesaKelurahan($desaId)
{
try {
$profiles = Profile::where('desa_kelurahan_id', $desaId)
->orderBy('nama', 'asc')
->get(['id', 'nama']);
return response()->json([
'status' => 'success',
'data' => $profiles,
]);
} catch (\Throwable $e) {
return response()->json([
'status' => 'error',
'message' => $e->getMessage(),
], 500);
}
}
public function create()
{
$provinsi = Provinsi::orderBy('nama', 'asc')->get();
+5
View File
@@ -25,4 +25,9 @@ class JenisKomoditas extends Model
{
return $this->belongsTo(Komoditas::class, 'komoditas_id');
}
public function varietas()
{
return $this->hasMany(Varietas::class, 'jenis_komoditas_id');
}
}
+12
View File
@@ -5,6 +5,8 @@ namespace App\Models\Pertanian;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
use App\Models\Master\JenisKomoditas;
use App\Models\Master\Varietas;
class Komoditas extends Model
{
@@ -30,4 +32,14 @@ class Komoditas extends Model
$builder->whereIn('id', app('SystemProgram')->komoditas()->pluck('id'));
});
}
public function jenisKomoditas()
{
return $this->hasMany(JenisKomoditas::class, 'komoditas_id');
}
public function varietas()
{
return $this->hasMany(Varietas::class, 'komoditas_id');
}
}
+19 -2
View File
@@ -4,9 +4,11 @@ namespace App\Models\Pertanian;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\Lahan;
use App\Models\Profile;
use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\Komoditas;
use App\Models\Master\JenisKomoditas;
use App\Models\Master\Varietas;
class Tanaman extends Model
{
@@ -15,13 +17,18 @@ class Tanaman extends Model
protected $table = 'map_tanaman';
protected $fillable = [
'uid',
'nama',
'jenis_komoditas_id',
'varietas_id',
'komoditas_id',
'profile_id',
'lahan_id',
'latitude',
'longitude',
'kondisi_tanaman',
'metode_pengumpulan',
'deskripsi',
'created_by',
'updated_by',
'deleted_by',
@@ -32,6 +39,16 @@ class Tanaman extends Model
return $this->belongsTo(Komoditas::class, 'komoditas_id');
}
public function jenisKomoditas()
{
return $this->belongsTo(JenisKomoditas::class, 'jenis_komoditas_id');
}
public function varietas()
{
return $this->belongsTo(Varietas::class, 'varietas_id');
}
public function profile()
{
return $this->belongsTo(Profile::class, 'profile_id');