Files
database-pertani-web/app/Http/Requests/Bumdes/StoreOperasionalBumdesRequest.php
T
2026-11-05 19:20:05 +07:00

253 lines
16 KiB
PHP

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