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
+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 {}