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', ]; } }