|
|
|
@@ -0,0 +1,466 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Services\Produktivitas;
|
|
|
|
|
|
|
|
|
|
use App\Enums\AksesPasar\PraktikFermentasi;
|
|
|
|
|
use App\Enums\PraktikBudidaya\MetodePenangananHamaPenyakit;
|
|
|
|
|
use App\Enums\PraktikBudidaya\PemberianPupuk;
|
|
|
|
|
use App\Enums\SosialEkonomi\TerdaftarKelompokTani;
|
|
|
|
|
use App\Models\Pertanian\Lahan;
|
|
|
|
|
use App\Models\Pertanian\Petani;
|
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Daftar isian Profil Petani yang WAJIB (dipakai skor Kesiapan Adopsi)
|
|
|
|
|
* dan PERLU (dipakai dashboard Karakteristik, Produksi, Pasar).
|
|
|
|
|
*
|
|
|
|
|
* Satu-satunya tempat daftar ini ditulis. Dipakai oleh ringkasan kelengkapan
|
|
|
|
|
* di atas setiap tab petani, dan nanti oleh fitur verifikasi.
|
|
|
|
|
*
|
|
|
|
|
* Isian yang tidak berlaku (mis. jenis hama kalau "tidak ada hama",
|
|
|
|
|
* data kelompok kalau bukan anggota) tidak dimasukkan.
|
|
|
|
|
*/
|
|
|
|
|
class KelengkapanPetani
|
|
|
|
|
{
|
|
|
|
|
public const WAJIB = 'wajib';
|
|
|
|
|
public const PERLU = 'perlu';
|
|
|
|
|
|
|
|
|
|
public const TAB_LABEL = [
|
|
|
|
|
'profil' => 'Profil',
|
|
|
|
|
'lahan' => 'Lahan & Tanaman',
|
|
|
|
|
'praktik-budidaya' => 'Praktik Budidaya',
|
|
|
|
|
'sosial-ekonomi' => 'Sosial Ekonomi',
|
|
|
|
|
'akses-pasar' => 'Akses Pasar',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
private const KONSERVASI_TIDAK_ADA = 'Tidak ada yang seperti itu di kebun saya';
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Seluruh isian Profil Petani (total 209 untuk 1 lahan), per tabel.
|
|
|
|
|
* Aturan hitung: satu pertanyaan = satu isian; kolom repeater dihitung sekali per kolom;
|
|
|
|
|
* teks "Lainnya" tidak dihitung; provinsi/kabupaten/kecamatan ikut terisi bila desa terisi.
|
|
|
|
|
*/
|
|
|
|
|
private const ISIAN_PROFIL = [ // 15 + 3 wilayah = 18
|
|
|
|
|
'nama', 'nomor_telepon', 'alamat', 'kk', 'ktp', 'path_kk', 'path_ktp', 'foto',
|
|
|
|
|
'jenis_kelamin', 'tempat_lahir', 'tanggal_lahir', 'pendidikan_terakhir', 'status_perkawinan',
|
|
|
|
|
'komoditas_id', 'desa_kelurahan_id',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
private const ISIAN_LAHAN = [ // 18 + 3 wilayah = 21, per lahan
|
|
|
|
|
'desa_kelurahan_id', 'path', 'luas_lahan', 'komoditas_id', 'jenis_komoditas_id', 'varietas_id',
|
|
|
|
|
'jumlah_tanaman', 'kondisi_tanaman', 'serangan_hama', 'penyakit_tanaman', 'keparahan_serangan',
|
|
|
|
|
'jenis_hama', 'jenis_penyakit', 'umur_tanaman', 'umur_lahan', 'komoditas_lain', 'tanaman_penaung', 'foto',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
private const ISIAN_PRAKTIK_BUDIDAYA = [ // 39
|
|
|
|
|
'tenaga_kerja', 'frekuensi_pemangkasan_utama', 'teknik_pemangkasan', 'frekuensi_pemangkasan_penaung',
|
|
|
|
|
'penyerbukan_manual', 'deskripsi_penyerbukan_manual', 'tingkat_keberhasilan_penyerbukan',
|
|
|
|
|
'pemberian_pupuk', 'jenis_pupuk', 'frekuensi_pemberian_pupuk', 'estimasi_dosis_pupuk_organik',
|
|
|
|
|
'estimasi_dosis_pupuk_anorganik', 'waktu_pemberian_pupuk', 'cara_pemberian_pupuk',
|
|
|
|
|
'metode_penanganan_opt', 'jenis_hama', 'jenis_penyakit', 'intensitas_serangan', 'waktu_kemunculan_terparah',
|
|
|
|
|
'metode_paling_sering_dilakukan', 'volume_obat_obatan_padat_permusim', 'volume_obat_obatan_cair_permusim',
|
|
|
|
|
'frekuensi_sanitasi_lahan', 'penanganan_sisa_buah_ranting', 'penanganan_gulma',
|
|
|
|
|
'kondisi_pengelolaan_air', 'sumber_air', 'sistem_irigasi', 'kebutuhan_air_permusim',
|
|
|
|
|
'kebiasaan_konservasi_tanah', 'pemahaman_manfaat_konservasi_tanah',
|
|
|
|
|
'upah_tenaga_kerja', 'biaya_bibit', 'biaya_pupuk', 'biaya_obat_obatan', 'biaya_sewa_alat_produksi',
|
|
|
|
|
'biaya_penyediaan_air', 'biaya_produksi_lainnya', 'total_estimasi_biaya_produksi',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
private const ISIAN_PANEN = [ // 21
|
|
|
|
|
'dasar_penentuan_panen', 'frekuensi_panen_pertahun', 'bulan_panen_utama', 'hasil_komoditas_utama_permusim',
|
|
|
|
|
'hasil_komoditas_lainnya_permusim', 'disimpan_untuk_sendiri', 'hasil_panen_disimpan', 'tujuan_disimpan',
|
|
|
|
|
'praktik_sortasi', 'bentuk_sortasi', 'hasil_panen_reject', 'jumlah_panen_reject', 'tindakan_panen_reject',
|
|
|
|
|
'upah_tenaga_panen', 'biaya_pengangkutan_panen', 'biaya_wadah_panen', 'biaya_sewa_alat_panen',
|
|
|
|
|
'biaya_panen_lainnya', 'total_estimasi_biaya_panen', 'estimasi_kehilangan_akibat_opt',
|
|
|
|
|
'estimasi_kehilangan_akibat_hama_penyakit',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
private const ISIAN_PRODUKTIVITAS = ['komoditas_id', 'kuantitas', 'satuan']; // 3 (repeater)
|
|
|
|
|
private const ISIAN_PELATIHAN = ['jenis_pelatihan', 'penyelenggara', 'tahun_pelaksanaan']; // 3 (repeater)
|
|
|
|
|
private const ISIAN_SERTIFIKASI = ['jenis_sertifikasi', 'lembaga_penerbit', 'tahun_pelaksanaan', 'is_aktif']; // 4 (repeater)
|
|
|
|
|
|
|
|
|
|
private const ISIAN_SOSIAL_EKONOMI = [ // 70 + 4 bantuan NGO + 4 pendapatan komoditas + 2 pendapatan luar = 80
|
|
|
|
|
'jumlah_tanggungan', 'anak_masih_sekolah', 'yang_ikut_bekerja', 'skor_periode_paceklik', 'bulan_paceklik',
|
|
|
|
|
'sumber_penghasilan_paceklik', 'total_estimasi_biaya_kebun_per_musim', 'skor_kemampuan_menabung',
|
|
|
|
|
'estimasi_tabungan_per_bulan', 'skor_kecukupan_penghasilan', 'alasan_kecukupan_penghasilan',
|
|
|
|
|
'status_kepemilikan_lahan', 'skor_kejelasan_status_lahan', 'ada_sertifikat_dokumen', 'ada_sengketa',
|
|
|
|
|
'keterangan_sengketa', 'pihak_membantu_konflik', 'pihak_membantu_konflik_nama', 'tahun_bantuan_konflik',
|
|
|
|
|
'status_konflik', 'kemauan_mencoba_praktik_baru', 'alasan_mencoba_praktik_baru',
|
|
|
|
|
'hambatan_mengubah_cara_bertani', 'pemahaman_mutu_harga', 'contoh_pemahaman_mutu_harga',
|
|
|
|
|
'pengetahuan_harga_hasil_olah', 'pernah_jual_harga_lebih_tinggi', 'penyebab_harga_lebih_tinggi',
|
|
|
|
|
'usaha_mutu_tambahan_harga', 'alasan_usaha_mutu_tambahan_harga', 'panutan_petani_sukses',
|
|
|
|
|
'nama_lokasi_panutan', 'kemauan_ikut_program', 'harapan_program', 'orientasi_rencana_jangka_panjang',
|
|
|
|
|
'rencana_jangka_panjang', 'terdaftar_kelompok_tani', 'nama_kelompok_tani', 'lama_bergabung_kelompok_tahun',
|
|
|
|
|
'kedekatan_sesama_anggota', 'keaktifan_pertemuan_kelompok', 'topik_biasa_dibahas', 'peran_dalam_kelompok',
|
|
|
|
|
'manfaat_kelompok_tani', 'status_kartu_tani', 'bisa_beli_pupuk_bersubsidi', 'manfaat_lain_kartu_tani',
|
|
|
|
|
'status_rekening_tabungan', 'nama_bank', 'pengalaman_kredit_kebun', 'alasan_kredit_ditolak',
|
|
|
|
|
'kondisi_aset_produktif', 'jenis_aset_produktif', 'keterangan_kondisi_aset',
|
|
|
|
|
'keterlibatan_program_keuangan_formal', 'status_program_keuangan_formal', 'pernah_bantuan_ngo_perusahaan',
|
|
|
|
|
'keterikatan_hutang_panen', 'pinjaman_tokoh_adat_panen', 'keterangan_pinjaman_tokoh_adat',
|
|
|
|
|
'total_hutang_rupiah', 'total_hutang_setara_kg_panen', 'total_hutang_tidak_bersedia', 'praktik_ijon',
|
|
|
|
|
'tekanan_jual_segera', 'penyebab_tekanan_jual_segera', 'kebebasan_memilih_pembeli',
|
|
|
|
|
'alasan_tidak_bebas_memilih_pembeli', 'minat_pembeli_harga_stabil', 'alasan_minat_pembeli_harga_stabil',
|
|
|
|
|
];
|
|
|
|
|
private const ISIAN_BANTUAN_NGO = ['nama_lembaga', 'bentuk_bantuan', 'frekuensi', 'tahun_terakhir'];
|
|
|
|
|
private const ISIAN_PENDAPATAN_KOMODITAS = ['kategori', 'komoditas', 'pendapatan', 'periode'];
|
|
|
|
|
private const ISIAN_PENDAPATAN_LUAR = ['jenis_pekerjaan', 'estimasi_per_bulan'];
|
|
|
|
|
|
|
|
|
|
private const ISIAN_AKSES_PASAR = [ // 16 + 4 harga jual = 20
|
|
|
|
|
'tujuan_penjualan', 'sifat_hubungan_bisnis', 'bentuk_penjualan', 'frekuensi_penjualan', 'skor_pengalaman',
|
|
|
|
|
'saluran_terdahulu', 'alasan_berhenti', 'tahu_harga_sebelumnya', 'sumber_info_harga', 'praktik_fermentasi',
|
|
|
|
|
'proses_fermentasi', 'model_fermentasi_memungkinkan', 'skor_kesadaran_premium', 'sumber_info_premium',
|
|
|
|
|
'tingkat_kepercayaan_pembeli_baru', 'alasan_kepercayaan_pembeli_baru',
|
|
|
|
|
];
|
|
|
|
|
private const ISIAN_HARGA_JUAL = ['bentuk_produk', 'harga_panen_terakhir', 'harga_tahun_lalu', 'harga_dua_tahun_lalu'];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Satu instance per objek Petani, supaya header dan ringkasan tidak memuat/menghitung ulang.
|
|
|
|
|
* WeakMap: otomatis dibuang saat objek Petani tidak dipakai lagi (tidak menumpuk antar-request).
|
|
|
|
|
*/
|
|
|
|
|
private static ?\WeakMap $cache = null;
|
|
|
|
|
|
|
|
|
|
private ?Collection $semuaKosong = null;
|
|
|
|
|
private ?array $hitungIsian = null;
|
|
|
|
|
|
|
|
|
|
public function __construct(private Petani $petani)
|
|
|
|
|
{
|
|
|
|
|
$petani->loadMissing([
|
|
|
|
|
'komoditas',
|
|
|
|
|
'lahans',
|
|
|
|
|
'praktikBudidaya',
|
|
|
|
|
'surveyPanen',
|
|
|
|
|
'surveyProduktivitas',
|
|
|
|
|
'surveyPelatihan',
|
|
|
|
|
'surveySertifikasi',
|
|
|
|
|
'sosialEkonomi.pendapatanKomoditas',
|
|
|
|
|
'sosialEkonomi.pendapatanLuarPertanian',
|
|
|
|
|
'aksesPasar',
|
|
|
|
|
'hargaJualPanen',
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static function untuk(Petani $petani): self
|
|
|
|
|
{
|
|
|
|
|
self::$cache ??= new \WeakMap();
|
|
|
|
|
|
|
|
|
|
return self::$cache[$petani] ??= new self($petani);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Jumlah isian WAJIB (skor) yang masih kosong di semua tab. */
|
|
|
|
|
public function jumlahWajibKosong(): int
|
|
|
|
|
{
|
|
|
|
|
return $this->semuaKosong()->flatten(1)->where('prioritas', self::WAJIB)->count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hitungan seluruh isian: terisi, total (209 untuk 1 lahan; +21 per lahan tambahan),
|
|
|
|
|
* tidak_berlaku (pertanyaan lanjutan yang tidak perlu dijawab), berlaku, persen.
|
|
|
|
|
*/
|
|
|
|
|
public function hitungIsian(): array
|
|
|
|
|
{
|
|
|
|
|
return $this->hitungIsian ??= $this->hitungSemuaIsian();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function hitungSemuaIsian(): array
|
|
|
|
|
{
|
|
|
|
|
$hasil = ['terisi' => 0, 'total' => 0, 'tidak_berlaku' => 0];
|
|
|
|
|
$p = $this->petani;
|
|
|
|
|
|
|
|
|
|
// Profil (+ provinsi/kabupaten/kecamatan yang mengikuti desa)
|
|
|
|
|
$this->hitungKolom($hasil, $p, self::ISIAN_PROFIL);
|
|
|
|
|
$this->hitungNilai($hasil, 3, self::terisi($p->desa_kelurahan_id));
|
|
|
|
|
|
|
|
|
|
// Lahan & Tanaman, per lahan. Belum ada lahan = dihitung 1 lahan kosong.
|
|
|
|
|
$daftarLahan = $p->lahans->isEmpty() ? collect([null]) : $p->lahans;
|
|
|
|
|
foreach ($daftarLahan as $lahan) {
|
|
|
|
|
$this->hitungKolom($hasil, $lahan, self::ISIAN_LAHAN);
|
|
|
|
|
$this->hitungNilai($hasil, 3, self::terisi($lahan?->desa_kelurahan_id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Praktik Budidaya, Panen, Produktivitas
|
|
|
|
|
$pb = $p->praktikBudidaya;
|
|
|
|
|
$tidakBerlakuPb = [];
|
|
|
|
|
if (! $p->isKomoditasVanili()) {
|
|
|
|
|
array_push($tidakBerlakuPb, 'penyerbukan_manual', 'deskripsi_penyerbukan_manual', 'tingkat_keberhasilan_penyerbukan');
|
|
|
|
|
}
|
|
|
|
|
if ((int) $pb?->pemberian_pupuk === PemberianPupuk::TIDAK_PERNAH->value) {
|
|
|
|
|
array_push($tidakBerlakuPb, 'jenis_pupuk', 'frekuensi_pemberian_pupuk', 'estimasi_dosis_pupuk_organik',
|
|
|
|
|
'estimasi_dosis_pupuk_anorganik', 'waktu_pemberian_pupuk', 'cara_pemberian_pupuk');
|
|
|
|
|
}
|
|
|
|
|
if ((int) $pb?->metode_penanganan_opt === MetodePenangananHamaPenyakit::TIDAK_ADA->value) {
|
|
|
|
|
array_push($tidakBerlakuPb, 'jenis_hama', 'jenis_penyakit');
|
|
|
|
|
}
|
|
|
|
|
$this->hitungKolom($hasil, $pb, self::ISIAN_PRAKTIK_BUDIDAYA, $tidakBerlakuPb);
|
|
|
|
|
$this->hitungKolom($hasil, $p->surveyPanen, self::ISIAN_PANEN);
|
|
|
|
|
$this->hitungRepeater($hasil, $p->surveyProduktivitas, self::ISIAN_PRODUKTIVITAS);
|
|
|
|
|
|
|
|
|
|
// Pendidikan & Pelatihan
|
|
|
|
|
$this->hitungRepeater($hasil, $p->surveyPelatihan, self::ISIAN_PELATIHAN);
|
|
|
|
|
$this->hitungRepeater($hasil, $p->surveySertifikasi, self::ISIAN_SERTIFIKASI);
|
|
|
|
|
|
|
|
|
|
// Sosial Ekonomi (data kelompok tidak berlaku kalau bukan anggota)
|
|
|
|
|
$se = $p->sosialEkonomi;
|
|
|
|
|
$tidakBerlakuSe = self::nilaiEnum($se?->terdaftar_kelompok_tani) === TerdaftarKelompokTani::TIDAK->value
|
|
|
|
|
? ['nama_kelompok_tani', 'lama_bergabung_kelompok_tahun', 'kedekatan_sesama_anggota',
|
|
|
|
|
'keaktifan_pertemuan_kelompok', 'topik_biasa_dibahas', 'peran_dalam_kelompok', 'manfaat_kelompok_tani']
|
|
|
|
|
: [];
|
|
|
|
|
$this->hitungKolom($hasil, $se, self::ISIAN_SOSIAL_EKONOMI, $tidakBerlakuSe);
|
|
|
|
|
$this->hitungRepeater($hasil, collect($se?->detail_bantuan_ngo_perusahaan ?? []), self::ISIAN_BANTUAN_NGO);
|
|
|
|
|
$this->hitungRepeater($hasil, $se?->pendapatanKomoditas ?? collect(), self::ISIAN_PENDAPATAN_KOMODITAS);
|
|
|
|
|
$this->hitungRepeater($hasil, $se?->pendapatanLuarPertanian ?? collect(), self::ISIAN_PENDAPATAN_LUAR);
|
|
|
|
|
|
|
|
|
|
// Akses Pasar (detail fermentasi tidak berlaku kalau belum pernah)
|
|
|
|
|
$ap = $p->aksesPasar;
|
|
|
|
|
$tidakBerlakuAp = self::nilaiEnum($ap?->praktik_fermentasi) === PraktikFermentasi::BELUM_PERNAH->value
|
|
|
|
|
? ['proses_fermentasi', 'model_fermentasi_memungkinkan']
|
|
|
|
|
: [];
|
|
|
|
|
$this->hitungKolom($hasil, $ap, self::ISIAN_AKSES_PASAR, $tidakBerlakuAp);
|
|
|
|
|
$this->hitungRepeater($hasil, $p->hargaJualPanen, self::ISIAN_HARGA_JUAL);
|
|
|
|
|
|
|
|
|
|
$hasil['berlaku'] = $hasil['total'] - $hasil['tidak_berlaku'];
|
|
|
|
|
$hasil['persen'] = $hasil['berlaku'] > 0 ? (int) floor($hasil['terisi'] / $hasil['berlaku'] * 100) : 0;
|
|
|
|
|
|
|
|
|
|
return $hasil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function nilaiEnum(mixed $nilai): mixed
|
|
|
|
|
{
|
|
|
|
|
return $nilai instanceof \BackedEnum ? $nilai->value : $nilai;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function hitungKolom(array &$hasil, ?object $model, array $kolom, array $tidakBerlaku = []): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($kolom as $k) {
|
|
|
|
|
$hasil['total']++;
|
|
|
|
|
|
|
|
|
|
if (in_array($k, $tidakBerlaku, true)) {
|
|
|
|
|
$hasil['tidak_berlaku']++;
|
|
|
|
|
} elseif ($model && self::terisi($model->{$k})) {
|
|
|
|
|
$hasil['terisi']++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function hitungNilai(array &$hasil, int $jumlah, bool $terisi): void
|
|
|
|
|
{
|
|
|
|
|
$hasil['total'] += $jumlah;
|
|
|
|
|
$hasil['terisi'] += $terisi ? $jumlah : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Kolom repeater dianggap terisi kalau minimal satu baris mengisinya. */
|
|
|
|
|
private function hitungRepeater(array &$hasil, Collection $baris, array $kolom): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($kolom as $k) {
|
|
|
|
|
$hasil['total']++;
|
|
|
|
|
$hasil['terisi'] += $baris->contains(fn ($row) => self::terisi(data_get($row, $k))) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Isian yang masih kosong di satu tab.
|
|
|
|
|
* Setiap item: label, prioritas (wajib/perlu), input (atribut name di form),
|
|
|
|
|
* grup (judul pengelompokan, mis. nama lahan), lahan_id, url (opsional, halaman lain).
|
|
|
|
|
*/
|
|
|
|
|
public function kosong(string $tab): Collection
|
|
|
|
|
{
|
|
|
|
|
return $this->semuaKosong()->get($tab, collect());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function hitungKosong(string $tab): Collection
|
|
|
|
|
{
|
|
|
|
|
$isian = match ($tab) {
|
|
|
|
|
'profil' => $this->profil(),
|
|
|
|
|
'lahan' => $this->lahan(),
|
|
|
|
|
'praktik-budidaya' => $this->praktikBudidaya(),
|
|
|
|
|
'sosial-ekonomi' => $this->sosialEkonomi(),
|
|
|
|
|
'akses-pasar' => $this->aksesPasar(),
|
|
|
|
|
default => [],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return collect($isian)
|
|
|
|
|
->reject(fn (array $item) => $item['terisi'])
|
|
|
|
|
->map(fn (array $item) => collect($item)->except('terisi')->all())
|
|
|
|
|
->values();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Isian kosong semua tab, dikelompokkan per tab (untuk tab Kesiapan Adopsi). */
|
|
|
|
|
public function semuaKosong(): Collection
|
|
|
|
|
{
|
|
|
|
|
return $this->semuaKosong ??= collect(array_keys(self::TAB_LABEL))
|
|
|
|
|
->mapWithKeys(fn (string $tab) => [$tab => $this->hitungKosong($tab)]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function item(string $label, string $prioritas, string $input, mixed $nilai, array $tambahan = []): array
|
|
|
|
|
{
|
|
|
|
|
return $this->itemCek($label, $prioritas, $input, self::terisi($nilai), $tambahan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Untuk isian yang status terisinya dihitung sendiri (mis. repeater). */
|
|
|
|
|
private function itemCek(string $label, string $prioritas, string $input, bool $terisi, array $tambahan = []): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
'label' => $label,
|
|
|
|
|
'prioritas' => $prioritas,
|
|
|
|
|
'input' => $input,
|
|
|
|
|
'terisi' => $terisi,
|
|
|
|
|
'grup' => null,
|
|
|
|
|
'lahan_id' => null,
|
|
|
|
|
'url' => null,
|
|
|
|
|
...$tambahan,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function terisi(mixed $nilai): bool
|
|
|
|
|
{
|
|
|
|
|
if ($nilai instanceof Collection) {
|
|
|
|
|
return $nilai->isNotEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ! (is_null($nilai) || $nilai === '' || $nilai === []);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function profil(): array
|
|
|
|
|
{
|
|
|
|
|
$p = $this->petani;
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
$this->item('Jenis kelamin', self::PERLU, 'jenis_kelamin', $p->jenis_kelamin),
|
|
|
|
|
$this->item('Tanggal lahir', self::PERLU, 'tanggal_lahir', $p->tanggal_lahir),
|
|
|
|
|
$this->item('Pendidikan terakhir', self::PERLU, 'pendidikan_terakhir', $p->pendidikan_terakhir),
|
|
|
|
|
$this->item('Komoditas utama', self::PERLU, 'komoditas_id', $p->komoditas_id),
|
|
|
|
|
$this->item('Desa/kelurahan', self::PERLU, 'desa_kelurahan_id', $p->desa_kelurahan_id),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Diisi per lahan; setiap item membawa link ke halaman edit lahannya. */
|
|
|
|
|
private function lahan(): array
|
|
|
|
|
{
|
|
|
|
|
$daftarLahan = $this->petani->lahans->sortBy('id');
|
|
|
|
|
|
|
|
|
|
if ($daftarLahan->isEmpty()) {
|
|
|
|
|
return [$this->itemCek('Belum ada lahan', self::PERLU, '', false, [
|
|
|
|
|
'url' => route('petani.lahan-tanaman.create', $this->petani->id),
|
|
|
|
|
])];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $daftarLahan->values()->flatMap(function (Lahan $l, int $i) {
|
|
|
|
|
$tambahan = [
|
|
|
|
|
'grup' => $l->nama ?: 'Lahan ' . ($i + 1),
|
|
|
|
|
'lahan_id' => $l->id,
|
|
|
|
|
'url' => route('petani.lahan-tanaman.edit', [$this->petani->id, $l->id]),
|
|
|
|
|
];
|
|
|
|
|
$adaSerangan = self::terisi($l->serangan_hama) || self::terisi($l->penyakit_tanaman);
|
|
|
|
|
|
|
|
|
|
return array_filter([
|
|
|
|
|
$this->item('Luas lahan', self::PERLU, 'luas_lahan', $l->luas_lahan, $tambahan),
|
|
|
|
|
$this->item('Peta/polygon lahan', self::PERLU, 'path', $l->path, $tambahan),
|
|
|
|
|
$this->item('Desa lahan', self::PERLU, 'desa_kelurahan_id', $l->desa_kelurahan_id, $tambahan),
|
|
|
|
|
$this->item('Umur tanaman', self::PERLU, 'umur_tanaman', $l->umur_tanaman, $tambahan),
|
|
|
|
|
$this->item('Jumlah tanaman', self::PERLU, 'jumlah_tanaman', $l->jumlah_tanaman, $tambahan),
|
|
|
|
|
$this->item('Kondisi tanaman', self::PERLU, 'kondisi_tanaman', $l->kondisi_tanaman, $tambahan),
|
|
|
|
|
$this->item('Serangan hama', self::PERLU, 'serangan_hama', $l->serangan_hama, $tambahan),
|
|
|
|
|
$this->item('Penyakit tanaman', self::PERLU, 'penyakit_tanaman', $l->penyakit_tanaman, $tambahan),
|
|
|
|
|
$adaSerangan
|
|
|
|
|
? $this->item('Keparahan serangan', self::PERLU, 'keparahan_serangan', $l->keparahan_serangan, $tambahan)
|
|
|
|
|
: null,
|
|
|
|
|
]);
|
|
|
|
|
})->all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function praktikBudidaya(): array
|
|
|
|
|
{
|
|
|
|
|
$pb = $this->petani->praktikBudidaya;
|
|
|
|
|
$panen = $this->petani->surveyPanen;
|
|
|
|
|
|
|
|
|
|
$adaHama = $pb && self::terisi($pb->metode_penanganan_opt)
|
|
|
|
|
&& (int) $pb->metode_penanganan_opt !== MetodePenangananHamaPenyakit::TIDAK_ADA->value;
|
|
|
|
|
|
|
|
|
|
$konservasi = (array) ($pb?->kebiasaan_konservasi_tanah ?? []);
|
|
|
|
|
$adaKonservasi = collect($konservasi)->contains(fn ($v) => $v !== self::KONSERVASI_TIDAK_ADA);
|
|
|
|
|
|
|
|
|
|
return array_filter([
|
|
|
|
|
$this->item('Frekuensi pemangkasan', self::WAJIB, 'frekuensi_pemangkasan_komoditas_utama', $pb?->frekuensi_pemangkasan_utama),
|
|
|
|
|
$this->item('Pemberian pupuk', self::WAJIB, 'pemberian_pupuk', $pb?->pemberian_pupuk),
|
|
|
|
|
$this->item('Metode penanganan hama & penyakit', self::WAJIB, 'metode_penanganan_hama_penyakit', $pb?->metode_penanganan_opt),
|
|
|
|
|
$adaHama ? $this->item('Jenis hama', self::PERLU, 'jenis_hama', $pb->jenis_hama) : null,
|
|
|
|
|
$adaHama ? $this->item('Jenis penyakit', self::PERLU, 'jenis_penyakit', $pb->jenis_penyakit) : null,
|
|
|
|
|
$this->item('Frekuensi sanitasi lahan', self::WAJIB, 'frekuensi_sanitasi_lahan', $pb?->frekuensi_sanitasi_lahan),
|
|
|
|
|
$this->item('Penanganan gulma', self::WAJIB, 'penanganan_gulma', $pb?->penanganan_gulma),
|
|
|
|
|
$this->item('Kondisi pengelolaan air & irigasi', self::WAJIB, 'kondisi_pengelolaan_air_irigasi', $pb?->kondisi_pengelolaan_air),
|
|
|
|
|
$this->item('Sumber air', self::PERLU, 'sumber_air', $pb?->sumber_air),
|
|
|
|
|
$this->item('Kebiasaan konservasi tanah', self::WAJIB, 'kebiasaan_konservasi_tanah', $konservasi),
|
|
|
|
|
$adaKonservasi
|
|
|
|
|
? $this->item('Pemahaman manfaat konservasi', self::WAJIB, 'pemahaman_manfaat_konservasi', $pb->pemahaman_manfaat_konservasi_tanah)
|
|
|
|
|
: null,
|
|
|
|
|
$this->item('Total estimasi biaya produksi', self::WAJIB, 'total_estimasi_biaya_produksi', $pb?->total_estimasi_biaya_produksi),
|
|
|
|
|
$this->item('Dasar penentuan panen', self::WAJIB, 'dasar_penentuan_panen', $panen?->dasar_penentuan_panen),
|
|
|
|
|
$this->item('Hasil komoditas utama per musim', self::PERLU, 'hasil_komoditas_utama_permusim', $panen?->hasil_komoditas_utama_permusim),
|
|
|
|
|
$this->item('Praktik sortasi', self::WAJIB, 'praktik_sortasi', $panen?->praktik_sortasi),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function sosialEkonomi(): array
|
|
|
|
|
{
|
|
|
|
|
$se = $this->petani->sosialEkonomi;
|
|
|
|
|
$anggotaKelompok = $se?->terdaftar_kelompok_tani === TerdaftarKelompokTani::YA
|
|
|
|
|
|| $se?->terdaftar_kelompok_tani === TerdaftarKelompokTani::YA->value;
|
|
|
|
|
|
|
|
|
|
$adaPendapatan = (bool) $se?->pendapatanKomoditas->contains(fn ($row) => (int) $row->pendapatan > 0);
|
|
|
|
|
|
|
|
|
|
return array_filter([
|
|
|
|
|
// Utama
|
|
|
|
|
$this->item('Jumlah tanggungan', self::PERLU, 'jumlah_tanggungan', $se?->jumlah_tanggungan),
|
|
|
|
|
$this->itemCek('Pendapatan per komoditas', self::WAJIB, 'pendapatan_komoditas', $adaPendapatan),
|
|
|
|
|
$this->item('Periode paceklik', self::WAJIB, 'skor_periode_paceklik', $se?->skor_periode_paceklik),
|
|
|
|
|
$this->item('Kemampuan menabung', self::WAJIB, 'skor_kemampuan_menabung', $se?->skor_kemampuan_menabung),
|
|
|
|
|
$this->item('Kecukupan penghasilan', self::WAJIB, 'skor_kecukupan_penghasilan', $se?->skor_kecukupan_penghasilan),
|
|
|
|
|
$this->item('Kejelasan status lahan', self::WAJIB, 'skor_kejelasan_status_lahan', $se?->skor_kejelasan_status_lahan),
|
|
|
|
|
|
|
|
|
|
// Sosial budaya
|
|
|
|
|
$this->item('Kemauan mencoba praktik baru', self::WAJIB, 'kemauan_mencoba_praktik_baru', $se?->kemauan_mencoba_praktik_baru),
|
|
|
|
|
$this->item('Pemahaman mutu & harga', self::WAJIB, 'pemahaman_mutu_harga', $se?->pemahaman_mutu_harga),
|
|
|
|
|
$this->item('Panutan petani sukses', self::WAJIB, 'panutan_petani_sukses', $se?->panutan_petani_sukses),
|
|
|
|
|
$this->item('Kemauan ikut program', self::WAJIB, 'kemauan_ikut_program', $se?->kemauan_ikut_program),
|
|
|
|
|
$this->item('Orientasi rencana jangka panjang', self::WAJIB, 'orientasi_rencana_jangka_panjang', $se?->orientasi_rencana_jangka_panjang),
|
|
|
|
|
|
|
|
|
|
// Keanggotaan kelompok: pertanyaan lanjutan hanya untuk anggota
|
|
|
|
|
$this->item('Terdaftar di kelompok tani', self::WAJIB, 'terdaftar_kelompok_tani', $se?->terdaftar_kelompok_tani),
|
|
|
|
|
$anggotaKelompok ? $this->item('Keaktifan pertemuan kelompok', self::WAJIB, 'keaktifan_pertemuan_kelompok', $se->keaktifan_pertemuan_kelompok) : null,
|
|
|
|
|
$anggotaKelompok ? $this->item('Peran dalam kelompok', self::WAJIB, 'peran_dalam_kelompok', $se->peran_dalam_kelompok) : null,
|
|
|
|
|
$anggotaKelompok ? $this->item('Manfaat kelompok tani', self::WAJIB, 'manfaat_kelompok_tani', $se->manfaat_kelompok_tani) : null,
|
|
|
|
|
|
|
|
|
|
// Akses keuangan
|
|
|
|
|
$this->item('Status rekening tabungan', self::WAJIB, 'status_rekening_tabungan', $se?->status_rekening_tabungan),
|
|
|
|
|
$this->item('Pengalaman kredit kebun', self::WAJIB, 'pengalaman_kredit_kebun', $se?->pengalaman_kredit_kebun),
|
|
|
|
|
$this->item('Kondisi aset produktif', self::WAJIB, 'kondisi_aset_produktif', $se?->kondisi_aset_produktif),
|
|
|
|
|
$this->item('Keterlibatan program keuangan formal', self::WAJIB, 'keterlibatan_program_keuangan_formal', $se?->keterlibatan_program_keuangan_formal),
|
|
|
|
|
|
|
|
|
|
// Keterikatan hutang
|
|
|
|
|
$this->item('Keterikatan hutang panen', self::WAJIB, 'keterikatan_hutang_panen', $se?->keterikatan_hutang_panen),
|
|
|
|
|
$this->item('Praktik ijon', self::WAJIB, 'praktik_ijon', $se?->praktik_ijon),
|
|
|
|
|
$this->item('Kebebasan memilih pembeli', self::WAJIB, 'kebebasan_memilih_pembeli', $se?->kebebasan_memilih_pembeli),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function aksesPasar(): array
|
|
|
|
|
{
|
|
|
|
|
$ap = $this->petani->aksesPasar;
|
|
|
|
|
$harga = $this->petani->hargaJualPanen;
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
$this->item('Tujuan penjualan', self::PERLU, 'tujuan_penjualan', $ap?->tujuan_penjualan),
|
|
|
|
|
$this->item('Sifat hubungan dengan pembeli', self::PERLU, 'sifat_hubungan_bisnis', $ap?->sifat_hubungan_bisnis),
|
|
|
|
|
$this->item('Frekuensi penjualan', self::PERLU, 'frekuensi_penjualan', $ap?->frekuensi_penjualan),
|
|
|
|
|
$this->item('Pengalaman menjual ke saluran lain', self::WAJIB, 'skor_pengalaman', $ap?->skor_pengalaman),
|
|
|
|
|
$this->item('Praktik fermentasi', self::PERLU, 'praktik_fermentasi', $ap?->praktik_fermentasi),
|
|
|
|
|
$this->item('Kesadaran pasar premium', self::WAJIB, 'skor_kesadaran_premium', $ap?->skor_kesadaran_premium),
|
|
|
|
|
$this->item('Kepercayaan pada pembeli baru', self::WAJIB, 'tingkat_kepercayaan_pembeli_baru', $ap?->tingkat_kepercayaan_pembeli_baru),
|
|
|
|
|
$this->itemCek('Harga jual panen terakhir', self::PERLU, 'harga_jual',
|
|
|
|
|
$harga->contains(fn ($h) => self::terisi($h->bentuk_produk) && (float) $h->harga_panen_terakhir > 0)),
|
|
|
|
|
$this->itemCek('Harga jual tahun lalu', self::PERLU, 'harga_jual',
|
|
|
|
|
$harga->contains(fn ($h) => (float) $h->harga_tahun_lalu > 0)),
|
|
|
|
|
$this->itemCek('Harga jual dua tahun lalu', self::PERLU, 'harga_jual',
|
|
|
|
|
$harga->contains(fn ($h) => (float) $h->harga_dua_tahun_lalu > 0)),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|