Update BUMDes

This commit is contained in:
2026-11-05 19:20:05 +07:00
parent 9cdd178297
commit c55ff109a0
73 changed files with 6699 additions and 1548 deletions
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum AsetProduktifBumdes: string
{
case BANGUNAN_KANTOR = 'bangunan_kantor';
case GUDANG_PENYIMPANAN = 'gudang_penyimpanan';
case KENDARAAN_OPERASIONAL_ANGKUT = 'kendaraan_operasional_angkut';
case LAHAN_USAHA = 'lahan_usaha';
case ALAT_PENGOLAHAN_KOMODITAS = 'alat_pengolahan_komoditas';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::BANGUNAN_KANTOR => 'Bangunan / kantor',
self::GUDANG_PENYIMPANAN => 'Gudang penyimpanan',
self::KENDARAAN_OPERASIONAL_ANGKUT => 'Kendaraan operasional/angkut',
self::LAHAN_USAHA => 'Lahan usaha',
self::ALAT_PENGOLAHAN_KOMODITAS => 'Alat pengolahan komoditas',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum BentukProdukBumdes: string
{
case BUAH_SEGAR = 'buah_segar';
case BIJI_BASAH = 'biji_basah';
case BIJI_KERING = 'biji_kering';
case TERFERMENTASI = 'terfermentasi';
public function label(): string
{
return match ($this) {
self::BUAH_SEGAR => 'Buah segar hasil petik',
self::BIJI_BASAH => 'Biji basah',
self::BIJI_KERING => 'Biji kering/biji kupas',
self::TERFERMENTASI => 'Terfermentasi',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Enums\Bumdes;
enum CakupanLayananBumdes: string
{
case DESA_SENDIRI = 'desa_sendiri';
case DESA_LAIN = 'desa_sendiri_dan_lain';
public function label(): string
{
return match ($this) {
self::DESA_SENDIRI => 'Hanya melayani desa sendiri',
self::DESA_LAIN => 'Melayani desa sendiri dan desa lain',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace App\Enums\Bumdes;
enum DukunganDesaBumdes: string
{
case PENDAMPINGAN_TEKNIS = 'pendampingan_teknis';
case REGULASI_PERDES = 'regulasi_perdes';
case FASILITASI_JEJARING = 'fasilitasi_jejaring';
case TIDAK_ADA = 'tidak_ada';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::PENDAMPINGAN_TEKNIS => 'Pendampingan teknis',
self::REGULASI_PERDES => 'Regulasi/Perdes pendukung',
self::FASILITASI_JEJARING => 'Fasilitasi jejaring/kemitraan',
self::TIDAK_ADA => 'Tidak ada dukungan khusus',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum FormatPembukuanBumdes: string
{
case MANUAL = 'manual';
case DIGITAL_EXCEL = 'digital_excel';
case APLIKASI = 'aplikasi';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::MANUAL => 'Manual/buku kas',
self::DIGITAL_EXCEL => 'Digital/file Excel',
self::APLIKASI => 'Aplikasi keuangan khusus',
self::TIDAK_ADA => 'Tidak ada',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum HambatanUsahaBumdes: string
{
case MODAL = 'modal';
case SDM = 'sdm';
case INFRASTRUKTUR = 'infrastruktur';
case PASOKAN = 'pasokan';
case PERSAINGAN = 'persaingan';
case AKSES_PASAR = 'akses_pasar';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::MODAL => 'Keterbatasan modal',
self::SDM => 'Keterbatasan SDM/kapasitas pengurus',
self::INFRASTRUKTUR => 'Keterbatasan infrastruktur/alat',
self::PASOKAN => 'Kesulitan mendapat pasokan konsisten dari produsen',
self::PERSAINGAN => 'Persaingan dengan tengkulak/pedagang',
self::AKSES_PASAR => 'Belum ada akses ke offtaker/pasar premium',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum HubunganPemasokBumdes: string
{
case BEBAS = 'bebas';
case LANGGANAN = 'langganan';
case PINJAMAN = 'pinjaman';
case KONSINYASI = 'konsinyasi';
case KOMITMEN_VOLUME = 'komitmen_volume';
case SEMI_KONTRAK = 'semi_kontrak';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::BEBAS => 'Bebas/tidak terikat: petani bebas menjual ke BUMDes atau pihak lain kapan saja, tanpa ikatan apa pun',
self::LANGGANAN => 'Langganan tetap: petani rutin menjual ke BUMDes tanpa perjanjian formal',
self::PINJAMAN => 'Berbasis hutang/pinjaman: petani menjual ke BUMDes karena memiliki pinjaman kepada BUMDes',
self::KONSINYASI => 'Titip jual (konsinyasi): petani dibayar setelah hasil panen terjual',
self::KOMITMEN_VOLUME => 'Ada komitmen volume: kesepakatan volume tertentu yang dipenuhi secara berkala',
self::SEMI_KONTRAK => 'Semi-kontrak: kesepakatan tertulis/lisan mengenai harga, volume, dan waktu penyerahan',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum InfrastrukturPascapanenBumdes: string
{
case GUDANG_PENYIMPANAN_HASIL_PANEN = 'gudang_penyimpanan_hasil_panen';
case ALAT_MESIN_PENGERING = 'alat_mesin_pengering';
case MESIN_PULPER_HULLER = 'mesin_pulper_huller';
case TIMBANGAN = 'timbangan';
case ALAT_SORTASI = 'alat_sortasi';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::GUDANG_PENYIMPANAN_HASIL_PANEN => 'Gudang penyimpanan hasil panen',
self::ALAT_MESIN_PENGERING => 'Alat/mesin pengering',
self::MESIN_PULPER_HULLER => 'Mesin pulper/huller',
self::TIMBANGAN => 'Timbangan',
self::ALAT_SORTASI => 'Alat sortasi',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum JabatanPengurusIntiBumdes: string
{
case PENASIHAT_KEPALA_DESA = 'penasihat_kepala_desa';
case KETUA_PENGAWAS = 'ketua_pengawas';
case DIREKTUR_KETUA_BUMDES = 'direktur_ketua_bumdes';
case SEKRETARIS = 'sekretaris';
case BENDAHARA = 'bendahara';
case KEPALA_UNIT_USAHA_KOMODITAS = 'kepala_unit_usaha_komoditas';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::PENASIHAT_KEPALA_DESA => 'Penasihat (Kepala Desa)',
self::KETUA_PENGAWAS => 'Ketua Pengawas',
self::DIREKTUR_KETUA_BUMDES => 'Direktur/Ketua BUMDes',
self::SEKRETARIS => 'Sekretaris',
self::BENDAHARA => 'Bendahara',
self::KEPALA_UNIT_USAHA_KOMODITAS => 'Kepala Unit Usaha Komoditas',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum KemitraanEksternalBumdes: string
{
case NGO = 'ngo';
case PEMERINTAH_KABUPATEN = 'pemerintah_kabupaten';
case SWASTA_OFFTAKER = 'swasta_offtaker';
case PROGRAM_PEMERINTAH_LAIN = 'program_pemerintah_lain';
case BELUM_ADA = 'belum_ada';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::NGO => 'NGO/lembaga pemberdayaan',
self::PEMERINTAH_KABUPATEN => 'Dinas/pemerintah kabupaten',
self::SWASTA_OFFTAKER => 'Perusahaan swasta/offtaker',
self::PROGRAM_PEMERINTAH_LAIN => 'Program pemerintah lain',
self::BELUM_ADA => 'Belum ada kemitraan eksternal',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum KeterlibatanKoordinasiBumdes: string
{
case SELALU = 'selalu';
case KADANG = 'kadang';
case TIDAK_PERNAH = 'tidak_pernah';
public function label(): string
{
return match ($this) {
self::SELALU => 'Selalu dilibatkan',
self::KADANG => 'Kadang dilibatkan',
self::TIDAK_PERNAH => 'Tidak pernah dilibatkan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Enums\Bumdes;
enum KondisiAsetProduktifBumdes: string
{
case BERFUNGSI = 'berfungsi';
case PERLU_PERBAIKAN = 'perlu_perbaikan_evaluasi';
case RUSAK = 'rusak_tidak_bisa_dipakai';
case MANGKRAK = 'mangkrak';
public function label(): string
{
return match ($this) {
self::BERFUNGSI => 'Berfungsi',
self::PERLU_PERBAIKAN => 'Perlu perbaikan/evaluasi',
self::RUSAK => 'Rusak/tidak bisa dipakai',
self::MANGKRAK => 'Mangkrak',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
public static function normalizeLegacy(mixed $value): ?string
{
if (! is_scalar($value) || trim((string) $value) === '') {
return null;
}
$value = trim((string) $value);
return match (mb_strtolower($value)) {
'baik', 'berfungsi', 'baik dan berfungsi', 'baik_berfungsi' => self::BERFUNGSI->value,
'rusak ringan', 'perlu perbaikan', 'perlu perbaikan/evaluasi' => self::PERLU_PERBAIKAN->value,
'rusak', 'rusak/tidak terpakai', 'rusak_tidak_terpakai', 'rusak/tidak bisa dipakai' => self::RUSAK->value,
'mangkrak' => self::MANGKRAK->value,
default => $value,
};
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Enums\Bumdes;
enum KondisiInfrastrukturBumdes: string
{
case BAIK_BERFUNGSI = 'baik_berfungsi';
case RUSAK_TIDAK_TERPAKAI = 'rusak_tidak_terpakai';
public function label(): string
{
return match ($this) {
self::BAIK_BERFUNGSI => 'Baik dan berfungsi',
self::RUSAK_TIDAK_TERPAKAI => 'Rusak/tidak terpakai',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum KondisiKeuanganBumdes: string
{
case UNTUNG_SURPLUS = 'untung_surplus';
case IMPAS = 'impas';
case RUGI_DEFISIT = 'rugi_defisit';
case TIDAK_MENJAWAB = 'tidak_menjawab';
public function label(): string
{
return match ($this) {
self::UNTUNG_SURPLUS => 'Untung/surplus',
self::IMPAS => 'Impas',
self::RUGI_DEFISIT => 'Rugi/defisit',
self::TIDAK_MENJAWAB => 'Tidak tahu/tidak mau menjawab',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum KontribusiPadesBumdes: string
{
case RUTIN = 'rutin';
case TIDAK_RUTIN = 'tidak_rutin';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::TIDAK_RUTIN => 'Ya, tapi tidak rutin',
self::BELUM_PERNAH => 'Belum pernah',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace App\Enums\Bumdes;
enum LayananPetaniBumdes: string
{
case SIMPAN_PINJAM = 'simpan_pinjam';
case PENGADAAN_INPUT = 'pengadaan_input';
case PEMASARAN_PANEN = 'pemasaran_panen';
case PENYEWAAN_ALAT = 'penyewaan_alat';
case JASA_PENGOLAHAN = 'jasa_pengolahan';
case PELATIHAN = 'pelatihan';
case BELUM_ADA = 'belum_ada';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::SIMPAN_PINJAM => 'Simpan pinjam',
self::PENGADAAN_INPUT => 'Pengadaan input (pupuk, bibit, dll)',
self::PEMASARAN_PANEN => 'Pembelian/pemasaran hasil panen',
self::PENYEWAAN_ALAT => 'Penyewaan alat pengolahan',
self::JASA_PENGOLAHAN => 'Jasa pengolahan/fermentasi',
self::PELATIHAN => 'Pelatihan/pendampingan',
self::BELUM_ADA => 'Belum ada layanan terkait komoditas ini',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Enums\Bumdes;
enum MekanismePembayaranBumdes: string
{
case TUNAI = 'tunai';
case TEMPO = 'tempo';
case CAMPURAN = 'campuran';
case IJON = 'ijon';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::TUNAI => 'Tunai langsung',
self::TEMPO => 'Sistem tempo/dibayar kemudian',
self::CAMPURAN => 'Campuran, tergantung situasi',
self::IJON => 'BUMDes membayar di muka sebelum panen, sebagai bagian dari ikatan pinjaman kepada petani (ijon)',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum ModelFermentasiBumdes: string
{
case INDIVIDUAL = 'individual';
case KOLEKTIF_KELOMPOK = 'kolektif_kelompok';
case UNIT_BUMDES = 'unit_bumdes';
case CAMPURAN = 'campuran';
public function label(): string
{
return match ($this) {
self::INDIVIDUAL => 'Individual (masing-masing petani)',
self::KOLEKTIF_KELOMPOK => 'Kolektif kelompok tani',
self::UNIT_BUMDES => 'Unit pengolah BUMDes/desa',
self::CAMPURAN => 'Campuran',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PencatatanPetaniBumdes: string
{
case RAPI = 'rapi';
case TIDAK_RAPI = 'tidak_rapi';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::RAPI => 'Ada, tercatat rapi',
self::TIDAK_RAPI => 'Ada tapi tidak rapi',
self::TIDAK_ADA => 'Tidak ada pencatatan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum PenetapanHargaBeliBumdes: string
{
case PASAR_SETEMPAT = 'pasar_setempat';
case KALKULASI_BIAYA = 'kalkulasi_biaya';
case HARGA_MITRA = 'harga_mitra';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::PASAR_SETEMPAT => 'Mengikuti harga pasar/tengkulak setempat',
self::KALKULASI_BIAYA => 'Ditetapkan sendiri berdasarkan kalkulasi biaya',
self::HARGA_MITRA => 'Mengikuti harga dari offtaker/mitra',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PengalamanOfftakerBumdes: string
{
case BERJALAN = 'berjalan';
case BERHENTI = 'berhenti';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::BERJALAN => 'Sedang berjalan',
self::BERHENTI => 'Pernah, tapi sudah berhenti',
self::BELUM_PERNAH => 'Belum pernah',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum PeranRantaiNilaiBumdes: string
{
case MEMBELI_LANGSUNG = 'membeli_langsung';
case PERANTARA = 'perantara';
case MENGOLAH_SENDIRI = 'mengolah_sendiri';
case BELUM_BERPERAN = 'belum_berperan';
public function label(): string
{
return match ($this) {
self::MEMBELI_LANGSUNG => 'Membeli langsung dari petani',
self::PERANTARA => 'Menjadi perantara/mengumpulkan untuk dijual ke pihak lain',
self::MENGOLAH_SENDIRI => 'Mengolah sendiri (sortasi/fermentasi/dll) sebelum dijual',
self::BELUM_BERPERAN => 'Belum berperan dalam rantai nilai komoditas ini',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PeriodePanenBumdes: string
{
case TERAKHIR = 'panen_terakhir';
case TAHUN_LALU = 'tahun_lalu';
case DUA_TAHUN_LALU = 'dua_tahun_lalu';
public function label(): string
{
return match ($this) {
self::TERAKHIR => 'Panen Terakhir',
self::TAHUN_LALU => 'Tahun Lalu',
self::DUA_TAHUN_LALU => 'Dua Tahun Lalu',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PerjanjianPetaniBumdes: string
{
case TERTULIS = 'tertulis';
case LISAN = 'lisan';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::TERTULIS => 'Ada, tertulis',
self::LISAN => 'Ada, kesepakatan lisan saja',
self::TIDAK_ADA => 'Tidak ada perjanjian',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PertanggungjawabanMusdesBumdes: string
{
case TAHUNAN = 'tahunan';
case TIDAK_RUTIN = 'tidak_rutin';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::TAHUNAN => 'Ya, setiap tahun',
self::TIDAK_RUTIN => 'Tidak rutin',
self::BELUM_PERNAH => 'Belum pernah',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum SaluranPenjualanBumdes: string
{
case OFFTAKER_EKSPORTIR = 'offtaker_eksportir';
case PEDAGANG_KABUPATEN = 'pedagang_kabupaten';
case KOPERASI_BUMDES = 'koperasi_bumdes';
case PASAR_LOKAL = 'pasar_lokal';
case BELUM_MENJUAL = 'belum_menjual';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::OFFTAKER_EKSPORTIR => 'Offtaker/eksportir langsung',
self::PEDAGANG_KABUPATEN => 'Pedagang besar/pengepul kabupaten',
self::KOPERASI_BUMDES => 'Koperasi atau BUMDes lain',
self::PASAR_LOKAL => 'Dijual eceran/pasar lokal',
self::BELUM_MENJUAL => 'Belum pernah menjual (masih disimpan/diproses)',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Enums\Bumdes;
enum SifatAuditBumdes: string
{
case INTERNAL = 'internal';
case EKSTERNAL = 'eksternal';
public function label(): string
{
return match ($this) {
self::INTERNAL => 'Internal (pengurus/pengawas BUMDes sendiri)',
self::EKSTERNAL => 'Eksternal (Inspektorat, Dinas PMD, akuntan publik/auditor independen)',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusAdArtBumdes: string
{
case ADA_LENGKAP = 'ada_lengkap';
case ADA_TIDAK_LENGKAP = 'ada_tidak_lengkap';
case TIDAK_ADA = 'tidak_ada';
case TIDAK_TAHU = 'tidak_tahu';
public function label(): string
{
return match ($this) {
self::ADA_LENGKAP => 'Ada, lengkap',
self::ADA_TIDAK_LENGKAP => 'Ada tapi tidak lengkap',
self::TIDAK_ADA => 'Tidak ada',
self::TIDAK_TAHU => 'Tidak tahu',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusBadanHukumBumdes: string
{
case SUDAH_BERBADAN_HUKUM = 'sudah_berbadan_hukum';
case PROSES_PENDAFTARAN = 'proses_pendaftaran';
case BELUM_BERBADAN_HUKUM = 'belum_berbadan_hukum';
case TIDAK_TAHU = 'tidak_tahu';
public function label(): string
{
return match ($this) {
self::SUDAH_BERBADAN_HUKUM => 'Sudah berbadan hukum (terdaftar Kemenkumham)',
self::PROSES_PENDAFTARAN => 'Proses pendaftaran',
self::BELUM_BERBADAN_HUKUM => 'Belum berbadan hukum',
self::TIDAK_TAHU => 'Tidak tahu',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusFermentasiBumdes: string
{
case RUTIN = 'rutin';
case PERNAH_MENCOBA = 'pernah_mencoba';
case DIRENCANAKAN = 'direncanakan';
case TIDAK_DIRENCANAKAN = 'tidak_direncanakan';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::PERNAH_MENCOBA => 'Pernah mencoba',
self::DIRENCANAKAN => 'Belum pernah, direncanakan',
self::TIDAK_DIRENCANAKAN => 'Belum pernah, tidak direncanakan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusKeaktifanBumdes: string
{
case AKTIF_PENUH = 'aktif_penuh';
case AKTIF_TERBATAS = 'aktif_terbatas';
case TIDAK_AKTIF_VAKUM = 'tidak_aktif_vakum';
case BERDIRI_BELUM_BEROPERASI = 'berdiri_belum_beroperasi';
public function label(): string
{
return match ($this) {
self::AKTIF_PENUH => 'Aktif beroperasi penuh',
self::AKTIF_TERBATAS => 'Aktif tapi terbatas (sebagian unit usaha berjalan)',
self::TIDAK_AKTIF_VAKUM => 'Tidak aktif/vakum',
self::BERDIRI_BELUM_BEROPERASI => 'Sudah berdiri tapi belum pernah beroperasi',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusKepemilikanAsetBumdes: string
{
case MILIK_BUMDES_SENDIRI = 'milik_bumdes_sendiri';
case MILIK_DESA_DIPINJAMKAN_DIKELOLA = 'milik_desa_dipinjamkan_dikelola';
case SEWA_PINJAM_PIHAK_LAIN = 'sewa_pinjam_pihak_lain';
public function label(): string
{
return match ($this) {
self::MILIK_BUMDES_SENDIRI => 'Milik BUMDes sendiri',
self::MILIK_DESA_DIPINJAMKAN_DIKELOLA => 'Milik desa (dipinjamkan/dikelola)',
self::SEWA_PINJAM_PIHAK_LAIN => 'Sewa/pinjam pihak lain',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusPembukuanBumdes: string
{
case RUTIN_TERTIB = 'rutin_tertib';
case TIDAK_RUTIN = 'tidak_rutin';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::RUTIN_TERTIB => 'Ya, rutin dan tertib',
self::TIDAK_RUTIN => 'Ada tapi tidak rutin/tidak rapi',
self::TIDAK_ADA => 'Tidak ada pembukuan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusPengeringanBumdes: string
{
case RUTIN = 'rutin';
case KADANG = 'kadang';
case TIDAK_PERNAH = 'tidak_pernah';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::KADANG => 'Kadang-kadang',
self::TIDAK_PERNAH => 'Tidak pernah, produk dijual dalam kondisi diterima',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusSortasiBumdes: string
{
case RUTIN_STANDAR = 'rutin_standar';
case TIDAK_KONSISTEN = 'tidak_konsisten';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::RUTIN_STANDAR => 'Ya, rutin dengan standar tertentu',
self::TIDAK_KONSISTEN => 'Ya, tapi tidak konsisten',
self::BELUM_PERNAH => 'Belum pernah dilakukan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusUnitKomoditasBumdes: string
{
case YA = 'ya';
case DITANGANI_PENGURUS_INTI = 'ditangani_pengurus_inti';
case DIRENCANAKAN = 'direncanakan';
public function label(): string
{
return match ($this) {
self::YA => 'Ya, ada unit khusus',
self::DITANGANI_PENGURUS_INTI => 'Tidak ada unit khusus, ditangani langsung pengurus inti',
self::DIRENCANAKAN => 'Belum ada, masih direncanakan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace App\Enums\Bumdes;
enum SumberPasokanBumdes: string
{
case ANGGOTA_KELOMPOK = 'anggota_kelompok';
case PETANI_NON_ANGGOTA = 'petani_non_anggota';
case PENGUMPUL_DESA = 'pengumpul_desa';
case CAMPURAN = 'campuran';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::ANGGOTA_KELOMPOK => 'Anggota kelompok tani langsung',
self::PETANI_NON_ANGGOTA => 'Petani non-anggota',
self::PENGUMPUL_DESA => 'Pengumpul/sub-agen desa',
self::CAMPURAN => 'Campuran',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum UnitUsahaBumdes: string
{
case SIMPAN_PINJAM = 'simpan_pinjam';
case PERDAGANGAN_TOKO_DESA = 'perdagangan_toko_desa';
case PENGELOLAAN_AIR_BERSIH = 'pengelolaan_air_bersih';
case WISATA_DESA_AGROWISATA = 'wisata_desa_agrowisata';
case PENGELOLAAN_HASIL_PERTANIAN_KOMODITAS = 'pengelolaan_hasil_pertanian_komoditas';
case PENYEWAAN_ALAT_ASET = 'penyewaan_alat_aset';
case JASA_LAINNYA = 'jasa_lainnya';
public function label(): string
{
return match ($this) {
self::SIMPAN_PINJAM => 'Simpan pinjam',
self::PERDAGANGAN_TOKO_DESA => 'Perdagangan/toko desa',
self::PENGELOLAAN_AIR_BERSIH => 'Pengelolaan air bersih',
self::WISATA_DESA_AGROWISATA => 'Wisata desa/agrowisata',
self::PENGELOLAAN_HASIL_PERTANIAN_KOMODITAS => 'Pengelolaan hasil pertanian/komoditas',
self::PENYEWAAN_ALAT_ASET => 'Penyewaan alat/aset',
self::JASA_LAINNYA => 'Jasa lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Web\Bumdes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bumdes\BumdesRequest;
use App\Http\Requests\Bumdes\StoreKelembagaanAktorBumdesRequest;
use App\Models\Bumdes\PengurusBumdes;
use App\Services\Bumdes\PengurusBumdesService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class KelembagaanAktorBumdesController extends Controller
{
public function __construct(private readonly PengurusBumdesService $service) {}
public function index(BumdesRequest $request, PengurusBumdes $pengurusBumdes): View
{
return view('bumdes.kelembagaan-aktor.index', $this->service->sectionData($pengurusBumdes));
}
public function store(StoreKelembagaanAktorBumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
$this->service->saveSection($pengurusBumdes, $request->validated(), 'kelembagaan');
return redirect()->route('bumdes.kelembagaan-aktor.index', $pengurusBumdes)
->with('success', 'Data Kelembagaan berhasil disimpan.');
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Web\Bumdes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bumdes\BumdesRequest;
use App\Http\Requests\Bumdes\StoreOperasionalBumdesRequest;
use App\Models\Bumdes\PengurusBumdes;
use App\Services\Bumdes\PengurusBumdesService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class OperasionalBumdesController extends Controller
{
public function __construct(private readonly PengurusBumdesService $service) {}
public function index(BumdesRequest $request, PengurusBumdes $pengurusBumdes): View
{
return view('bumdes.operasional.index', $this->service->sectionData($pengurusBumdes));
}
public function store(StoreOperasionalBumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
$this->service->saveSection($pengurusBumdes, $request->validated(), 'operasional');
return redirect()->route('bumdes.operasional.index', $pengurusBumdes)
->with('success', 'Data Operasional berhasil disimpan.');
}
}
@@ -2,579 +2,66 @@
namespace App\Http\Controllers\Web\Bumdes;
use App\Enums\Bumdes\JabatanBumdes;
use App\Enums\Pendidikan;
use App\Http\Controllers\Controller;
use App\Models\Bumdes\KelembagaanAktorBumdes;
use App\Http\Requests\Bumdes\BumdesRequest;
use App\Http\Requests\Bumdes\IndexPengurusBumdesRequest;
use App\Http\Requests\Bumdes\StorePengurusBumdesRequest;
use App\Http\Requests\Bumdes\UpdatePengurusBumdesRequest;
use App\Models\Bumdes\PengurusBumdes;
use App\Models\Wilayah\Provinsi;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use App\Services\Bumdes\PengurusBumdesService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class PengurusBumdesController extends Controller
{
public function index(Request $request)
public function __construct(private readonly PengurusBumdesService $service) {}
public function index(IndexPengurusBumdesRequest $request): View
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$query = PengurusBumdes::with([
...$this->wilayahRelationsWithoutProgramScope(),
'creator:id,name',
])
->orderBy('created_at', 'desc');
if ($request->search) {
$query->where(function ($query) use ($request) {
$query->where('nama', 'like', '%' . $request->search . '%')
->orWhere('jabatan', 'like', '%' . $request->search . '%')
->orWhere('jabatan_lainnya', 'like', '%' . $request->search . '%');
});
}
if (auth()->user()->role->value === 'enumerator') {
$query->where('created_by', auth()->id());
}
$summaryQuery = clone $query;
$totalPengurus = (clone $summaryQuery)->count();
$totalLakiLaki = (clone $summaryQuery)->where('jenis_kelamin', true)->count();
$totalPerempuan = (clone $summaryQuery)->where('jenis_kelamin', false)->count();
$totalDesaKelurahan = (clone $summaryQuery)->distinct('desa_kelurahan_id')->count('desa_kelurahan_id');
$totalJabatan = (clone $summaryQuery)->distinct('jabatan')->count('jabatan');
$pengurus = $query->paginate($request->per_page ?? 10);
$userRole = auth()->user()->role->value;
$showEnumerator = in_array($userRole, ['super_admin', 'admin']);
return view('bumdes.profil.index', compact(
'pengurus',
'totalPengurus',
'totalLakiLaki',
'totalPerempuan',
'totalDesaKelurahan',
'totalJabatan',
'showEnumerator'
));
return view('bumdes.profil.index', $this->service->indexData($request->validated()));
}
public function create()
public function create(BumdesRequest $request): View
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$provinsi = $this->provinsiOptions();
$jabatan = JabatanBumdes::options();
$pendidikan = Pendidikan::options();
return view('bumdes.profil.add', compact('provinsi', 'jabatan', 'pendidikan'));
return view('bumdes.profil.create', $this->service->profileData());
}
public function store(Request $request)
public function store(StorePengurusBumdesRequest $request): RedirectResponse
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$pengurus = $this->service->storeProfile($request->validated());
$validatedData = $this->validatedData($request);
$pengurus = PengurusBumdes::create([
...$this->formatData($validatedData),
'uid' => 'BMD-' . strtoupper(Str::random(10)),
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
]);
return redirect()->route('bumdes.edit', $pengurus->id)->with('success', 'Data pengurus BUMDes berhasil ditambahkan.');
return $this->profileSavedResponse($request, $pengurus);
}
public function show(string $id)
public function show(BumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
return redirect()->route('bumdes.edit', $id);
return redirect()->route('bumdes.edit', $pengurusBumdes);
}
public function edit(string $id)
public function edit(BumdesRequest $request, PengurusBumdes $pengurusBumdes): View
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$pengurus = $this->pengurusQuery()
->with($this->wilayahRelationsWithoutProgramScope())
->findOrFail($id);
$provinsi = $this->provinsiOptions();
$jabatan = JabatanBumdes::options();
$pendidikan = Pendidikan::options();
return view('bumdes.profil.edit', compact('pengurus', 'provinsi', 'jabatan', 'pendidikan'));
return view('bumdes.profil.edit', $this->service->profileData($pengurusBumdes));
}
public function update(Request $request, string $id)
public function update(UpdatePengurusBumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$this->service->updateProfile($pengurusBumdes, $request->validated());
$pengurus = $this->pengurusQuery()->findOrFail($id);
$validatedData = $this->validatedData($request);
$pengurus->update([
...$this->formatData($validatedData),
'updated_by' => auth()->id(),
]);
return redirect()->route('bumdes.edit', $pengurus->id)->with('success', 'Data pengurus BUMDes berhasil diupdate.');
return $this->profileSavedResponse($request, $pengurusBumdes);
}
public function destroy(string $id)
public function destroy(BumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
DB::transaction(fn () => $pengurusBumdes->delete());
$pengurus = $this->pengurusQuery()->findOrFail($id);
$pengurus->update(['deleted_by' => auth()->id()]);
$pengurus->delete();
return response()->json(['message' => 'Data pengurus BUMDes berhasil dihapus.']);
return redirect()->route('bumdes.index')->with('success', 'Data profil berhasil dihapus.');
}
public function kelembagaanAktor(string $id)
private function profileSavedResponse(BumdesRequest $request, PengurusBumdes $pengurus): RedirectResponse
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$fragment = $request->input('redirect_fragment') === 'section-kepengurusan' ? '#section-kepengurusan' : '';
$pengurus = $this->pengurusQuery()
->with([
...$this->wilayahRelationsWithoutProgramScope(),
'kelembagaanAktor',
])
->findOrFail($id);
$kelembagaanAktor = $pengurus->kelembagaanAktor;
return view('bumdes.kelembagaan-aktor.index', array_merge(
compact('pengurus', 'kelembagaanAktor'),
$this->kelembagaanAktorOptions()
));
}
public function storeKelembagaanAktor(Request $request, string $id)
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
$pengurus = $this->pengurusQuery()->findOrFail($id);
$validatedData = $this->validatedKelembagaanAktorData($request);
KelembagaanAktorBumdes::updateOrCreate(
['pengurus_bumdes_id' => $pengurus->id],
[
...$this->formatKelembagaanAktorData($validatedData),
'created_by' => $pengurus->kelembagaanAktor?->created_by ?? auth()->id(),
'updated_by' => auth()->id(),
]
);
return redirect()
->route('bumdes.kelembagaan-aktor.index', $pengurus->id)
->with('success', 'Data kelembagaan dan aktor BUMDes berhasil disimpan.');
}
private function pengurusQuery()
{
$query = PengurusBumdes::query();
if (auth()->user()->role->value === 'enumerator') {
$query->where('created_by', auth()->id());
}
return $query;
}
private function provinsiOptions()
{
return Provinsi::withoutGlobalScope('program')
->select('id', 'kode', 'nama')
->orderBy('kode', 'asc')
->get();
}
private function wilayahRelationsWithoutProgramScope(): array
{
return [
'desaKelurahan' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama', 'kecamatan_id'),
'desaKelurahan.kecamatan' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama', 'kabupaten_kota_id'),
'desaKelurahan.kecamatan.kabupatenKota' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama', 'provinsi_id'),
'desaKelurahan.kecamatan.kabupatenKota.provinsi' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama'),
];
}
private function validatedData(Request $request): array
{
return $request->validate([
'nama' => ['required', 'string', 'max:255'],
'jenis_kelamin' => ['required', 'boolean'],
'tempat_lahir' => ['required', 'string', 'max:255'],
'tanggal_lahir' => ['required', 'date_format:d-m-Y'],
'pendidikan_terakhir' => ['required', Rule::enum(Pendidikan::class)],
'alamat' => ['required', 'string', 'max:500'],
'desa_kelurahan_id' => ['required', 'exists:master_desa_kelurahan,id'],
'nomor_telepon' => ['nullable', 'digits_between:11,13'],
'jabatan' => ['required', Rule::enum(JabatanBumdes::class)],
'jabatan_lainnya' => ['nullable', 'required_if:jabatan,' . JabatanBumdes::LAINNYA->value, 'string', 'max:255'],
'lama_menjabat_tahun' => ['required', 'integer', 'min:0', 'max:80'],
], [
'nama.required' => 'Nama harus diisi.',
'jenis_kelamin.required' => 'Jenis kelamin harus dipilih.',
'tempat_lahir.required' => 'Tempat lahir harus diisi.',
'tanggal_lahir.required' => 'Tanggal lahir harus diisi.',
'tanggal_lahir.date_format' => 'Tanggal lahir harus menggunakan format tanggal yang valid.',
'pendidikan_terakhir.required' => 'Pendidikan terakhir harus dipilih.',
'alamat.required' => 'Alamat harus diisi.',
'desa_kelurahan_id.required' => 'Desa kelurahan harus dipilih.',
'desa_kelurahan_id.exists' => 'Desa kelurahan tidak ditemukan.',
'nomor_telepon.digits_between' => 'Nomor telepon harus berupa angka 11 sampai 13 digit.',
'jabatan.required' => 'Jabatan/peran harus dipilih.',
'jabatan_lainnya.required_if' => 'Jabatan lainnya harus diisi.',
'lama_menjabat_tahun.required' => 'Lama menjabat harus diisi.',
'lama_menjabat_tahun.integer' => 'Lama menjabat harus berupa angka tahun.',
]);
}
private function formatData(array $data): array
{
$data['tanggal_lahir'] = Carbon::createFromFormat('d-m-Y', $data['tanggal_lahir'])->format('Y-m-d');
$data['tanggal_mulai_menjabat'] = Carbon::now()
->subYears((int) $data['lama_menjabat_tahun'])
->format('Y-m-d');
if (($data['jabatan'] ?? null) !== JabatanBumdes::LAINNYA->value) {
$data['jabatan_lainnya'] = null;
}
return $data;
}
private function validatedKelembagaanAktorData(Request $request): array
{
$this->normalizeKelembagaanAktorInput($request);
$maxYear = now()->year + 1;
return $request->validate([
'status_badan_hukum' => ['nullable', Rule::in(array_keys($this->statusBadanHukumOptions()))],
'nomor_dasar_hukum' => ['nullable', 'string', 'max:255'],
'tahun_dasar_hukum' => ['nullable', 'integer', 'digits:4', 'min:1900', 'max:' . $maxYear],
'status_keaktifan' => ['nullable', Rule::in(array_keys($this->statusKeaktifanOptions()))],
'alasan_tidak_aktif' => ['nullable', 'string'],
'unit_usaha' => ['nullable', 'array'],
'unit_usaha.*' => ['string', Rule::in(array_keys($this->unitUsahaOptions()))],
'unit_usaha_jasa_lainnya' => ['nullable', 'string', 'max:255'],
'status_unit_komoditas' => ['nullable', Rule::in(array_keys($this->statusUnitKomoditasOptions()))],
'nama_unit_komoditas' => ['nullable', 'string', 'max:255'],
'status_ad_art' => ['nullable', Rule::in(array_keys($this->statusAdArtOptions()))],
'tahun_ad_art' => ['nullable', 'integer', 'digits:4', 'min:1900', 'max:' . $maxYear],
'pengurus_inti' => ['nullable', 'array'],
'pengurus_inti.*.jabatan' => ['nullable', 'string', 'max:255'],
'pengurus_inti.*.nama' => ['nullable', 'string', 'max:255'],
'pengurus_inti.*.aktif' => ['nullable', 'boolean'],
'memiliki_staf' => ['nullable', 'boolean'],
'jumlah_staf' => ['nullable', 'integer', 'min:0'],
'unit_usaha_staf' => ['nullable', 'string'],
'modal_awal' => ['nullable', 'integer', 'min:0'],
'tahun_modal_awal' => ['nullable', 'integer', 'digits:4', 'min:1900', 'max:' . $maxYear],
'pernah_penambahan_modal' => ['nullable', 'boolean'],
'penambahan_modal' => ['nullable', 'array'],
'penambahan_modal.*.tahun' => ['nullable', 'integer', 'digits:4', 'min:1900', 'max:' . $maxYear],
'penambahan_modal.*.jumlah' => ['nullable', 'integer', 'min:0'],
'aset_produktif' => ['nullable', 'array'],
'aset_produktif.*.aset' => ['nullable', 'string', 'max:255'],
'aset_produktif.*.dipilih' => ['nullable', 'boolean'],
'aset_produktif.*.jumlah' => ['nullable', 'string', 'max:255'],
'aset_produktif.*.kondisi' => ['nullable', 'string', 'max:255'],
'aset_produktif_lainnya' => ['nullable', 'string', 'max:255'],
'status_kepemilikan_aset' => ['nullable', Rule::in(array_keys($this->statusKepemilikanAsetOptions()))],
'infrastruktur_pascapanen' => ['nullable', 'array'],
'infrastruktur_pascapanen.*.infrastruktur' => ['nullable', 'string', 'max:255'],
'infrastruktur_pascapanen.*.dipilih' => ['nullable', 'boolean'],
'infrastruktur_pascapanen.*.jumlah' => ['nullable', 'string', 'max:255'],
'infrastruktur_pascapanen.*.kondisi' => ['nullable', Rule::in(array_keys($this->kondisiInfrastrukturOptions()))],
'infrastruktur_pascapanen_lainnya' => ['nullable', 'string', 'max:255'],
], $this->kelembagaanAktorValidationMessages(), $this->kelembagaanAktorValidationAttributes());
}
private function normalizeKelembagaanAktorInput(Request $request): void
{
foreach (['modal_awal'] as $field) {
if ($request->has($field)) {
$request->merge([$field => preg_replace('/\D/', '', (string) $request->input($field))]);
}
}
$penambahanModal = collect($request->input('penambahan_modal', []))
->map(function ($row) {
if (isset($row['jumlah'])) {
$row['jumlah'] = preg_replace('/\D/', '', (string) $row['jumlah']);
}
return $row;
})
->all();
if ($request->has('penambahan_modal')) {
$request->merge(['penambahan_modal' => $penambahanModal]);
}
}
private function formatKelembagaanAktorData(array $data): array
{
$payload = array_merge([
'status_badan_hukum' => null,
'nomor_dasar_hukum' => null,
'tahun_dasar_hukum' => null,
'status_keaktifan' => null,
'alasan_tidak_aktif' => null,
'unit_usaha' => [],
'unit_usaha_jasa_lainnya' => null,
'status_unit_komoditas' => null,
'nama_unit_komoditas' => null,
'status_ad_art' => null,
'tahun_ad_art' => null,
'pengurus_inti' => [],
'memiliki_staf' => null,
'jumlah_staf' => null,
'unit_usaha_staf' => null,
'modal_awal' => null,
'tahun_modal_awal' => null,
'pernah_penambahan_modal' => null,
'penambahan_modal' => [],
'aset_produktif' => [],
'aset_produktif_lainnya' => null,
'status_kepemilikan_aset' => null,
'infrastruktur_pascapanen' => [],
'infrastruktur_pascapanen_lainnya' => null,
], $data);
$payload['unit_usaha'] = array_values($payload['unit_usaha'] ?? []);
$payload['pengurus_inti'] = $this->filterRows($payload['pengurus_inti'] ?? [], ['nama', 'aktif']);
$payload['penambahan_modal'] = $this->filterRows($payload['penambahan_modal'] ?? [], ['tahun', 'jumlah']);
$payload['aset_produktif'] = $this->filterRows($payload['aset_produktif'] ?? [], ['dipilih', 'jumlah', 'kondisi']);
$payload['infrastruktur_pascapanen'] = $this->filterRows($payload['infrastruktur_pascapanen'] ?? [], ['dipilih', 'jumlah', 'kondisi']);
if (($payload['status_keaktifan'] ?? null) !== 'tidak_aktif_vakum') {
$payload['alasan_tidak_aktif'] = null;
}
if (! in_array('jasa_lainnya', $payload['unit_usaha'], true)) {
$payload['unit_usaha_jasa_lainnya'] = null;
}
if (($payload['status_unit_komoditas'] ?? null) !== 'ya') {
$payload['nama_unit_komoditas'] = null;
}
if (($payload['status_ad_art'] ?? null) !== 'ada_lengkap') {
$payload['tahun_ad_art'] = null;
}
if (! (bool) ($payload['memiliki_staf'] ?? false)) {
$payload['jumlah_staf'] = null;
$payload['unit_usaha_staf'] = null;
}
if (! (bool) ($payload['pernah_penambahan_modal'] ?? false)) {
$payload['penambahan_modal'] = null;
}
if (! collect($payload['aset_produktif'] ?? [])->contains(fn ($row) => ($row['aset'] ?? null) === 'lainnya')) {
$payload['aset_produktif_lainnya'] = null;
}
if (! collect($payload['infrastruktur_pascapanen'] ?? [])->contains(fn ($row) => ($row['infrastruktur'] ?? null) === 'lainnya')) {
$payload['infrastruktur_pascapanen_lainnya'] = null;
}
return $payload;
}
private function filterRows(array $rows, array $valueKeys): array
{
return collect($rows)
->map(function ($row) {
return collect($row)
->map(fn ($value) => $value === '' ? null : $value)
->all();
})
->filter(function ($row) use ($valueKeys) {
foreach ($valueKeys as $key) {
if (filled($row[$key] ?? null)) {
return true;
}
}
return false;
})
->values()
->all();
}
private function kelembagaanAktorOptions(): array
{
return [
'statusBadanHukumOptions' => $this->statusBadanHukumOptions(),
'statusKeaktifanOptions' => $this->statusKeaktifanOptions(),
'unitUsahaOptions' => $this->unitUsahaOptions(),
'statusUnitKomoditasOptions' => $this->statusUnitKomoditasOptions(),
'statusAdArtOptions' => $this->statusAdArtOptions(),
'pengurusIntiRows' => $this->pengurusIntiRows(),
'asetProduktifRows' => $this->asetProduktifRows(),
'statusKepemilikanAsetOptions' => $this->statusKepemilikanAsetOptions(),
'infrastrukturPascapanenRows' => $this->infrastrukturPascapanenRows(),
'kondisiInfrastrukturOptions' => $this->kondisiInfrastrukturOptions(),
];
}
private function statusBadanHukumOptions(): array
{
return [
'sudah_berbadan_hukum' => 'Sudah berbadan hukum (terdaftar Kemenkumham)',
'proses_pendaftaran' => 'Proses pendaftaran',
'belum_berbadan_hukum' => 'Belum berbadan hukum',
'tidak_tahu' => 'Tidak tahu',
];
}
private function statusKeaktifanOptions(): array
{
return [
'aktif_penuh' => 'Aktif beroperasi penuh',
'aktif_terbatas' => 'Aktif tapi terbatas (sebagian unit usaha berjalan)',
'tidak_aktif_vakum' => 'Tidak aktif/vakum',
'berdiri_belum_beroperasi' => 'Sudah berdiri tapi belum pernah beroperasi',
];
}
private function unitUsahaOptions(): array
{
return [
'simpan_pinjam' => 'Simpan pinjam',
'perdagangan_toko_desa' => 'Perdagangan/toko desa',
'pengelolaan_air_bersih' => 'Pengelolaan air bersih',
'wisata_desa_agrowisata' => 'Wisata desa/agrowisata',
'pengelolaan_hasil_pertanian_komoditas' => 'Pengelolaan hasil pertanian/komoditas',
'penyewaan_alat_aset' => 'Penyewaan alat/aset',
'jasa_lainnya' => 'Jasa lainnya',
];
}
private function statusUnitKomoditasOptions(): array
{
return [
'ya' => 'Ya, ada unit khusus',
'ditangani_pengurus_inti' => 'Tidak ada unit khusus, ditangani langsung pengurus inti',
'direncanakan' => 'Belum ada, masih direncanakan',
];
}
private function statusAdArtOptions(): array
{
return [
'ada_lengkap' => 'Ada, lengkap',
'ada_tidak_lengkap' => 'Ada tapi tidak lengkap',
'tidak_ada' => 'Tidak ada',
'tidak_tahu' => 'Tidak tahu',
];
}
private function pengurusIntiRows(): array
{
return [
'penasihat_kepala_desa' => 'Penasihat (Kepala Desa)',
'ketua_pengawas' => 'Ketua Pengawas',
'direktur_ketua_bumdes' => 'Direktur/Ketua BUMDes',
'sekretaris' => 'Sekretaris',
'bendahara' => 'Bendahara',
'kepala_unit_usaha_komoditas' => 'Kepala Unit Usaha Komoditas',
'lainnya' => 'Lainnya',
];
}
private function asetProduktifRows(): array
{
return [
'bangunan_kantor' => 'Bangunan / kantor',
'gudang_penyimpanan' => 'Gudang penyimpanan',
'kendaraan_operasional_angkut' => 'Kendaraan operasional/angkut',
'lahan_usaha' => 'Lahan usaha',
'alat_pengolahan_komoditas' => 'Alat pengolahan komoditas',
'lainnya' => 'Lainnya',
];
}
private function statusKepemilikanAsetOptions(): array
{
return [
'milik_bumdes_sendiri' => 'Milik BUMDes sendiri',
'milik_desa_dipinjamkan_dikelola' => 'Milik desa (dipinjamkan/dikelola)',
'sewa_pinjam_pihak_lain' => 'Sewa/pinjam pihak lain',
];
}
private function infrastrukturPascapanenRows(): array
{
return [
'gudang_penyimpanan_hasil_panen' => 'Gudang penyimpanan hasil panen',
'alat_mesin_pengering' => 'Alat/mesin pengering',
'mesin_pulper_huller' => 'Mesin pulper/huller',
'timbangan' => 'Timbangan',
'alat_sortasi' => 'Alat sortasi',
'lainnya' => 'Lainnya',
];
}
private function kondisiInfrastrukturOptions(): array
{
return [
'baik_berfungsi' => 'Baik dan berfungsi',
'rusak_tidak_terpakai' => 'Rusak/tidak terpakai',
];
}
private function kelembagaanAktorValidationMessages(): array
{
return [
'integer' => ':attribute harus berupa angka.',
'digits' => ':attribute harus terdiri dari :digits digit.',
'min' => ':attribute tidak boleh kurang dari :min.',
'max' => ':attribute tidak valid.',
'in' => ':attribute tidak valid.',
'array' => ':attribute harus berupa daftar data.',
'boolean' => ':attribute harus dipilih.',
];
}
private function kelembagaanAktorValidationAttributes(): array
{
return [
'status_badan_hukum' => 'Status badan hukum',
'nomor_dasar_hukum' => 'Nomor dasar hukum',
'tahun_dasar_hukum' => 'Tahun dasar hukum',
'status_keaktifan' => 'Status keaktifan',
'unit_usaha' => 'Unit usaha',
'status_unit_komoditas' => 'Unit usaha komoditas',
'status_ad_art' => 'Dokumen AD/ART',
'memiliki_staf' => 'Status staf/karyawan',
'jumlah_staf' => 'Jumlah staf',
'modal_awal' => 'Modal awal',
'tahun_modal_awal' => 'Tahun modal awal',
'pernah_penambahan_modal' => 'Status penambahan modal',
'status_kepemilikan_aset' => 'Status kepemilikan aset',
];
return redirect(route('bumdes.edit', $pengurus).$fragment)->with('success', 'Data Profil berhasil disimpan.');
}
}
@@ -0,0 +1,34 @@
<?php
namespace App\Http\Controllers\Web\Bumdes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bumdes\BumdesRequest;
use App\Http\Requests\Bumdes\StoreRantaiNilaiBumdesRequest;
use App\Models\Bumdes\PengurusBumdes;
use App\Services\Bumdes\PengurusBumdesService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class RantaiNilaiBumdesController extends Controller
{
public function __construct(private readonly PengurusBumdesService $service) {}
public function index(BumdesRequest $request, PengurusBumdes $pengurusBumdes): View
{
return view('bumdes.rantai-nilai.index', $this->service->sectionData($pengurusBumdes));
}
public function store(StoreRantaiNilaiBumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
$this->service->saveSection($pengurusBumdes, $request->validated(), 'rantai-nilai');
$nextSection = $request->validated('redirect_fragment');
$postharvestSection = in_array($nextSection, ['section-rantai-pengeringan', 'section-rantai-fermentasi', 'section-rantai-premium-harga'], true);
$canContinue = $request->boolean($postharvestSection ? 'melakukan_pengolahan_pascapanen' : 'melakukan_jual_beli');
$nextSection = $canContinue ? $nextSection : null;
return redirect()->to(route('bumdes.rantai-nilai.index', $pengurusBumdes).($nextSection ? '#'.$nextSection : ''))
->with('success', 'Data Rantai Nilai & Akses Pasar berhasil disimpan.');
}
}
+174
View File
@@ -0,0 +1,174 @@
<?php
namespace App\Http\Requests\Bumdes;
use App\Enums\Bumdes\AsetProduktifBumdes;
use App\Enums\Bumdes\InfrastrukturPascapanenBumdes;
use App\Enums\Bumdes\JabatanPengurusIntiBumdes;
use App\Enums\Bumdes\KondisiInfrastrukturBumdes;
use App\Enums\Bumdes\StatusAdArtBumdes;
use App\Enums\Bumdes\StatusBadanHukumBumdes;
use App\Enums\Bumdes\StatusKeaktifanBumdes;
use App\Enums\Bumdes\StatusKepemilikanAsetBumdes;
use App\Enums\Bumdes\StatusUnitKomoditasBumdes;
use App\Enums\Bumdes\UnitUsahaBumdes;
use App\Enums\Role;
use App\Models\Bumdes\KelembagaanAktorBumdes;
use App\Models\Bumdes\PengurusBumdes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class BumdesRequest extends FormRequest
{
public function authorize(): bool
{
if (! Gate::any(['super_admin', 'admin', 'enumerator'])) {
return false;
}
$pengurus = $this->route('pengurusBumdes');
if ($pengurus instanceof PengurusBumdes && $this->user()->role === Role::ENUMERATOR) {
abort_unless((int) $pengurus->created_by === (int) $this->user()->id, 404);
}
if ($pengurus instanceof PengurusBumdes && $this->routeIs('bumdes.operasional.*', 'bumdes.kelembagaan-aktor.*', 'bumdes.rantai-nilai.*')) {
abort_unless($pengurus->profilLengkap(), 403);
}
return true;
}
public function rules(): array
{
return [];
}
protected function sectionRules(string $section): array
{
$maxYear = now()->year + 1;
$rules = [
'status_badan_hukum' => ['nullable', Rule::enum(StatusBadanHukumBumdes::class)],
'nomor_dasar_hukum' => [Rule::excludeIf($this->input('status_badan_hukum') !== 'sudah_berbadan_hukum'), 'required_if:status_badan_hukum,sudah_berbadan_hukum', 'string', 'max:255'],
'tahun_dasar_hukum' => [Rule::excludeIf($this->input('status_badan_hukum') !== 'sudah_berbadan_hukum'), 'required_if:status_badan_hukum,sudah_berbadan_hukum', 'integer', 'digits:4', 'min:1900', 'max:'.$maxYear],
'status_keaktifan' => ['nullable', Rule::enum(StatusKeaktifanBumdes::class)],
'alasan_tidak_aktif' => ['nullable', 'string'],
'unit_usaha' => ['nullable', 'array'],
'unit_usaha.*' => ['string', Rule::enum(UnitUsahaBumdes::class)],
'unit_usaha_jasa_lainnya' => ['nullable', 'string', 'max:255'],
'status_unit_komoditas' => ['nullable', Rule::enum(StatusUnitKomoditasBumdes::class)],
'nama_unit_komoditas' => [Rule::excludeIf($this->input('status_unit_komoditas') !== 'ya'), 'required_if:status_unit_komoditas,ya', 'string', 'max:255'],
'status_ad_art' => ['nullable', Rule::enum(StatusAdArtBumdes::class)],
'tahun_ad_art' => [Rule::excludeIf($this->input('status_ad_art') !== 'ada_lengkap'), 'required_if:status_ad_art,ada_lengkap', 'integer', 'digits:4', 'min:1900', 'max:'.$maxYear],
'pengurus_inti' => ['nullable', 'array'],
'pengurus_inti.*' => ['array'],
'pengurus_inti.*.jabatan' => ['nullable', Rule::enum(JabatanPengurusIntiBumdes::class)],
'pengurus_inti.*.nama' => ['nullable', 'string', 'max:255'],
'pengurus_inti.*.aktif' => ['nullable', 'boolean'],
'memiliki_staf' => ['nullable', 'boolean'],
'jumlah_staf' => ['nullable', 'integer', 'min:0'],
'unit_usaha_staf' => ['nullable', 'string'],
'modal_awal' => ['nullable', 'integer', 'min:0'],
'tahun_modal_awal' => ['nullable', 'integer', 'digits:4', 'min:1900', 'max:'.$maxYear],
'pernah_penambahan_modal' => ['nullable', 'boolean'],
'penambahan_modal' => [Rule::excludeIf(! $this->boolean('pernah_penambahan_modal')), 'nullable', 'array'],
'penambahan_modal.*' => [Rule::excludeIf(! $this->boolean('pernah_penambahan_modal')), 'array'],
'penambahan_modal.*.tahun' => [Rule::excludeIf(! $this->boolean('pernah_penambahan_modal')), 'nullable', 'integer', 'digits:4', 'min:1900', 'max:'.$maxYear],
'penambahan_modal.*.jumlah' => [Rule::excludeIf(! $this->boolean('pernah_penambahan_modal')), 'nullable', 'integer', 'min:0'],
'aset_produktif' => ['nullable', 'array'],
'aset_produktif.*' => ['array'],
'aset_produktif.*.aset' => ['nullable', Rule::enum(AsetProduktifBumdes::class)],
'aset_produktif.*.dipilih' => ['nullable', 'boolean'],
'aset_produktif.*.jumlah' => ['nullable', 'integer', 'min:0'],
'aset_produktif.*.kondisi' => ['nullable', 'string', 'max:255'],
'aset_produktif_lainnya' => ['nullable', 'string', 'max:255'],
'status_kepemilikan_aset' => ['nullable', Rule::enum(StatusKepemilikanAsetBumdes::class)],
'infrastruktur_pascapanen' => ['nullable', 'array'],
'infrastruktur_pascapanen.*' => ['array'],
'infrastruktur_pascapanen.*.infrastruktur' => ['nullable', Rule::enum(InfrastrukturPascapanenBumdes::class)],
'infrastruktur_pascapanen.*.dipilih' => ['nullable', 'boolean'],
'infrastruktur_pascapanen.*.jumlah' => ['nullable', 'integer', 'min:0'],
'infrastruktur_pascapanen.*.kondisi' => ['nullable', Rule::enum(KondisiInfrastrukturBumdes::class)],
'infrastruktur_pascapanen_lainnya' => ['nullable', 'string', 'max:255'],
];
$fields = KelembagaanAktorBumdes::sectionFields($section);
$rules = array_filter($rules, fn ($field) => in_array(Str::before($field, '.'), $fields, true), ARRAY_FILTER_USE_KEY);
return $rules;
}
public function messages(): array
{
return [
'nomor_dasar_hukum.required_if' => 'Nomor Peraturan Desa/SK wajib diisi.',
'tahun_dasar_hukum.required_if' => 'Tahun Ditetapkan wajib diisi.',
'nama_unit_komoditas.required_if' => 'Nama Unit Usaha Komoditas wajib diisi.',
'tahun_ad_art.required_if' => 'Tahun Terakhir Diperbarui wajib diisi.',
'string' => ':attribute harus berupa teks.',
'required' => ':attribute wajib diisi.',
'exists' => ':attribute tidak ditemukan.',
'integer' => ':attribute harus berupa angka.',
'digits' => ':attribute harus terdiri dari :digits digit.',
'min' => ':attribute tidak boleh kurang dari :min.',
'max' => ':attribute tidak valid.',
'enum' => 'Pilihan :attribute tidak valid.',
'in' => ':attribute tidak valid.',
'array' => ':attribute harus berupa daftar data.',
'boolean' => ':attribute harus dipilih.',
];
}
public function attributes(): array
{
return [
'search' => 'Pencarian',
'kabupaten_kota_id' => 'Kabupaten/Kota', 'kabupaten_id' => 'Kabupaten/Kota',
'provinsi_id' => 'Provinsi', 'kecamatan_id' => 'Kecamatan', 'desa_kelurahan_id' => 'Desa/Kelurahan',
'jenis_kelamin' => 'Jenis kelamin', 'per_page' => 'Jumlah data per halaman',
'nama' => 'Nama', 'tempat_lahir' => 'Tempat lahir', 'tanggal_lahir' => 'Tanggal lahir',
'pendidikan_terakhir' => 'Pendidikan terakhir', 'alamat' => 'Alamat', 'nomor_telepon' => 'Nomor telepon',
'jabatan' => 'Jabatan/peran', 'jabatan_lainnya' => 'Jabatan lainnya', 'lama_menjabat_tahun' => 'Lama menjabat',
'pengurus_inti' => 'Daftar Pengurus', 'pengurus_inti.*.jabatan' => 'Jabatan pengurus',
'pengurus_inti.*.nama' => 'Nama pengurus', 'pengurus_inti.*.aktif' => 'Keaktifan pengurus',
'status_badan_hukum' => 'Status badan hukum',
'nomor_dasar_hukum' => 'Nomor Peraturan Desa/SK',
'tahun_dasar_hukum' => 'Tahun Ditetapkan',
'nama_unit_komoditas' => 'Nama Unit Usaha Komoditas',
'tahun_ad_art' => 'Tahun Terakhir Diperbarui',
'status_keaktifan' => 'Status keaktifan',
'unit_usaha' => 'Unit usaha',
'status_unit_komoditas' => 'Unit usaha komoditas',
'status_ad_art' => 'Dokumen AD/ART',
'memiliki_staf' => 'Status staf/karyawan',
'jumlah_staf' => 'Jumlah staf',
'modal_awal' => 'Modal awal',
'tahun_modal_awal' => 'Tahun modal awal',
'pernah_penambahan_modal' => 'Status penambahan modal',
'penambahan_modal' => 'Rincian penambahan modal',
'penambahan_modal.*.tahun' => 'Tahun penambahan modal pada baris :position',
'penambahan_modal.*.jumlah' => 'Jumlah penambahan modal pada baris :position',
'status_kepemilikan_aset' => 'Status kepemilikan aset',
'alasan_tidak_aktif' => 'Alasan tidak aktif',
'unit_usaha.*' => 'Pilihan unit usaha',
'unit_usaha_jasa_lainnya' => 'Jasa lainnya',
'unit_usaha_staf' => 'Unit usaha staf',
'pengurus_inti.*' => 'Data pengurus pada baris :position',
'penambahan_modal.*' => 'Penambahan modal pada baris :position',
'aset_produktif' => 'Aset produktif',
'aset_produktif.*' => 'Data aset produktif pada baris :position',
'aset_produktif.*.aset' => 'Jenis aset produktif',
'aset_produktif.*.dipilih' => 'Pilihan aset produktif',
'aset_produktif.*.jumlah' => 'Jumlah aset produktif',
'aset_produktif.*.kondisi' => 'Kondisi aset produktif',
'aset_produktif_lainnya' => 'Aset produktif lainnya',
'infrastruktur_pascapanen' => 'Infrastruktur pascapanen',
'infrastruktur_pascapanen.*' => 'Data infrastruktur pada baris :position',
'infrastruktur_pascapanen.*.infrastruktur' => 'Jenis infrastruktur',
'infrastruktur_pascapanen.*.dipilih' => 'Pilihan infrastruktur',
'infrastruktur_pascapanen.*.jumlah' => 'Jumlah infrastruktur',
'infrastruktur_pascapanen.*.kondisi' => 'Kondisi infrastruktur',
'infrastruktur_pascapanen_lainnya' => 'Infrastruktur lainnya',
];
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Requests\Bumdes;
use App\Enums\Bumdes\StatusKeaktifanBumdes;
use Illuminate\Validation\Rule;
class IndexPengurusBumdesRequest extends BumdesRequest
{
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'kabupaten_kota_id' => ['nullable', 'integer', 'exists:master_kabupaten_kota,id'],
'kecamatan_id' => ['nullable', 'integer', 'exists:master_kecamatan,id'],
'desa_kelurahan_id' => ['nullable', 'integer', 'exists:master_desa_kelurahan,id'],
'status_keaktifan' => ['nullable', Rule::enum(StatusKeaktifanBumdes::class)],
'sort_by' => ['nullable', 'string'],
'per_page' => ['nullable', 'integer', 'in:10,25'],
];
}
public function messages(): array
{
return [...parent::messages(), 'exists' => ':attribute tidak ditemukan.', 'string' => ':attribute harus berupa teks.', 'max' => ':attribute terlalu panjang.', 'in' => 'Pilihan :attribute tidak valid.'];
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Http\Requests\Bumdes;
class StoreKelembagaanAktorBumdesRequest extends BumdesRequest
{
public function rules(): array
{
return $this->sectionRules('kelembagaan');
}
}
@@ -0,0 +1,252 @@
<?php
namespace App\Http\Requests\Bumdes;
use App\Enums\Bumdes\CakupanLayananBumdes;
use App\Enums\Bumdes\DukunganDesaBumdes;
use App\Enums\Bumdes\FormatPembukuanBumdes;
use App\Enums\Bumdes\HambatanUsahaBumdes;
use App\Enums\Bumdes\KemitraanEksternalBumdes;
use App\Enums\Bumdes\KeterlibatanKoordinasiBumdes;
use App\Enums\Bumdes\KondisiAsetProduktifBumdes;
use App\Enums\Bumdes\KondisiInfrastrukturBumdes;
use App\Enums\Bumdes\KondisiKeuanganBumdes;
use App\Enums\Bumdes\KontribusiPadesBumdes;
use App\Enums\Bumdes\LayananPetaniBumdes;
use App\Enums\Bumdes\PencatatanPetaniBumdes;
use App\Enums\Bumdes\PengalamanOfftakerBumdes;
use App\Enums\Bumdes\PeranRantaiNilaiBumdes;
use App\Enums\Bumdes\PertanggungjawabanMusdesBumdes;
use App\Enums\Bumdes\SifatAuditBumdes;
use App\Enums\Bumdes\StatusKepemilikanAsetBumdes;
use App\Enums\Bumdes\StatusPembukuanBumdes;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class StoreOperasionalBumdesRequest extends BumdesRequest
{
public function rules(): array
{
$rules = [...$this->sectionRules('operasional'), ...$this->pengelolaanRules()];
$dukungan = $this->input('dukungan_desa', []);
$kemitraan = $this->input('kemitraan_eksternal', []);
$dukunganLainnya = is_array($dukungan) && in_array(DukunganDesaBumdes::LAINNYA->value, $dukungan, true);
$kemitraanLainnya = is_array($kemitraan) && in_array(KemitraanEksternalBumdes::LAINNYA->value, $kemitraan, true);
$rules = [...$rules,
'ada_alokasi_desa' => ['nullable', 'boolean'],
'jumlah_alokasi_desa' => [Rule::excludeIf(! $this->boolean('ada_alokasi_desa')), 'required_if:ada_alokasi_desa,1', 'integer', 'min:0', 'max:9999999999999999'],
'dukungan_desa' => ['nullable', 'array'],
'dukungan_desa.*' => ['string', 'distinct', Rule::enum(DukunganDesaBumdes::class)],
'dukungan_desa_lainnya' => [Rule::excludeIf(! $dukunganLainnya), Rule::requiredIf($dukunganLainnya), 'string', 'max:255'],
'keterlibatan_koordinasi_desa' => ['nullable', Rule::enum(KeterlibatanKoordinasiBumdes::class)],
'kemitraan_eksternal' => ['nullable', 'array'],
'kemitraan_eksternal.*' => ['string', 'distinct', Rule::enum(KemitraanEksternalBumdes::class)],
'kemitraan_eksternal_lainnya' => [Rule::excludeIf(! $kemitraanLainnya), Rule::requiredIf($kemitraanLainnya), 'string', 'max:255'],
];
$saved = collect($this->route('pengurusBumdes')?->kelembagaanAktor?->aset_produktif ?? [])->keyBy('aset');
$rows = $this->input('aset_produktif', []);
$hasOtherAsset = false;
foreach (is_array($rows) ? $rows : [] as $index => $row) {
if (! is_array($row)) {
continue;
}
$exists = in_array($row['dipilih'] ?? null, [true, 1, '1'], true);
$assetKey = is_string($row['aset'] ?? null) ? $row['aset'] : '';
$hasOtherAsset = $hasOtherAsset || ($exists && ($row['aset'] ?? null) === 'lainnya');
$conditions = array_keys(KondisiAsetProduktifBumdes::options());
// Kondisi teks lama tetap dapat ditampilkan dan disimpan untuk aset yang sama.
$legacy = KondisiAsetProduktifBumdes::normalizeLegacy(data_get($saved->get($assetKey), 'kondisi'));
if ($legacy !== null) {
$conditions[] = $legacy;
}
$prefix = 'aset_produktif.'.$index.'.';
$rules[$prefix.'status_kepemilikan_aset'] = [Rule::excludeIf(! $exists), Rule::requiredIf($exists), Rule::enum(StatusKepemilikanAsetBumdes::class)];
$rules[$prefix.'kondisi'] = [Rule::excludeIf(! $exists), Rule::requiredIf($exists), Rule::in($conditions)];
$rules[$prefix.'jumlah'] = [Rule::excludeIf(! $exists), 'nullable', 'integer', 'min:0'];
}
$rules['aset_produktif_lainnya'] = [Rule::excludeIf(! $hasOtherAsset), Rule::requiredIf($hasOtherAsset), 'string', 'max:255'];
$rows = $this->input('infrastruktur_pascapanen', []);
$hasOtherInfrastructure = false;
foreach (is_array($rows) ? $rows : [] as $index => $row) {
if (! is_array($row)) {
continue;
}
$exists = in_array($row['dipilih'] ?? null, [true, 1, '1'], true);
$hasOtherInfrastructure = $hasOtherInfrastructure || ($exists && ($row['infrastruktur'] ?? null) === 'lainnya');
$prefix = 'infrastruktur_pascapanen.'.$index.'.';
$rules[$prefix.'kondisi'] = [Rule::excludeIf(! $exists), Rule::requiredIf($exists), Rule::enum(KondisiInfrastrukturBumdes::class)];
$rules[$prefix.'jumlah'] = [Rule::excludeIf(! $exists), 'nullable', 'integer', 'min:0'];
}
$rules['infrastruktur_pascapanen_lainnya'] = [Rule::excludeIf(! $hasOtherInfrastructure), Rule::requiredIf($hasOtherInfrastructure), 'string', 'max:255'];
return $rules;
}
private function pengelolaanRules(): array
{
$hasAudit = $this->boolean('pernah_audit');
$annualReport = $this->input('pertanggungjawaban_musdes') === PertanggungjawabanMusdesBumdes::TAHUNAN->value;
$hasPades = in_array($this->input('kontribusi_pades'), [KontribusiPadesBumdes::RUTIN->value, KontribusiPadesBumdes::TIDAK_RUTIN->value], true);
$otherVillage = $this->input('cakupan_layanan') === CakupanLayananBumdes::DESA_LAIN->value;
$activePartnership = $this->input('pengalaman_offtaker') === PengalamanOfftakerBumdes::BERJALAN->value;
$stoppedPartnership = $this->input('pengalaman_offtaker') === PengalamanOfftakerBumdes::BERHENTI->value;
$hasOther = fn (string $field, string $value) => is_array($selected = $this->input($field)) && in_array($value, $selected, true);
$otherService = $hasOther('layanan_petani', LayananPetaniBumdes::LAINNYA->value);
$otherObstacle = $hasOther('hambatan_usaha', HambatanUsahaBumdes::LAINNYA->value);
$year = ['integer', 'digits:4', 'min:1900', 'max:'.now()->year];
return [
'status_pembukuan' => ['nullable', Rule::enum(StatusPembukuanBumdes::class)],
'format_pembukuan' => ['nullable', Rule::enum(FormatPembukuanBumdes::class)],
'pernah_audit' => ['nullable', 'boolean'],
'sifat_audit' => [Rule::excludeIf(! $hasAudit), Rule::requiredIf($hasAudit), 'array', 'min:1'],
'sifat_audit.*' => [Rule::excludeIf(! $hasAudit), 'string', 'distinct', Rule::enum(SifatAuditBumdes::class)],
'pelaksana_audit' => [Rule::excludeIf(! $hasAudit), Rule::requiredIf($hasAudit), 'string', 'max:255'],
'tahun_audit' => [Rule::excludeIf(! $hasAudit), Rule::requiredIf($hasAudit), ...$year],
'pertanggungjawaban_musdes' => ['nullable', Rule::enum(PertanggungjawabanMusdesBumdes::class)],
'tahun_laporan_musdes' => [Rule::excludeIf(! $annualReport), Rule::requiredIf($annualReport), ...$year],
'kondisi_keuangan' => ['nullable', Rule::enum(KondisiKeuanganBumdes::class)],
'kontribusi_pades' => ['nullable', Rule::enum(KontribusiPadesBumdes::class)],
'nominal_kontribusi_pades' => [Rule::excludeIf(! $hasPades), Rule::requiredIf($hasPades), 'integer', 'min:0', 'max:9999999999999999'],
'cakupan_layanan' => ['nullable', Rule::enum(CakupanLayananBumdes::class)],
'desa_lain_dilayani' => [Rule::excludeIf(! $otherVillage), Rule::requiredIf($otherVillage), 'string', 'max:2000'],
'jumlah_petani_desa_sendiri' => ['nullable', 'integer', 'min:0', 'max:2147483647'],
'jumlah_petani_desa_lain' => [Rule::excludeIf(! $otherVillage), Rule::requiredIf($otherVillage), 'integer', 'min:0', 'max:2147483647'],
'pencatatan_petani' => ['nullable', Rule::enum(PencatatanPetaniBumdes::class)],
'layanan_petani' => ['nullable', 'array'],
'layanan_petani.*' => ['string', 'distinct', Rule::enum(LayananPetaniBumdes::class)],
'layanan_petani_lainnya' => [Rule::excludeIf(! $otherService), Rule::requiredIf($otherService), 'string', 'max:255'],
'peran_rantai_nilai' => ['nullable', Rule::enum(PeranRantaiNilaiBumdes::class)],
'pengalaman_offtaker' => ['nullable', Rule::enum(PengalamanOfftakerBumdes::class)],
'nama_offtaker' => [Rule::excludeIf(! $activePartnership), Rule::requiredIf($activePartnership), 'string', 'max:255'],
'tahun_mulai_offtaker' => [Rule::excludeIf(! $activePartnership), Rule::requiredIf($activePartnership), ...$year],
'alasan_berhenti_offtaker' => [Rule::excludeIf(! $stoppedPartnership), Rule::requiredIf($stoppedPartnership), 'string', 'max:2000'],
'hambatan_usaha' => ['nullable', 'array'],
'hambatan_usaha.*' => ['string', 'distinct', Rule::enum(HambatanUsahaBumdes::class)],
'hambatan_usaha_lainnya' => [Rule::excludeIf(! $otherObstacle), Rule::requiredIf($otherObstacle), 'string', 'max:255'],
];
}
protected function prepareForValidation(): void
{
foreach (['jumlah_alokasi_desa', 'nominal_kontribusi_pades'] as $field) {
$amount = $this->input($field);
if (is_string($amount) && preg_match('/^\d{1,3}(\.\d{3})+$/D', $amount)) {
$this->merge([$field => str_replace('.', '', $amount)]);
}
}
$normalize = static fn ($value) => is_scalar($value) ? preg_replace('/\D/', '', (string) $value) : $value;
$data = [];
if ($this->has('modal_awal')) {
$data['modal_awal'] = $normalize($this->input('modal_awal'));
}
if (is_array($this->input('penambahan_modal'))) {
$data['penambahan_modal'] = array_map(function ($row) use ($normalize) {
if (is_array($row) && array_key_exists('jumlah', $row)) {
$row['jumlah'] = $normalize($row['jumlah']);
}
return $row;
}, $this->input('penambahan_modal'));
}
if (is_array($this->input('aset_produktif'))) {
$legacyOwnership = $this->input('status_kepemilikan_aset')
?? $this->route('pengurusBumdes')?->kelembagaanAktor?->status_kepemilikan_aset?->value;
$data['aset_produktif'] = array_map(function ($row) use ($legacyOwnership) {
if (! is_array($row)) {
return $row;
}
if (! array_key_exists('status_kepemilikan_aset', $row)) {
$row['status_kepemilikan_aset'] = $legacyOwnership;
}
if (is_scalar($row['kondisi'] ?? null)) {
$row['kondisi'] = KondisiAsetProduktifBumdes::normalizeLegacy($row['kondisi']);
}
return $row;
}, $this->input('aset_produktif'));
}
$this->merge($data);
}
public function after(): array
{
return [function (Validator $validator) {
foreach (['dukungan_desa' => DukunganDesaBumdes::TIDAK_ADA->value, 'kemitraan_eksternal' => KemitraanEksternalBumdes::BELUM_ADA->value, 'layanan_petani' => LayananPetaniBumdes::BELUM_ADA->value] as $field => $none) {
$selected = $this->input($field, []);
if (is_array($selected) && in_array($none, $selected, true) && count($selected) > 1) {
$validator->errors()->add($field, match ($field) {
'dukungan_desa' => 'Tidak ada dukungan khusus tidak boleh dipilih bersama bentuk dukungan lainnya.',
'kemitraan_eksternal' => 'Belum ada kemitraan eksternal tidak boleh dipilih bersama jenis kemitraan lainnya.',
'layanan_petani' => 'Belum ada layanan tidak boleh dipilih bersama jenis layanan lainnya.',
});
}
}
}];
}
public function messages(): array
{
return [...parent::messages(),
'jumlah_alokasi_desa.required_if' => 'Besaran alokasi APBDes/Dana Desa wajib diisi jika ada alokasi tahun berjalan.',
'jumlah_alokasi_desa.max' => 'Besaran alokasi APBDes/Dana Desa tidak boleh melebihi Rp 9.999.999.999.999.999.',
'dukungan_desa_lainnya.required' => 'Bentuk dukungan lainnya wajib diisi jika memilih Lainnya.',
'kemitraan_eksternal_lainnya.required' => 'Jenis kemitraan lainnya wajib diisi jika memilih Lainnya.',
'nominal_kontribusi_pades.max' => 'Nominal kontribusi PADes tidak boleh melebihi Rp 9.999.999.999.999.999.',
'sifat_audit.min' => 'Pilih minimal satu sifat audit/pemeriksaan.',
'distinct' => ':attribute tidak boleh dipilih lebih dari satu kali.',
'aset_produktif.*.status_kepemilikan_aset.required' => 'Status Kepemilikan wajib diisi jika aset dipilih Ada.',
'aset_produktif.*.kondisi.required' => 'Kondisi wajib diisi jika aset dipilih Ada.',
'aset_produktif_lainnya.required' => 'Nama aset lainnya wajib diisi jika dipilih Ada.',
'infrastruktur_pascapanen.*.kondisi.required' => 'Kondisi wajib diisi jika infrastruktur dipilih Ada.',
'infrastruktur_pascapanen_lainnya.required' => 'Nama infrastruktur lainnya wajib diisi jika dipilih Ada.',
];
}
public function attributes(): array
{
return [...parent::attributes(),
'status_pembukuan' => 'Sistem pembukuan dan laporan keuangan',
'format_pembukuan' => 'Format pembukuan',
'pernah_audit' => 'Status audit/pemeriksaan',
'sifat_audit' => 'Sifat audit/pemeriksaan',
'pelaksana_audit' => 'Pelaksana audit/pemeriksaan',
'tahun_audit' => 'Tahun terakhir audit/pemeriksaan',
'pertanggungjawaban_musdes' => 'Pertanggungjawaban ke musyawarah desa',
'tahun_laporan_musdes' => 'Tahun terakhir laporan ke musyawarah desa',
'kondisi_keuangan' => 'Kondisi keuangan',
'kontribusi_pades' => 'Kontribusi ke PADes',
'nominal_kontribusi_pades' => 'Nominal kontribusi ke PADes',
'cakupan_layanan' => 'Cakupan wilayah layanan',
'desa_lain_dilayani' => 'Desa lain yang dilayani',
'jumlah_petani_desa_sendiri' => 'Jumlah petani dari desa sendiri',
'jumlah_petani_desa_lain' => 'Jumlah petani dari desa lain',
'pencatatan_petani' => 'Pencatatan petani yang dilayani',
'layanan_petani' => 'Layanan bagi petani',
'layanan_petani_lainnya' => 'Layanan lainnya',
'peran_rantai_nilai' => 'Peran dalam rantai nilai',
'pengalaman_offtaker' => 'Pengalaman kemitraan dengan offtaker',
'nama_offtaker' => 'Nama offtaker',
'tahun_mulai_offtaker' => 'Tahun mulai kemitraan',
'alasan_berhenti_offtaker' => 'Alasan kemitraan berhenti',
'hambatan_usaha' => 'Hambatan usaha',
'hambatan_usaha_lainnya' => 'Hambatan lainnya',
'sifat_audit.*' => 'Pilihan sifat audit/pemeriksaan',
'layanan_petani.*' => 'Pilihan layanan bagi petani',
'hambatan_usaha.*' => 'Pilihan hambatan usaha',
'ada_alokasi_desa' => 'Status alokasi APBDes/Dana Desa',
'jumlah_alokasi_desa' => 'Besaran alokasi APBDes/Dana Desa',
'dukungan_desa' => 'Bentuk dukungan pemerintah desa',
'dukungan_desa.*' => 'Pilihan dukungan pemerintah desa',
'dukungan_desa_lainnya' => 'Bentuk dukungan lainnya',
'keterlibatan_koordinasi_desa' => 'Keterlibatan dalam rapat/koordinasi desa',
'kemitraan_eksternal' => 'Kemitraan eksternal',
'kemitraan_eksternal.*' => 'Pilihan kemitraan eksternal',
'kemitraan_eksternal_lainnya' => 'Jenis kemitraan lainnya',
'aset_produktif.*.status_kepemilikan_aset' => 'Status Kepemilikan aset',
];
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Http\Requests\Bumdes;
use App\Enums\Bumdes\JabatanBumdes;
use App\Enums\Pendidikan;
use Illuminate\Validation\Rule;
class StorePengurusBumdesRequest extends BumdesRequest
{
public function rules(): array
{
return [
'nama' => ['required', 'string', 'max:255'],
'jenis_kelamin' => ['required', 'boolean'],
'tempat_lahir' => ['required', 'string', 'max:255'],
'tanggal_lahir' => ['required', 'date_format:d-m-Y'],
'pendidikan_terakhir' => ['required', Rule::enum(Pendidikan::class)],
'alamat' => ['required', 'string', 'max:500'],
'provinsi_id' => ['bail', 'required', 'integer', 'exists:master_provinsi,id'],
'kabupaten_id' => ['bail', 'required', 'integer', 'exists:master_kabupaten_kota,id'],
'kecamatan_id' => ['bail', 'required', 'integer', 'exists:master_kecamatan,id'],
'desa_kelurahan_id' => ['bail', 'required', 'integer', 'exists:master_desa_kelurahan,id'],
'nomor_telepon' => ['nullable', 'digits_between:11,13'],
'jabatan' => ['required', Rule::enum(JabatanBumdes::class)],
'jabatan_lainnya' => ['nullable', 'required_if:jabatan,'.JabatanBumdes::LAINNYA->value, 'string', 'max:255'],
'lama_menjabat_tahun' => ['required', 'integer', 'min:0', 'max:80'],
...$this->sectionRules('profil'),
];
}
public function messages(): array
{
return [
...parent::messages(),
'nama.required' => 'Nama harus diisi.',
'jenis_kelamin.required' => 'Jenis kelamin harus dipilih.',
'tempat_lahir.required' => 'Tempat lahir harus diisi.',
'tanggal_lahir.required' => 'Tanggal lahir harus diisi.',
'tanggal_lahir.date_format' => 'Tanggal lahir harus menggunakan format tanggal yang valid.',
'pendidikan_terakhir.required' => 'Pendidikan terakhir harus dipilih.',
'alamat.required' => 'Alamat harus diisi.',
'provinsi_id.required' => 'Provinsi wajib dipilih.',
'kabupaten_id.required' => 'Kabupaten/Kota wajib dipilih.',
'kecamatan_id.required' => 'Kecamatan wajib dipilih.',
'provinsi_id.integer' => 'Pilihan Provinsi tidak valid.',
'kabupaten_id.integer' => 'Pilihan Kabupaten/Kota tidak valid.',
'kecamatan_id.integer' => 'Pilihan Kecamatan tidak valid.',
'desa_kelurahan_id.integer' => 'Pilihan Desa/Kelurahan tidak valid.',
'provinsi_id.exists' => 'Provinsi tidak ditemukan.',
'kabupaten_id.exists' => 'Kabupaten/Kota tidak ditemukan.',
'kecamatan_id.exists' => 'Kecamatan tidak ditemukan.',
'desa_kelurahan_id.required' => 'Desa kelurahan harus dipilih.',
'desa_kelurahan_id.exists' => 'Desa kelurahan tidak ditemukan.',
'nomor_telepon.digits_between' => 'Nomor telepon harus berupa angka 11 sampai 13 digit.',
'jabatan.required' => 'Jabatan/peran harus dipilih.',
'jabatan_lainnya.required_if' => 'Jabatan lainnya harus diisi.',
'lama_menjabat_tahun.required' => 'Lama menjabat harus diisi.',
'lama_menjabat_tahun.integer' => 'Lama menjabat harus berupa angka tahun.',
'string' => ':attribute harus berupa teks.',
'max' => ':attribute tidak valid.',
'min' => ':attribute tidak boleh kurang dari :min.',
'enum' => 'Pilihan :attribute tidak valid.',
];
}
}
@@ -0,0 +1,172 @@
<?php
namespace App\Http\Requests\Bumdes;
use App\Enums\Bumdes\BentukProdukBumdes;
use App\Enums\Bumdes\HubunganPemasokBumdes;
use App\Enums\Bumdes\MekanismePembayaranBumdes;
use App\Enums\Bumdes\ModelFermentasiBumdes;
use App\Enums\Bumdes\PenetapanHargaBeliBumdes;
use App\Enums\Bumdes\PeriodePanenBumdes;
use App\Enums\Bumdes\PerjanjianPetaniBumdes;
use App\Enums\Bumdes\SaluranPenjualanBumdes;
use App\Enums\Bumdes\StatusFermentasiBumdes;
use App\Enums\Bumdes\StatusPengeringanBumdes;
use App\Enums\Bumdes\StatusSortasiBumdes;
use App\Enums\Bumdes\SumberPasokanBumdes;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class StoreRantaiNilaiBumdesRequest extends BumdesRequest
{
public function rules(): array
{
$trading = $this->boolean('melakukan_jual_beli');
$hasChoice = fn (string $field, string $value) => is_array($selected = $this->input($field)) && in_array($value, $selected, true);
$notSold = $hasChoice('saluran_penjualan', SaluranPenjualanBumdes::BELUM_MENJUAL->value);
$otherSource = $trading && $hasChoice('sumber_pasokan', SumberPasokanBumdes::LAINNYA->value);
$otherChannel = $trading && $hasChoice('saluran_penjualan', SaluranPenjualanBumdes::LAINNYA->value);
$otherRelationship = $trading && $hasChoice('hubungan_petani_pemasok', HubunganPemasokBumdes::LAINNYA->value);
$otherPayment = $trading && $this->input('mekanisme_pembayaran_petani') === MekanismePembayaranBumdes::LAINNYA->value;
$otherPrice = $trading && $this->input('penetapan_harga_beli') === PenetapanHargaBeliBumdes::LAINNYA->value;
$periods = implode(',', array_keys(PeriodePanenBumdes::options()));
$products = implode(',', array_keys(BentukProdukBumdes::options()));
$rules = [...$this->pascapanenRules(),
'melakukan_jual_beli' => ['required', 'boolean'],
'redirect_fragment' => ['nullable', Rule::in(['section-rantai-penjualan', 'section-rantai-hubungan-pemasok', 'section-rantai-harga-beli', 'section-rantai-sortasi', 'section-rantai-pengeringan', 'section-rantai-fermentasi', 'section-rantai-premium-harga'])],
'sumber_pasokan' => [Rule::excludeIf(! $trading), 'nullable', 'array'],
'sumber_pasokan.*' => [Rule::excludeIf(! $trading), 'string', 'distinct', Rule::enum(SumberPasokanBumdes::class)],
'sumber_pasokan_lainnya' => [Rule::excludeIf(! $otherSource), Rule::requiredIf($otherSource), 'string', 'max:255'],
'bentuk_produk_dibeli' => [Rule::excludeIf(! $trading), 'nullable', 'array'],
'bentuk_produk_dibeli.*' => [Rule::excludeIf(! $trading), 'string', 'distinct', Rule::enum(BentukProdukBumdes::class)],
'volume_pembelian' => [Rule::excludeIf(! $trading), 'nullable', 'array:'.$periods],
'volume_pembelian.*' => [Rule::excludeIf(! $trading), 'nullable', 'numeric', 'decimal:0,3', 'min:0', 'max:999999999999.999'],
'saluran_penjualan' => [Rule::excludeIf(! $trading), 'nullable', 'array'],
'saluran_penjualan.*' => [Rule::excludeIf(! $trading), 'string', 'distinct', Rule::enum(SaluranPenjualanBumdes::class)],
'saluran_penjualan_lainnya' => [Rule::excludeIf(! $otherChannel), Rule::requiredIf($otherChannel), 'string', 'max:255'],
'bentuk_produk_dijual' => [Rule::excludeIf(! $trading || $notSold), 'nullable', 'array'],
'bentuk_produk_dijual.*' => [Rule::excludeIf(! $trading || $notSold), 'string', 'distinct', Rule::enum(BentukProdukBumdes::class)],
'volume_penjualan' => [Rule::excludeIf(! $trading || $notSold), 'nullable', 'array:'.$periods],
'volume_penjualan.*' => [Rule::excludeIf(! $trading || $notSold), 'nullable', 'numeric', 'decimal:0,3', 'min:0', 'max:999999999999.999'],
'hubungan_petani_pemasok' => [Rule::excludeIf(! $trading), 'nullable', 'array'],
'hubungan_petani_pemasok.*' => [Rule::excludeIf(! $trading), 'string', 'distinct', Rule::enum(HubunganPemasokBumdes::class)],
'hubungan_petani_pemasok_lainnya' => [Rule::excludeIf(! $otherRelationship), Rule::requiredIf($otherRelationship), 'string', 'max:255'],
'mekanisme_pembayaran_petani' => [Rule::excludeIf(! $trading), 'nullable', Rule::enum(MekanismePembayaranBumdes::class)],
'mekanisme_pembayaran_lainnya' => [Rule::excludeIf(! $otherPayment), Rule::requiredIf($otherPayment), 'string', 'max:255'],
'perjanjian_petani' => [Rule::excludeIf(! $trading), 'nullable', Rule::enum(PerjanjianPetaniBumdes::class)],
'harga_beli_petani' => [Rule::excludeIf(! $trading), 'nullable', 'array:'.$products],
'penetapan_harga_beli' => [Rule::excludeIf(! $trading), 'nullable', Rule::enum(PenetapanHargaBeliBumdes::class)],
'penetapan_harga_beli_lainnya' => [Rule::excludeIf(! $otherPrice), Rule::requiredIf($otherPrice), 'string', 'max:255'],
];
foreach (BentukProdukBumdes::cases() as $product) {
$enabled = $trading && $hasChoice('bentuk_produk_dibeli', $product->value);
$prefix = 'harga_beli_petani.'.$product->value;
$rules[$prefix] = [Rule::excludeIf(! $enabled), 'nullable', 'array:'.$periods];
$rules[$prefix.'.*'] = [Rule::excludeIf(! $enabled), 'nullable', 'integer', 'min:0', 'max:9999999999999999'];
}
return $rules;
}
private function pascapanenRules(): array
{
$processing = $this->boolean('melakukan_pengolahan_pascapanen');
$sorting = $processing && in_array($this->input('status_sortasi'), [StatusSortasiBumdes::RUTIN_STANDAR->value, StatusSortasiBumdes::TIDAK_KONSISTEN->value], true);
$drying = $processing && in_array($this->input('status_pengeringan'), [StatusPengeringanBumdes::RUTIN->value, StatusPengeringanBumdes::KADANG->value], true);
$fermenting = $processing && in_array($this->input('status_fermentasi'), [StatusFermentasiBumdes::RUTIN->value, StatusFermentasiBumdes::PERNAH_MENCOBA->value], true);
return [
'melakukan_pengolahan_pascapanen' => ['required', 'boolean'],
'status_sortasi' => [Rule::excludeIf(! $processing), 'nullable', Rule::enum(StatusSortasiBumdes::class)],
'kriteria_sortasi' => [Rule::excludeIf(! $sorting), Rule::requiredIf($sorting), 'string', 'max:2000'],
'status_pengeringan' => [Rule::excludeIf(! $processing), 'nullable', Rule::enum(StatusPengeringanBumdes::class)],
'cara_tempat_pengeringan' => [Rule::excludeIf(! $drying), Rule::requiredIf($drying), 'string', 'max:2000'],
'status_fermentasi' => [Rule::excludeIf(! $processing), 'nullable', Rule::enum(StatusFermentasiBumdes::class)],
'model_fermentasi' => [Rule::excludeIf(! $fermenting), Rule::requiredIf($fermenting), 'array', 'min:1'],
'model_fermentasi.*' => [Rule::excludeIf(! $fermenting), 'string', 'distinct', Rule::enum(ModelFermentasiBumdes::class)],
'proses_fermentasi' => [Rule::excludeIf(! $fermenting), Rule::requiredIf($fermenting), 'string', 'max:2000'],
'premium_harga_pascapanen' => [Rule::excludeIf(! $processing), 'nullable', 'integer', 'min:0', 'max:9999999999999999'],
];
}
protected function prepareForValidation(): void
{
$premium = $this->input('premium_harga_pascapanen');
if (is_string($premium) && preg_match('/^\d{1,3}(\.\d{3})+$/D', $premium)) {
$this->merge(['premium_harga_pascapanen' => str_replace('.', '', $premium)]);
}
$prices = $this->input('harga_beli_petani');
if (! is_array($prices)) {
return;
}
foreach ($prices as &$row) {
if (! is_array($row)) {
continue;
}
foreach ($row as &$value) {
if (is_string($value) && preg_match('/^\d{1,3}(\.\d{3})+$/D', $value)) {
$value = str_replace('.', '', $value);
}
}
unset($value);
}
unset($row);
$this->merge(['harga_beli_petani' => $prices]);
}
public function after(): array
{
return [function (Validator $validator) {
$channels = $this->input('saluran_penjualan');
if ($this->boolean('melakukan_jual_beli') && is_array($channels) && count($channels) > 1 && in_array(SaluranPenjualanBumdes::BELUM_MENJUAL->value, $channels, true)) {
$validator->errors()->add('saluran_penjualan', 'Belum pernah menjual tidak boleh dipilih bersama saluran penjualan lainnya.');
}
}];
}
public function messages(): array
{
return [...parent::messages(),
'melakukan_pengolahan_pascapanen.required' => 'Kegiatan pengolahan pascapanen wajib dipilih.',
'melakukan_jual_beli.required' => 'Kegiatan jual beli komoditas wajib dipilih.',
'model_fermentasi.min' => 'Pilih minimal satu model fermentasi.',
'premium_harga_pascapanen.max' => 'Premium harga tidak boleh melebihi Rp 9.999.999.999.999.999 per kg.',
'numeric' => ':attribute harus berupa angka.',
'decimal' => ':attribute boleh memiliki maksimal 3 angka di belakang koma.',
'distinct' => ':attribute tidak boleh dipilih lebih dari satu kali.',
'harga_beli_petani.*.*.max' => 'Harga beli tidak boleh melebihi Rp 9.999.999.999.999.999 per kg.',
];
}
public function attributes(): array
{
return [...parent::attributes(),
'melakukan_pengolahan_pascapanen' => 'Kegiatan pengolahan pascapanen',
'status_sortasi' => 'Praktik sortasi',
'kriteria_sortasi' => 'Standar/kriteria sortasi',
'status_pengeringan' => 'Praktik pengeringan',
'cara_tempat_pengeringan' => 'Cara dan tempat pengeringan',
'status_fermentasi' => 'Praktik fermentasi/pengepresan',
'model_fermentasi' => 'Model fermentasi',
'proses_fermentasi' => 'Proses fermentasi',
'premium_harga_pascapanen' => 'Premium harga per kg',
'model_fermentasi.*' => 'Pilihan model fermentasi',
'melakukan_jual_beli' => 'Kegiatan jual beli komoditas',
'redirect_fragment' => 'Tujuan setelah penyimpanan',
'sumber_pasokan' => 'Sumber pasokan', 'sumber_pasokan.*' => 'Pilihan sumber pasokan',
'sumber_pasokan_lainnya' => 'Sumber pasokan lainnya',
'bentuk_produk_dibeli' => 'Bentuk produk yang dibeli', 'bentuk_produk_dibeli.*' => 'Pilihan bentuk produk yang dibeli',
'volume_pembelian' => 'Volume pembelian', 'volume_pembelian.*' => 'Volume pembelian pada musim panen terkait',
'saluran_penjualan' => 'Saluran penjualan', 'saluran_penjualan.*' => 'Pilihan saluran penjualan',
'saluran_penjualan_lainnya' => 'Saluran penjualan lainnya',
'bentuk_produk_dijual' => 'Bentuk produk yang dijual', 'bentuk_produk_dijual.*' => 'Pilihan bentuk produk yang dijual',
'volume_penjualan' => 'Volume penjualan', 'volume_penjualan.*' => 'Volume penjualan pada musim panen terkait',
'hubungan_petani_pemasok' => 'Hubungan dengan petani pemasok', 'hubungan_petani_pemasok.*' => 'Pilihan hubungan dengan petani pemasok',
'hubungan_petani_pemasok_lainnya' => 'Hubungan dengan petani pemasok lainnya',
'mekanisme_pembayaran_petani' => 'Mekanisme pembayaran kepada petani', 'mekanisme_pembayaran_lainnya' => 'Mekanisme pembayaran lainnya',
'perjanjian_petani' => 'Perjanjian dengan petani',
'harga_beli_petani' => 'Harga beli dari petani', 'harga_beli_petani.*' => 'Harga beli untuk bentuk produk terkait', 'harga_beli_petani.*.*' => 'Harga beli pada musim panen terkait',
'penetapan_harga_beli' => 'Penetapan harga beli', 'penetapan_harga_beli_lainnya' => 'Penetapan harga beli lainnya',
];
}
}
@@ -0,0 +1,5 @@
<?php
namespace App\Http\Requests\Bumdes;
class UpdatePengurusBumdesRequest extends StorePengurusBumdesRequest {}
+237 -15
View File
@@ -2,15 +2,49 @@
namespace App\Models\Bumdes;
use App\Enums\Bumdes\BentukProdukBumdes;
use App\Enums\Bumdes\CakupanLayananBumdes;
use App\Enums\Bumdes\DukunganDesaBumdes;
use App\Enums\Bumdes\FormatPembukuanBumdes;
use App\Enums\Bumdes\HambatanUsahaBumdes;
use App\Enums\Bumdes\HubunganPemasokBumdes;
use App\Enums\Bumdes\KemitraanEksternalBumdes;
use App\Enums\Bumdes\KeterlibatanKoordinasiBumdes;
use App\Enums\Bumdes\KondisiKeuanganBumdes;
use App\Enums\Bumdes\KontribusiPadesBumdes;
use App\Enums\Bumdes\LayananPetaniBumdes;
use App\Enums\Bumdes\MekanismePembayaranBumdes;
use App\Enums\Bumdes\ModelFermentasiBumdes;
use App\Enums\Bumdes\PencatatanPetaniBumdes;
use App\Enums\Bumdes\PenetapanHargaBeliBumdes;
use App\Enums\Bumdes\PengalamanOfftakerBumdes;
use App\Enums\Bumdes\PeranRantaiNilaiBumdes;
use App\Enums\Bumdes\PerjanjianPetaniBumdes;
use App\Enums\Bumdes\PertanggungjawabanMusdesBumdes;
use App\Enums\Bumdes\SaluranPenjualanBumdes;
use App\Enums\Bumdes\SifatAuditBumdes;
use App\Enums\Bumdes\StatusAdArtBumdes;
use App\Enums\Bumdes\StatusBadanHukumBumdes;
use App\Enums\Bumdes\StatusFermentasiBumdes;
use App\Enums\Bumdes\StatusKeaktifanBumdes;
use App\Enums\Bumdes\StatusKepemilikanAsetBumdes;
use App\Enums\Bumdes\StatusPembukuanBumdes;
use App\Enums\Bumdes\StatusPengeringanBumdes;
use App\Enums\Bumdes\StatusSortasiBumdes;
use App\Enums\Bumdes\StatusUnitKomoditasBumdes;
use App\Enums\Bumdes\SumberPasokanBumdes;
use App\Enums\Bumdes\UnitUsahaBumdes;
use App\Models\Concerns\CatatAktivitas;
use App\Models\Concerns\HasDeletedBy;
use App\Models\User;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class KelembagaanAktorBumdes extends Model
{
use SoftDeletes, CatatAktivitas;
use CatatAktivitas, HasDeletedBy, SoftDeletes;
protected $table = 'bumdes_kelembagaan_aktor';
@@ -40,25 +74,213 @@ class KelembagaanAktorBumdes extends Model
'status_kepemilikan_aset',
'infrastruktur_pascapanen',
'infrastruktur_pascapanen_lainnya',
'ada_alokasi_desa',
'jumlah_alokasi_desa',
'dukungan_desa',
'dukungan_desa_lainnya',
'keterlibatan_koordinasi_desa',
'kemitraan_eksternal',
'kemitraan_eksternal_lainnya',
'status_pembukuan',
'format_pembukuan',
'pernah_audit',
'sifat_audit',
'pelaksana_audit',
'tahun_audit',
'pertanggungjawaban_musdes',
'tahun_laporan_musdes',
'kondisi_keuangan',
'kontribusi_pades',
'nominal_kontribusi_pades',
'cakupan_layanan',
'desa_lain_dilayani',
'jumlah_petani_desa_sendiri',
'jumlah_petani_desa_lain',
'pencatatan_petani',
'layanan_petani',
'layanan_petani_lainnya',
'peran_rantai_nilai',
'pengalaman_offtaker',
'nama_offtaker',
'tahun_mulai_offtaker',
'alasan_berhenti_offtaker',
'hambatan_usaha',
'hambatan_usaha_lainnya',
'melakukan_jual_beli',
'sumber_pasokan',
'sumber_pasokan_lainnya',
'bentuk_produk_dibeli',
'volume_pembelian',
'saluran_penjualan',
'saluran_penjualan_lainnya',
'bentuk_produk_dijual',
'volume_penjualan',
'hubungan_petani_pemasok',
'hubungan_petani_pemasok_lainnya',
'mekanisme_pembayaran_petani',
'mekanisme_pembayaran_lainnya',
'perjanjian_petani',
'harga_beli_petani',
'penetapan_harga_beli',
'penetapan_harga_beli_lainnya',
'melakukan_pengolahan_pascapanen',
'status_sortasi',
'kriteria_sortasi',
'status_pengeringan',
'cara_tempat_pengeringan',
'status_fermentasi',
'model_fermentasi',
'proses_fermentasi',
'premium_harga_pascapanen',
'created_by',
'updated_by',
'deleted_by',
];
protected $casts = [
'tahun_dasar_hukum' => 'integer',
'tahun_ad_art' => 'integer',
'unit_usaha' => 'array',
'pengurus_inti' => 'array',
'memiliki_staf' => 'boolean',
'jumlah_staf' => 'integer',
'modal_awal' => 'decimal:2',
'tahun_modal_awal' => 'integer',
'pernah_penambahan_modal' => 'boolean',
'penambahan_modal' => 'array',
'aset_produktif' => 'array',
'infrastruktur_pascapanen' => 'array',
];
protected function casts(): array
{
return [
'melakukan_pengolahan_pascapanen' => 'boolean',
'status_sortasi' => StatusSortasiBumdes::class,
'status_pengeringan' => StatusPengeringanBumdes::class,
'status_fermentasi' => StatusFermentasiBumdes::class,
'model_fermentasi' => AsEnumCollection::of(ModelFermentasiBumdes::class),
'premium_harga_pascapanen' => 'decimal:2',
'melakukan_jual_beli' => 'boolean',
'sumber_pasokan' => AsEnumCollection::of(SumberPasokanBumdes::class),
'bentuk_produk_dibeli' => AsEnumCollection::of(BentukProdukBumdes::class),
'volume_pembelian' => 'array',
'saluran_penjualan' => AsEnumCollection::of(SaluranPenjualanBumdes::class),
'bentuk_produk_dijual' => AsEnumCollection::of(BentukProdukBumdes::class),
'volume_penjualan' => 'array',
'hubungan_petani_pemasok' => AsEnumCollection::of(HubunganPemasokBumdes::class),
'mekanisme_pembayaran_petani' => MekanismePembayaranBumdes::class,
'perjanjian_petani' => PerjanjianPetaniBumdes::class,
'harga_beli_petani' => 'array',
'penetapan_harga_beli' => PenetapanHargaBeliBumdes::class,
'status_pembukuan' => StatusPembukuanBumdes::class,
'format_pembukuan' => FormatPembukuanBumdes::class,
'pernah_audit' => 'boolean',
'sifat_audit' => AsEnumCollection::of(SifatAuditBumdes::class),
'tahun_audit' => 'integer',
'pertanggungjawaban_musdes' => PertanggungjawabanMusdesBumdes::class,
'tahun_laporan_musdes' => 'integer',
'kondisi_keuangan' => KondisiKeuanganBumdes::class,
'kontribusi_pades' => KontribusiPadesBumdes::class,
'nominal_kontribusi_pades' => 'decimal:2',
'cakupan_layanan' => CakupanLayananBumdes::class,
'jumlah_petani_desa_sendiri' => 'integer',
'jumlah_petani_desa_lain' => 'integer',
'pencatatan_petani' => PencatatanPetaniBumdes::class,
'layanan_petani' => AsEnumCollection::of(LayananPetaniBumdes::class),
'peran_rantai_nilai' => PeranRantaiNilaiBumdes::class,
'pengalaman_offtaker' => PengalamanOfftakerBumdes::class,
'tahun_mulai_offtaker' => 'integer',
'hambatan_usaha' => AsEnumCollection::of(HambatanUsahaBumdes::class),
'ada_alokasi_desa' => 'boolean',
'jumlah_alokasi_desa' => 'decimal:2',
'dukungan_desa' => AsEnumCollection::of(DukunganDesaBumdes::class),
'keterlibatan_koordinasi_desa' => KeterlibatanKoordinasiBumdes::class,
'kemitraan_eksternal' => AsEnumCollection::of(KemitraanEksternalBumdes::class),
'status_badan_hukum' => StatusBadanHukumBumdes::class,
'status_keaktifan' => StatusKeaktifanBumdes::class,
'status_unit_komoditas' => StatusUnitKomoditasBumdes::class,
'status_ad_art' => StatusAdArtBumdes::class,
'status_kepemilikan_aset' => StatusKepemilikanAsetBumdes::class,
'tahun_dasar_hukum' => 'integer',
'tahun_ad_art' => 'integer',
'unit_usaha' => AsEnumCollection::of(UnitUsahaBumdes::class),
'pengurus_inti' => 'array',
'memiliki_staf' => 'boolean',
'jumlah_staf' => 'integer',
'modal_awal' => 'decimal:2',
'tahun_modal_awal' => 'integer',
'pernah_penambahan_modal' => 'boolean',
'penambahan_modal' => 'array',
'aset_produktif' => 'array',
'infrastruktur_pascapanen' => 'array',
];
}
public static function sectionFields(string $section): array
{
if ($section === 'rantai-nilai') {
return [
'melakukan_pengolahan_pascapanen',
'status_sortasi',
'kriteria_sortasi',
'status_pengeringan',
'cara_tempat_pengeringan',
'status_fermentasi',
'model_fermentasi',
'proses_fermentasi',
'premium_harga_pascapanen',
'melakukan_jual_beli',
'sumber_pasokan',
'sumber_pasokan_lainnya',
'bentuk_produk_dibeli',
'volume_pembelian',
'saluran_penjualan',
'saluran_penjualan_lainnya',
'bentuk_produk_dijual',
'volume_penjualan',
'hubungan_petani_pemasok',
'hubungan_petani_pemasok_lainnya',
'mekanisme_pembayaran_petani',
'mekanisme_pembayaran_lainnya',
'perjanjian_petani',
'harga_beli_petani',
'penetapan_harga_beli',
'penetapan_harga_beli_lainnya',
];
}
if ($section === 'profil') {
return [
'status_keaktifan', 'alasan_tidak_aktif', 'pengurus_inti', 'memiliki_staf',
'jumlah_staf', 'unit_usaha_staf',
];
}
return $section === 'operasional' ? [
'modal_awal', 'tahun_modal_awal',
'pernah_penambahan_modal', 'penambahan_modal', 'aset_produktif',
'aset_produktif_lainnya', 'status_kepemilikan_aset', 'infrastruktur_pascapanen',
'infrastruktur_pascapanen_lainnya',
'ada_alokasi_desa', 'jumlah_alokasi_desa', 'dukungan_desa',
'dukungan_desa_lainnya', 'keterlibatan_koordinasi_desa',
'kemitraan_eksternal', 'kemitraan_eksternal_lainnya',
'status_pembukuan',
'format_pembukuan',
'pernah_audit',
'sifat_audit',
'pelaksana_audit',
'tahun_audit',
'pertanggungjawaban_musdes',
'tahun_laporan_musdes',
'kondisi_keuangan',
'kontribusi_pades',
'nominal_kontribusi_pades',
'cakupan_layanan',
'desa_lain_dilayani',
'jumlah_petani_desa_sendiri',
'jumlah_petani_desa_lain',
'pencatatan_petani',
'layanan_petani',
'layanan_petani_lainnya',
'peran_rantai_nilai',
'pengalaman_offtaker',
'nama_offtaker',
'tahun_mulai_offtaker',
'alasan_berhenti_offtaker',
'hambatan_usaha',
'hambatan_usaha_lainnya',
] : [
'status_badan_hukum', 'nomor_dasar_hukum', 'tahun_dasar_hukum', 'unit_usaha',
'unit_usaha_jasa_lainnya', 'status_unit_komoditas', 'nama_unit_komoditas',
'status_ad_art', 'tahun_ad_art',
];
}
public function pengurusBumdes(): BelongsTo
{
+34 -13
View File
@@ -2,9 +2,10 @@
namespace App\Models\Bumdes;
use App\Models\Concerns\CatatAktivitas;
use App\Enums\Bumdes\JabatanBumdes;
use App\Enums\Pendidikan;
use App\Models\Concerns\CatatAktivitas;
use App\Models\Concerns\HasDeletedBy;
use App\Models\User;
use App\Models\Wilayah\DesaKelurahan;
use Carbon\Carbon;
@@ -15,7 +16,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class PengurusBumdes extends Model
{
use SoftDeletes, CatatAktivitas;
use CatatAktivitas, HasDeletedBy, SoftDeletes;
protected $table = 'bumdes_pengurus';
@@ -38,13 +39,33 @@ class PengurusBumdes extends Model
'deleted_by',
];
protected $casts = [
'jenis_kelamin' => 'boolean',
'tanggal_lahir' => 'date',
'pendidikan_terakhir' => Pendidikan::class,
'tanggal_mulai_menjabat' => 'date',
'jabatan' => JabatanBumdes::class,
];
protected function casts(): array
{
return [
'jenis_kelamin' => 'boolean',
'tanggal_lahir' => 'date',
'pendidikan_terakhir' => Pendidikan::class,
'tanggal_mulai_menjabat' => 'date',
'jabatan' => JabatanBumdes::class,
];
}
protected static function booted(): void
{
static::deleting(function (self $pengurus) {
if (! $pengurus->isForceDeleting()) {
$pengurus->kelembagaanAktor()->each(fn ($data) => $data->delete());
}
});
}
public function profilLengkap(): bool
{
return $this->exists && collect([
'nama', 'tempat_lahir', 'tanggal_lahir', 'pendidikan_terakhir', 'alamat',
'desa_kelurahan_id', 'jabatan', 'lama_menjabat_tahun',
])->every(fn ($field) => filled($this->{$field})) && $this->jenis_kelamin !== null;
}
public function getUsiaAttribute(): ?int
{
@@ -58,7 +79,7 @@ class PengurusBumdes extends Model
public function getLamaMenjabatAttribute(): string
{
if (! is_null($this->lama_menjabat_tahun)) {
return $this->lama_menjabat_tahun . ' tahun';
return $this->lama_menjabat_tahun.' tahun';
}
if (! $this->tanggal_mulai_menjabat) {
@@ -75,15 +96,15 @@ class PengurusBumdes extends Model
$bagian = [];
if ($selisih->y > 0) {
$bagian[] = $selisih->y . ' tahun';
$bagian[] = $selisih->y.' tahun';
}
if ($selisih->m > 0) {
$bagian[] = $selisih->m . ' bulan';
$bagian[] = $selisih->m.' bulan';
}
if (empty($bagian)) {
return $selisih->d . ' hari';
return $selisih->d.' hari';
}
return implode(' ', $bagian);
@@ -0,0 +1,633 @@
<?php
namespace App\Services\Bumdes;
use App\Enums\Bumdes\AsetProduktifBumdes;
use App\Enums\Bumdes\BentukProdukBumdes;
use App\Enums\Bumdes\CakupanLayananBumdes;
use App\Enums\Bumdes\DukunganDesaBumdes;
use App\Enums\Bumdes\FormatPembukuanBumdes;
use App\Enums\Bumdes\HambatanUsahaBumdes;
use App\Enums\Bumdes\HubunganPemasokBumdes;
use App\Enums\Bumdes\InfrastrukturPascapanenBumdes;
use App\Enums\Bumdes\JabatanBumdes;
use App\Enums\Bumdes\JabatanPengurusIntiBumdes;
use App\Enums\Bumdes\KemitraanEksternalBumdes;
use App\Enums\Bumdes\KeterlibatanKoordinasiBumdes;
use App\Enums\Bumdes\KondisiAsetProduktifBumdes;
use App\Enums\Bumdes\KondisiInfrastrukturBumdes;
use App\Enums\Bumdes\KondisiKeuanganBumdes;
use App\Enums\Bumdes\KontribusiPadesBumdes;
use App\Enums\Bumdes\LayananPetaniBumdes;
use App\Enums\Bumdes\MekanismePembayaranBumdes;
use App\Enums\Bumdes\ModelFermentasiBumdes;
use App\Enums\Bumdes\PencatatanPetaniBumdes;
use App\Enums\Bumdes\PenetapanHargaBeliBumdes;
use App\Enums\Bumdes\PengalamanOfftakerBumdes;
use App\Enums\Bumdes\PeranRantaiNilaiBumdes;
use App\Enums\Bumdes\PeriodePanenBumdes;
use App\Enums\Bumdes\PerjanjianPetaniBumdes;
use App\Enums\Bumdes\PertanggungjawabanMusdesBumdes;
use App\Enums\Bumdes\SaluranPenjualanBumdes;
use App\Enums\Bumdes\SifatAuditBumdes;
use App\Enums\Bumdes\StatusAdArtBumdes;
use App\Enums\Bumdes\StatusBadanHukumBumdes;
use App\Enums\Bumdes\StatusFermentasiBumdes;
use App\Enums\Bumdes\StatusKeaktifanBumdes;
use App\Enums\Bumdes\StatusKepemilikanAsetBumdes;
use App\Enums\Bumdes\StatusPembukuanBumdes;
use App\Enums\Bumdes\StatusPengeringanBumdes;
use App\Enums\Bumdes\StatusSortasiBumdes;
use App\Enums\Bumdes\StatusUnitKomoditasBumdes;
use App\Enums\Bumdes\SumberPasokanBumdes;
use App\Enums\Bumdes\UnitUsahaBumdes;
use App\Enums\Pendidikan;
use App\Enums\Role;
use App\Models\Bumdes\KelembagaanAktorBumdes;
use App\Models\Bumdes\PengurusBumdes;
use App\Models\Wilayah\DesaKelurahan;
use App\Models\Wilayah\KabupatenKota;
use App\Models\Wilayah\Kecamatan;
use App\Models\Wilayah\Provinsi;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class PengurusBumdesService
{
// BUMDes memakai seluruh master wilayah, termasuk wilayah di luar lokasi program aktif.
public function indexData(array $validated): array
{
$defaultKabupaten = KabupatenKota::withoutGlobalScope('program')->select('id', 'nama')
->whereRaw('lower(nama) like ?', ['%ngada%'])->orderBy('nama')->first();
$filters = [
'search' => $validated['search'] ?? null,
'kabupaten_kota_id' => $validated['kabupaten_kota_id'] ?? $defaultKabupaten?->id,
'kecamatan_id' => $validated['kecamatan_id'] ?? null,
'desa_kelurahan_id' => $validated['desa_kelurahan_id'] ?? null,
'status_keaktifan' => $validated['status_keaktifan'] ?? null,
'sort_by' => in_array($validated['sort_by'] ?? null, ['nama_asc', 'nama_desc'], true)
? $validated['sort_by'] : null,
];
$query = $this->pengurusQuery()->with([
...$this->wilayahRelationsWithoutProgramScope(),
'creator:id,name',
'kelembagaanAktor',
]);
if (filled($filters['search'])) {
$search = '%'.Str::lower($filters['search']).'%';
$query->where(function ($query) use ($search) {
$query->whereRaw('lower(nama) like ?', [$search])
->orWhereHas('desaKelurahan', function ($query) use ($search) {
$query->withoutGlobalScope('program')->where(function ($query) use ($search) {
$query->whereRaw('lower(nama) like ?', [$search])
->orWhereHas('kecamatan', fn ($query) => $query->withoutGlobalScope('program')->whereRaw('lower(nama) like ?', [$search]));
});
});
});
}
$query->when($filters['kabupaten_kota_id'], function ($query, $id) {
$query->whereHas('desaKelurahan', function ($query) use ($id) {
$query->withoutGlobalScope('program')->whereHas('kecamatan', function ($query) use ($id) {
$query->withoutGlobalScope('program')->where('kabupaten_kota_id', $id);
});
});
})->when($filters['kecamatan_id'], function ($query, $id) {
$query->whereHas('desaKelurahan', fn ($query) => $query->withoutGlobalScope('program')->where('kecamatan_id', $id));
})->when($filters['desa_kelurahan_id'], fn ($query, $id) => $query->where('desa_kelurahan_id', $id));
$query->when($filters['status_keaktifan'], fn ($query, $value) => $query
->whereHas('kelembagaanAktor', fn ($query) => $query->where('status_keaktifan', $value)));
$summaryQuery = clone $query;
$totalBumdes = (clone $summaryQuery)->count();
$totalBumdesAktif = (clone $summaryQuery)->whereHas('kelembagaanAktor', fn ($query) => $query
->whereIn('status_keaktifan', [StatusKeaktifanBumdes::AKTIF_PENUH->value, StatusKeaktifanBumdes::AKTIF_TERBATAS->value]))->count();
$totalBerbadanHukum = (clone $summaryQuery)->whereHas('kelembagaanAktor', fn ($query) => $query
->where('status_badan_hukum', StatusBadanHukumBumdes::SUDAH_BERBADAN_HUKUM->value))->count();
$totalDesaKelurahan = (clone $summaryQuery)->distinct('desa_kelurahan_id')->count('desa_kelurahan_id');
if ($filters['sort_by']) {
$namaDesa = DesaKelurahan::withoutGlobalScope('program')->select('nama')
->whereColumn('master_desa_kelurahan.id', 'bumdes_pengurus.desa_kelurahan_id')->limit(1);
$query->orderBy($namaDesa, $filters['sort_by'] === 'nama_asc' ? 'asc' : 'desc');
} else {
$query->latest();
}
$perPage = (int) ($validated['per_page'] ?? 10);
$pengurus = $query->orderByDesc('id')->paginate($perPage)->appends([...$filters, 'per_page' => $perPage]);
$ringkasanBumdes = $pengurus->getCollection()
->mapWithKeys(fn (PengurusBumdes $item) => [$item->id => $this->profileSummary($item)]);
$selectedKabupaten = $filters['kabupaten_kota_id']
? KabupatenKota::withoutGlobalScope('program')->select('id', 'nama')->find($filters['kabupaten_kota_id']) : null;
$kecamatanOptions = $filters['kabupaten_kota_id']
? Kecamatan::withoutGlobalScope('program')->select('id', 'nama')->where('kabupaten_kota_id', $filters['kabupaten_kota_id'])->orderBy('nama')->get()
: collect();
$desaOptions = $filters['kecamatan_id']
? DesaKelurahan::withoutGlobalScope('program')->select('id', 'nama')->where('kecamatan_id', $filters['kecamatan_id'])->orderBy('nama')->get()
: collect();
$statusKeaktifanOptions = StatusKeaktifanBumdes::options();
$userRole = auth()->user()->role->value;
$showEnumerator = in_array($userRole, ['super_admin', 'admin']);
return compact(
'pengurus',
'ringkasanBumdes',
'totalBumdes',
'totalBumdesAktif',
'totalBerbadanHukum',
'totalDesaKelurahan',
'showEnumerator', 'filters', 'selectedKabupaten', 'kecamatanOptions', 'desaOptions',
'statusKeaktifanOptions'
);
}
public function profileData(?PengurusBumdes $pengurus = null): array
{
$pengurus?->loadMissing([...$this->wilayahRelationsWithoutProgramScope(), 'kelembagaanAktor']);
return [
'pengurus' => $pengurus,
'ringkasanProfil' => $this->profileSummary($pengurus),
'provinsi' => $this->provinsiOptions(),
'jabatan' => JabatanBumdes::options(),
'pendidikan' => Pendidikan::options(),
...$this->profileLocationOptions($pengurus),
...$this->profileBumdesOptions($pengurus),
];
}
public function sectionData(PengurusBumdes $pengurus): array
{
$pengurus->loadMissing([...$this->wilayahRelationsWithoutProgramScope(), 'kelembagaanAktor']);
return [
'pengurus' => $pengurus,
'ringkasanProfil' => $this->profileSummary($pengurus),
'kelembagaanAktor' => $pengurus->kelembagaanAktor?->attributesToArray(),
...$this->kelembagaanAktorOptions(),
];
}
private function profileSummary(?PengurusBumdes $pengurus): array
{
$data = $pengurus?->kelembagaanAktor;
$desa = $pengurus?->desaKelurahan;
$keaktifan = $data?->status_keaktifan;
$hukum = $data?->status_badan_hukum;
$unitUsaha = collect($data?->unit_usaha ?? [])->map(function (UnitUsahaBumdes $unit) use ($data) {
return $unit === UnitUsahaBumdes::JASA_LAINNYA && filled($data->unit_usaha_jasa_lainnya)
? $unit->label().': '.$data->unit_usaha_jasa_lainnya : $unit->label();
})->all();
$updatedAt = collect([
$pengurus?->updated_at ?? $pengurus?->created_at,
$data?->updated_at ?? $data?->created_at,
])->filter()->sortByDesc(fn ($date) => $date->getTimestamp())->first();
return [
'judul' => $pengurus
? ($desa?->nama ? 'BUMDes · '.$desa->nama : 'Profil BUMDes') : 'Profil BUMDes Baru',
'lokasi' => collect([
$desa?->kecamatan?->nama, $desa?->kecamatan?->kabupatenKota?->nama,
$desa?->kecamatan?->kabupatenKota?->provinsi?->nama,
])->filter(fn ($value) => filled($value))->implode(' · ') ?: 'Lokasi belum terisi',
'alamat' => $pengurus?->alamat ?: 'Belum terisi',
'keaktifan' => [
'label' => $keaktifan?->label() ?? 'Belum terisi',
'warna' => match ($keaktifan) {
StatusKeaktifanBumdes::AKTIF_PENUH => 'success',
StatusKeaktifanBumdes::AKTIF_TERBATAS => 'warning',
StatusKeaktifanBumdes::TIDAK_AKTIF_VAKUM => 'danger',
default => 'secondary',
},
],
'hukum' => [
'label' => $hukum?->label() ?? 'Belum terisi',
'warna' => match ($hukum) {
StatusBadanHukumBumdes::SUDAH_BERBADAN_HUKUM => 'success',
StatusBadanHukumBumdes::PROSES_PENDAFTARAN => 'warning',
default => 'secondary',
},
],
'unit_usaha' => $unitUsaha,
'responden' => $pengurus?->nama ?: 'Belum terisi',
'jabatan' => $pengurus ? $pengurus->nama_jabatan : 'Belum terisi',
'nomor_telepon' => $pengurus?->nomor_telepon ?: 'Belum terisi',
'diperbarui' => $updatedAt,
];
}
public function storeProfile(array $data): PengurusBumdes
{
return DB::transaction(function () use ($data) {
$pengurus = PengurusBumdes::create([
...$this->respondentData($data),
'uid' => 'BMD-'.strtoupper(Str::random(10)),
'created_by' => auth()->id(), 'updated_by' => auth()->id(),
]);
$this->saveSection($pengurus, $data, 'profil');
return $pengurus;
});
}
public function updateProfile(PengurusBumdes $pengurus, array $data): void
{
DB::transaction(function () use ($pengurus, $data) {
$pengurus->update([...$this->respondentData($data), 'updated_by' => auth()->id()]);
$this->saveSection($pengurus, $data, 'profil');
});
}
private function respondentData(array $data): array
{
$data = array_intersect_key($data, array_flip([
'nama', 'jenis_kelamin', 'tempat_lahir', 'tanggal_lahir', 'pendidikan_terakhir',
'alamat', 'desa_kelurahan_id', 'nomor_telepon', 'jabatan', 'jabatan_lainnya', 'lama_menjabat_tahun',
]));
return $this->formatData($data);
}
public function saveSection(PengurusBumdes $pengurus, array $validatedData, string $section): void
{
$data = array_intersect_key(
$section === 'rantai-nilai' ? $this->formatRantaiNilaiData($validatedData) : $this->formatKelembagaanAktorData($validatedData),
array_flip(KelembagaanAktorBumdes::sectionFields($section))
);
// Kolom kepemilikan lama tetap dipertahankan untuk data sebelum kepemilikan dipisah per aset.
if ($section === 'operasional' && ! array_key_exists('status_kepemilikan_aset', $validatedData)) {
unset($data['status_kepemilikan_aset']);
}
KelembagaanAktorBumdes::updateOrCreate(
['pengurus_bumdes_id' => $pengurus->id],
[
...$data,
'created_by' => $pengurus->kelembagaanAktor?->created_by ?? auth()->id(),
'updated_by' => auth()->id(),
]
);
}
private function profileBumdesOptions(?PengurusBumdes $pengurus = null): array
{
return [
'kelembagaanAktor' => $pengurus?->kelembagaanAktor?->attributesToArray(),
'statusKeaktifanOptions' => StatusKeaktifanBumdes::options(),
'pengurusIntiRows' => JabatanPengurusIntiBumdes::options(),
];
}
private function pengurusQuery()
{
$query = PengurusBumdes::query();
if (auth()->user()->role === Role::ENUMERATOR) {
$query->where('created_by', auth()->id());
}
return $query;
}
// Master wilayah BUMDes tidak dibatasi lokasi program, sama seperti halaman profilnya.
private function provinsiOptions()
{
return Provinsi::withoutGlobalScope('program')
->select('id', 'kode', 'nama')
->orderBy('kode', 'asc')
->get();
}
private function wilayahRelationsWithoutProgramScope(): array
{
return [
'desaKelurahan' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama', 'kecamatan_id'),
'desaKelurahan.kecamatan' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama', 'kabupaten_kota_id'),
'desaKelurahan.kecamatan.kabupatenKota' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama', 'provinsi_id'),
'desaKelurahan.kecamatan.kabupatenKota.provinsi' => fn ($query) => $query->withoutGlobalScope('program')->select('id', 'nama'),
];
}
private function profileLocationOptions(?PengurusBumdes $pengurus = null): array
{
$locationId = static fn ($value) => is_scalar($value) && filter_var($value, FILTER_VALIDATE_INT) !== false ? (int) $value : null;
$provinsiId = $locationId(old('provinsi_id', $pengurus?->desaKelurahan?->kecamatan?->kabupatenKota?->provinsi_id));
$kabupatenId = $locationId(old('kabupaten_id', $pengurus?->desaKelurahan?->kecamatan?->kabupaten_kota_id));
$kecamatanId = $locationId(old('kecamatan_id', $pengurus?->desaKelurahan?->kecamatan_id));
return [
'kabupatenOptions' => $provinsiId ? KabupatenKota::withoutGlobalScope('program')->where('provinsi_id', $provinsiId)->orderBy('nama')->get() : collect(),
'kecamatanOptions' => $kabupatenId ? Kecamatan::withoutGlobalScope('program')->where('kabupaten_kota_id', $kabupatenId)->orderBy('nama')->get() : collect(),
'desaOptions' => $kecamatanId ? DesaKelurahan::withoutGlobalScope('program')->where('kecamatan_id', $kecamatanId)->orderBy('nama')->get() : collect(),
];
}
private function formatData(array $data): array
{
$data['tanggal_lahir'] = Carbon::createFromFormat('d-m-Y', $data['tanggal_lahir'])->format('Y-m-d');
$data['tanggal_mulai_menjabat'] = Carbon::now()
->subYears((int) $data['lama_menjabat_tahun'])
->format('Y-m-d');
if (($data['jabatan'] ?? null) !== JabatanBumdes::LAINNYA->value) {
$data['jabatan_lainnya'] = null;
}
return $data;
}
private function formatRantaiNilaiData(array $data): array
{
$defaults = array_fill_keys(KelembagaanAktorBumdes::sectionFields('rantai-nilai'), null);
foreach (['sumber_pasokan', 'bentuk_produk_dibeli', 'volume_pembelian', 'saluran_penjualan', 'bentuk_produk_dijual', 'volume_penjualan', 'hubungan_petani_pemasok', 'harga_beli_petani'] as $field) {
$defaults[$field] = [];
}
$postharvest = $this->formatPascapanenData($data);
$defaults['melakukan_jual_beli'] = in_array($data['melakukan_jual_beli'] ?? null, [true, 1, '1'], true);
if (! $defaults['melakukan_jual_beli']) {
return array_replace($defaults, $postharvest);
}
$payload = array_replace($defaults, $data);
foreach (['sumber_pasokan', 'bentuk_produk_dibeli', 'saluran_penjualan', 'bentuk_produk_dijual', 'hubungan_petani_pemasok'] as $field) {
$payload[$field] = array_values($payload[$field] ?? []);
}
foreach (['sumber_pasokan' => 'sumber_pasokan_lainnya', 'saluran_penjualan' => 'saluran_penjualan_lainnya', 'hubungan_petani_pemasok' => 'hubungan_petani_pemasok_lainnya'] as $field => $other) {
if (! in_array('lainnya', $payload[$field], true)) {
$payload[$other] = null;
}
}
if ($payload['mekanisme_pembayaran_petani'] !== MekanismePembayaranBumdes::LAINNYA->value) {
$payload['mekanisme_pembayaran_lainnya'] = null;
}
if ($payload['penetapan_harga_beli'] !== PenetapanHargaBeliBumdes::LAINNYA->value) {
$payload['penetapan_harga_beli_lainnya'] = null;
}
$periods = array_keys(PeriodePanenBumdes::options());
foreach (['volume_pembelian', 'volume_penjualan'] as $field) {
$payload[$field] = collect($payload[$field] ?? [])->only($periods)->filter(fn ($value) => $value !== null && $value !== '')->all();
}
if (in_array(SaluranPenjualanBumdes::BELUM_MENJUAL->value, $payload['saluran_penjualan'], true)) {
$payload['bentuk_produk_dijual'] = [];
$payload['volume_penjualan'] = [];
}
$payload['harga_beli_petani'] = collect($payload['harga_beli_petani'] ?? [])->only($payload['bentuk_produk_dibeli'])
->map(fn ($row) => collect($row)->only($periods)->filter(fn ($value) => $value !== null && $value !== '')->all())
->filter(fn ($row) => count($row) > 0)->all();
return array_replace($payload, $postharvest);
}
private function formatPascapanenData(array $data): array
{
$processing = in_array($data['melakukan_pengolahan_pascapanen'] ?? null, [true, 1, '1'], true);
$payload = [
'melakukan_pengolahan_pascapanen' => ($data['melakukan_pengolahan_pascapanen'] ?? null) === null ? null : $processing,
'status_sortasi' => null, 'kriteria_sortasi' => null,
'status_pengeringan' => null, 'cara_tempat_pengeringan' => null,
'status_fermentasi' => null, 'model_fermentasi' => [],
'proses_fermentasi' => null, 'premium_harga_pascapanen' => null,
];
if (! $processing) {
return $payload;
}
$payload = array_replace($payload, array_intersect_key($data, $payload));
if (! in_array($payload['status_sortasi'], [StatusSortasiBumdes::RUTIN_STANDAR->value, StatusSortasiBumdes::TIDAK_KONSISTEN->value], true)) {
$payload['kriteria_sortasi'] = null;
}
if (! in_array($payload['status_pengeringan'], [StatusPengeringanBumdes::RUTIN->value, StatusPengeringanBumdes::KADANG->value], true)) {
$payload['cara_tempat_pengeringan'] = null;
}
if (! in_array($payload['status_fermentasi'], [StatusFermentasiBumdes::RUTIN->value, StatusFermentasiBumdes::PERNAH_MENCOBA->value], true)) {
$payload['model_fermentasi'] = [];
$payload['proses_fermentasi'] = null;
}
$payload['model_fermentasi'] = array_values($payload['model_fermentasi'] ?? []);
return $payload;
}
private function formatKelembagaanAktorData(array $data): array
{
$payload = array_merge([
'status_badan_hukum' => null,
'nomor_dasar_hukum' => null,
'tahun_dasar_hukum' => null,
'status_keaktifan' => null,
'alasan_tidak_aktif' => null,
'unit_usaha' => [],
'unit_usaha_jasa_lainnya' => null,
'status_unit_komoditas' => null,
'nama_unit_komoditas' => null,
'status_ad_art' => null,
'tahun_ad_art' => null,
'pengurus_inti' => [],
'memiliki_staf' => null,
'jumlah_staf' => null,
'unit_usaha_staf' => null,
'modal_awal' => null,
'tahun_modal_awal' => null,
'pernah_penambahan_modal' => null,
'penambahan_modal' => [],
'aset_produktif' => [],
'aset_produktif_lainnya' => null,
'status_kepemilikan_aset' => null,
'infrastruktur_pascapanen' => [],
'infrastruktur_pascapanen_lainnya' => null,
'status_pembukuan' => null,
'format_pembukuan' => null,
'pernah_audit' => null,
'sifat_audit' => [],
'pelaksana_audit' => null,
'tahun_audit' => null,
'pertanggungjawaban_musdes' => null,
'tahun_laporan_musdes' => null,
'kondisi_keuangan' => null,
'kontribusi_pades' => null,
'nominal_kontribusi_pades' => null,
'cakupan_layanan' => null,
'desa_lain_dilayani' => null,
'jumlah_petani_desa_sendiri' => null,
'jumlah_petani_desa_lain' => null,
'pencatatan_petani' => null,
'layanan_petani' => [],
'layanan_petani_lainnya' => null,
'peran_rantai_nilai' => null,
'pengalaman_offtaker' => null,
'nama_offtaker' => null,
'tahun_mulai_offtaker' => null,
'alasan_berhenti_offtaker' => null,
'hambatan_usaha' => [],
'hambatan_usaha_lainnya' => null,
'ada_alokasi_desa' => null,
'jumlah_alokasi_desa' => null,
'dukungan_desa' => [],
'dukungan_desa_lainnya' => null,
'keterlibatan_koordinasi_desa' => null,
'kemitraan_eksternal' => [],
'kemitraan_eksternal_lainnya' => null,
], $data);
foreach (['sifat_audit', 'layanan_petani', 'hambatan_usaha'] as $field) {
$payload[$field] = array_values($payload[$field] ?? []);
}
if (! (bool) $payload['pernah_audit']) {
$payload['sifat_audit'] = [];
$payload['pelaksana_audit'] = null;
$payload['tahun_audit'] = null;
}
if ($payload['pertanggungjawaban_musdes'] !== PertanggungjawabanMusdesBumdes::TAHUNAN->value) {
$payload['tahun_laporan_musdes'] = null;
}
if (! in_array($payload['kontribusi_pades'], [KontribusiPadesBumdes::RUTIN->value, KontribusiPadesBumdes::TIDAK_RUTIN->value], true)) {
$payload['nominal_kontribusi_pades'] = null;
}
if ($payload['cakupan_layanan'] !== CakupanLayananBumdes::DESA_LAIN->value) {
$payload['desa_lain_dilayani'] = null;
$payload['jumlah_petani_desa_lain'] = null;
}
if (! in_array(LayananPetaniBumdes::LAINNYA->value, $payload['layanan_petani'], true)) {
$payload['layanan_petani_lainnya'] = null;
}
if (! in_array(HambatanUsahaBumdes::LAINNYA->value, $payload['hambatan_usaha'], true)) {
$payload['hambatan_usaha_lainnya'] = null;
}
if ($payload['pengalaman_offtaker'] !== PengalamanOfftakerBumdes::BERJALAN->value) {
$payload['nama_offtaker'] = null;
$payload['tahun_mulai_offtaker'] = null;
}
if ($payload['pengalaman_offtaker'] !== PengalamanOfftakerBumdes::BERHENTI->value) {
$payload['alasan_berhenti_offtaker'] = null;
}
$payload['dukungan_desa'] = array_values($payload['dukungan_desa'] ?? []);
$payload['kemitraan_eksternal'] = array_values($payload['kemitraan_eksternal'] ?? []);
if (! (bool) $payload['ada_alokasi_desa']) {
$payload['jumlah_alokasi_desa'] = null;
}
if (! in_array(DukunganDesaBumdes::LAINNYA->value, $payload['dukungan_desa'], true)) {
$payload['dukungan_desa_lainnya'] = null;
}
if (! in_array(KemitraanEksternalBumdes::LAINNYA->value, $payload['kemitraan_eksternal'], true)) {
$payload['kemitraan_eksternal_lainnya'] = null;
}
$payload['unit_usaha'] = array_values($payload['unit_usaha'] ?? []);
$payload['pengurus_inti'] = $this->filterRows($payload['pengurus_inti'] ?? [], ['nama']);
$payload['penambahan_modal'] = $this->filterRows($payload['penambahan_modal'] ?? [], ['tahun', 'jumlah']);
foreach (['aset_produktif', 'infrastruktur_pascapanen'] as $field) {
$payload[$field] = collect($payload[$field] ?? [])
->filter(fn ($row) => in_array($row['dipilih'] ?? null, [true, 1, '1'], true))
->values()->all();
}
if (($payload['status_badan_hukum'] ?? null) !== 'sudah_berbadan_hukum') {
$payload['nomor_dasar_hukum'] = null;
$payload['tahun_dasar_hukum'] = null;
}
if (($payload['status_keaktifan'] ?? null) !== 'tidak_aktif_vakum') {
$payload['alasan_tidak_aktif'] = null;
}
if (! in_array('jasa_lainnya', $payload['unit_usaha'], true)) {
$payload['unit_usaha_jasa_lainnya'] = null;
}
if (($payload['status_unit_komoditas'] ?? null) !== 'ya') {
$payload['nama_unit_komoditas'] = null;
}
if (($payload['status_ad_art'] ?? null) !== 'ada_lengkap') {
$payload['tahun_ad_art'] = null;
}
if (! (bool) ($payload['memiliki_staf'] ?? false)) {
$payload['jumlah_staf'] = null;
$payload['unit_usaha_staf'] = null;
}
if (! (bool) ($payload['pernah_penambahan_modal'] ?? false)) {
$payload['penambahan_modal'] = null;
}
if (! collect($payload['aset_produktif'] ?? [])->contains(fn ($row) => ($row['aset'] ?? null) === 'lainnya')) {
$payload['aset_produktif_lainnya'] = null;
}
if (! collect($payload['infrastruktur_pascapanen'] ?? [])->contains(fn ($row) => ($row['infrastruktur'] ?? null) === 'lainnya')) {
$payload['infrastruktur_pascapanen_lainnya'] = null;
}
return $payload;
}
private function filterRows(array $rows, array $valueKeys): array
{
return collect($rows)
->map(function ($row) {
return collect($row)
->map(fn ($value) => $value === '' ? null : $value)
->all();
})
->filter(function ($row) use ($valueKeys) {
foreach ($valueKeys as $key) {
if (filled($row[$key] ?? null)) {
return true;
}
}
return false;
})
->values()
->all();
}
private function kelembagaanAktorOptions(): array
{
return [
'statusSortasiOptions' => StatusSortasiBumdes::options(),
'statusPengeringanOptions' => StatusPengeringanBumdes::options(),
'statusFermentasiOptions' => StatusFermentasiBumdes::options(),
'modelFermentasiOptions' => ModelFermentasiBumdes::options(),
'sumberPasokanOptions' => SumberPasokanBumdes::options(),
'bentukProdukOptions' => BentukProdukBumdes::options(),
'periodePanenOptions' => PeriodePanenBumdes::options(),
'saluranPenjualanOptions' => SaluranPenjualanBumdes::options(),
'hubunganPemasokOptions' => HubunganPemasokBumdes::options(),
'mekanismePembayaranOptions' => MekanismePembayaranBumdes::options(),
'perjanjianPetaniOptions' => PerjanjianPetaniBumdes::options(),
'penetapanHargaBeliOptions' => PenetapanHargaBeliBumdes::options(),
'statusBadanHukumOptions' => StatusBadanHukumBumdes::options(),
'statusKeaktifanOptions' => StatusKeaktifanBumdes::options(),
'unitUsahaOptions' => UnitUsahaBumdes::options(),
'statusUnitKomoditasOptions' => StatusUnitKomoditasBumdes::options(),
'statusAdArtOptions' => StatusAdArtBumdes::options(),
'pengurusIntiRows' => JabatanPengurusIntiBumdes::options(),
'asetProduktifRows' => AsetProduktifBumdes::options(),
'kondisiAsetProduktifOptions' => KondisiAsetProduktifBumdes::options(),
'statusKepemilikanAsetOptions' => StatusKepemilikanAsetBumdes::options(),
'infrastrukturPascapanenRows' => InfrastrukturPascapanenBumdes::options(),
'statusPembukuanOptions' => StatusPembukuanBumdes::options(),
'formatPembukuanOptions' => FormatPembukuanBumdes::options(),
'sifatAuditOptions' => SifatAuditBumdes::options(),
'pertanggungjawabanMusdesOptions' => PertanggungjawabanMusdesBumdes::options(),
'kondisiKeuanganOptions' => KondisiKeuanganBumdes::options(),
'kontribusiPadesOptions' => KontribusiPadesBumdes::options(),
'cakupanLayananOptions' => CakupanLayananBumdes::options(),
'pencatatanPetaniOptions' => PencatatanPetaniBumdes::options(),
'layananPetaniOptions' => LayananPetaniBumdes::options(),
'peranRantaiNilaiOptions' => PeranRantaiNilaiBumdes::options(),
'pengalamanOfftakerOptions' => PengalamanOfftakerBumdes::options(),
'hambatanUsahaOptions' => HambatanUsahaBumdes::options(),
'dukunganDesaOptions' => DukunganDesaBumdes::options(),
'keterlibatanKoordinasiOptions' => KeterlibatanKoordinasiBumdes::options(),
'kemitraanEksternalOptions' => KemitraanEksternalBumdes::options(),
'kondisiInfrastrukturOptions' => KondisiInfrastrukturBumdes::options(),
];
}
}