Update Profil Detail Petani
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Web\Produktivitas;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use App\Models\Pertanian\Petani;
|
||||
use App\Models\Pertanian\SkorPetani;
|
||||
use App\Models\Pertanian\Komoditas;
|
||||
use App\Models\Pertanian\Lahan;
|
||||
use App\Models\Pertanian\PendapatanKomoditas;
|
||||
use App\Models\Wilayah\DesaKelurahan;
|
||||
use App\Models\Profile;
|
||||
|
||||
class ProfilPetaniController extends Controller
|
||||
{
|
||||
private const DIMENSION_LOW_MAX = 2.49;
|
||||
private const DIMENSION_MEDIUM_MAX = 3.49;
|
||||
|
||||
public function index(int $id)
|
||||
{
|
||||
$petani = Petani::findOrFail($id);
|
||||
$skorPetani = SkorPetani::where('petani_id', $id)->first();
|
||||
$enumerator = Profile::where('user_id', $petani->created_by)->first();
|
||||
$komoditas = Komoditas::where('id', $petani->komoditas_id)->get();
|
||||
$lahan = Lahan::where('petani_id', $id )->get();
|
||||
|
||||
$desaKelurahan = DesaKelurahan::with('kecamatan')
|
||||
->where('id', $petani->desa_kelurahan_id)
|
||||
->first();
|
||||
|
||||
$ktpMasked = $petani->ktp ? Str::mask($petani->ktp, '*', 4, -4) : '-';
|
||||
$profiling = $skorPetani ? $this->buildProfiling($skorPetani) : null;
|
||||
|
||||
$data = [
|
||||
'petani' => $petani,
|
||||
'skorPetani' => $skorPetani,
|
||||
'enumerator' => $enumerator,
|
||||
'komoditas' => $komoditas,
|
||||
'lahan' => $lahan,
|
||||
'desaKelurahan' => $desaKelurahan,
|
||||
'ktpMasked' => $ktpMasked,
|
||||
'profiling' => $profiling,
|
||||
];
|
||||
return view('produktivitas.profil-petani.index', $data);
|
||||
}
|
||||
|
||||
private function buildProfiling(SkorPetani $skorPetani): array
|
||||
{
|
||||
$skorAkhir = $this->normalizeScore($skorPetani->skor_kesiapan_adopsi);
|
||||
$segmen = $this->getSegmen($skorAkhir);
|
||||
|
||||
$dimensions = [
|
||||
'd2' => [
|
||||
'kode' => 'D2',
|
||||
'nama' => 'Sistem & Praktik Budidaya',
|
||||
'skor' => $this->normalizeScore(
|
||||
$skorPetani->skor_d2_sistem_praktik_budidaya
|
||||
),
|
||||
],
|
||||
|
||||
'd4' => [
|
||||
'kode' => 'D4',
|
||||
'nama' => 'Sosial-Ekonomi Rumah Tangga',
|
||||
'skor' => $this->normalizeScore(
|
||||
$skorPetani->skor_d4_sosial_ekonomi
|
||||
),
|
||||
],
|
||||
|
||||
'd6' => [
|
||||
'kode' => 'D6',
|
||||
'nama' => 'Rantai Nilai & Akses Pasar',
|
||||
'skor' => $this->normalizeScore(
|
||||
$skorPetani->skor_d6_rantai_nilai_akses_pasar
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($dimensions as $key => $dimension) {
|
||||
$dimensions[$key]['level'] = $this->getDimensionLevel($dimension['skor']);
|
||||
}
|
||||
|
||||
$components = collect([
|
||||
[
|
||||
'key' => 'motivasi',
|
||||
'nama' => 'Motivasi & Kapasitas Adopsi',
|
||||
'short' => 'Motivasi',
|
||||
'dimensi' => 'D4',
|
||||
'bobot' => 25,
|
||||
'icon' => 'tabler-bulb',
|
||||
'skor' => $this->normalizeScore($skorPetani->skor_komp_1_d4_k3_motivasi_kapasitas_adopsi),
|
||||
],
|
||||
|
||||
[
|
||||
'key' => 'ekonomi',
|
||||
'nama' => 'Kondisi Ekonomi Rumah Tangga',
|
||||
'short' => 'Ekonomi',
|
||||
'dimensi' => 'D4',
|
||||
'bobot' => 20,
|
||||
'icon' => 'tabler-home-dollar',
|
||||
'skor' => $this->normalizeScore($skorPetani->skor_komp_2_d4_k2_ekonomi_rumah_tangga),
|
||||
],
|
||||
|
||||
[
|
||||
'key' => 'gap',
|
||||
'nama' => 'Praktik Budidaya & GAP',
|
||||
'short' => 'Budidaya / GAP',
|
||||
'dimensi' => 'D2',
|
||||
'bobot' => 20,
|
||||
'icon' => 'tabler-plant-2',
|
||||
'skor' => $this->normalizeScore($skorPetani->skor_komp_3_d2_praktik_budidaya_gap),
|
||||
],
|
||||
|
||||
[
|
||||
'key' => 'kelembagaan',
|
||||
'nama' => 'Keterlibatan Kelembagaan',
|
||||
'short' => 'Kelembagaan',
|
||||
'dimensi' => 'D4',
|
||||
'bobot' => 15,
|
||||
'icon' => 'tabler-users-group',
|
||||
'skor' => $this->normalizeScore($skorPetani->skor_komp_4_d4_k4_keterlibatan_kelembagaan),
|
||||
],
|
||||
|
||||
[
|
||||
'key' => 'keuangan',
|
||||
'nama' => 'Akses & Kebebasan Keuangan',
|
||||
'short' => 'Keuangan',
|
||||
'dimensi' => 'D4',
|
||||
'bobot' => 10,
|
||||
'icon' => 'tabler-building-bank',
|
||||
'skor' => $this->normalizeScore($skorPetani->skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan),
|
||||
],
|
||||
|
||||
[
|
||||
'key' => 'pasar',
|
||||
'nama' => 'Rantai Nilai & Akses Pasar',
|
||||
'short' => 'Akses Pasar',
|
||||
'dimensi' => 'D6',
|
||||
'bobot' => 10,
|
||||
'icon' => 'tabler-building-store',
|
||||
'skor' => $this->normalizeScore($skorPetani->skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar),
|
||||
],
|
||||
]);
|
||||
|
||||
$availableComponents = $components
|
||||
->filter(fn ($item) => $item['skor'] !== null)
|
||||
->values();
|
||||
|
||||
$strengths = $availableComponents
|
||||
->sortByDesc('skor')
|
||||
->take(2)
|
||||
->values();
|
||||
|
||||
$barriers = $availableComponents
|
||||
->filter(fn ($item) => $item['skor'] < 3)
|
||||
->sortBy('skor')
|
||||
->values();
|
||||
|
||||
$specialPattern = $this->detectSpecialPattern(
|
||||
$segmen,
|
||||
$dimensions,
|
||||
$skorPetani
|
||||
);
|
||||
|
||||
$title = $this->buildProfileTitle(
|
||||
$segmen,
|
||||
$specialPattern,
|
||||
$barriers
|
||||
);
|
||||
|
||||
$narrative = $this->buildNarrative(
|
||||
$segmen,
|
||||
$specialPattern,
|
||||
$strengths,
|
||||
$barriers
|
||||
);
|
||||
|
||||
$recommendations = $this->buildRecommendations(
|
||||
$specialPattern,
|
||||
$barriers
|
||||
);
|
||||
|
||||
return [
|
||||
'skor_akhir' => $skorAkhir,
|
||||
'segmen' => $segmen,
|
||||
'title' => $title,
|
||||
'dimensions' => $dimensions,
|
||||
'components' => $components,
|
||||
'strengths' => $strengths,
|
||||
'barriers' => $barriers,
|
||||
'special_pattern' => $specialPattern,
|
||||
'narrative' => $narrative,
|
||||
'recommendations' => $recommendations,
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizeScore($score): ?float
|
||||
{
|
||||
if ($score === null || $score === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$score = (float) $score;
|
||||
|
||||
if ($score <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $score;
|
||||
}
|
||||
|
||||
private function getSegmen(?float $score): string
|
||||
{
|
||||
if ($score === null) {
|
||||
return 'Belum Dinilai';
|
||||
}
|
||||
|
||||
return match (true) {
|
||||
$score >= 4.0 => 'Penggerak',
|
||||
$score >= 3.0 => 'Perintis',
|
||||
$score >= 2.0 => 'Pemerhati',
|
||||
default => 'Pemula',
|
||||
};
|
||||
}
|
||||
|
||||
private function getDimensionLevel(?float $score): string
|
||||
{
|
||||
if ($score === null) {
|
||||
return 'belum_dinilai';
|
||||
}
|
||||
|
||||
if ($score <= self::DIMENSION_LOW_MAX) {
|
||||
return 'rendah';
|
||||
}
|
||||
|
||||
if ($score <= self::DIMENSION_MEDIUM_MAX) {
|
||||
return 'sedang';
|
||||
}
|
||||
|
||||
return 'tinggi';
|
||||
}
|
||||
|
||||
private function detectSpecialPattern(
|
||||
string $segmen,
|
||||
array $dimensions,
|
||||
SkorPetani $skorPetani
|
||||
): ?array {
|
||||
|
||||
$d2 = $dimensions['d2']['level'];
|
||||
$d4 = $dimensions['d4']['level'];
|
||||
$d6 = $dimensions['d6']['level'];
|
||||
|
||||
if (
|
||||
$segmen === 'Perintis' &&
|
||||
$d4 === 'tinggi' &&
|
||||
$d2 === 'rendah' &&
|
||||
$d6 === 'sedang'
|
||||
) {
|
||||
return [
|
||||
'kode' => 'perintis_teknis',
|
||||
'nama' => 'Perintis dengan Hambatan Teknis',
|
||||
'prioritas' => 'gap',
|
||||
];
|
||||
}
|
||||
|
||||
if (
|
||||
$segmen === 'Perintis' &&
|
||||
$d4 === 'tinggi' &&
|
||||
in_array($d2, ['sedang', 'tinggi']) && $d6 === 'rendah'
|
||||
) {
|
||||
return [
|
||||
'kode' => 'perintis_pasar',
|
||||
'nama' => 'Perintis dengan Hambatan Pasar',
|
||||
'prioritas' => 'pasar',
|
||||
];
|
||||
}
|
||||
|
||||
if (
|
||||
$segmen === 'Pemerhati' &&
|
||||
$d4 === 'sedang' &&
|
||||
$d2 === 'rendah' &&
|
||||
$d6 === 'sedang'
|
||||
) {
|
||||
return [
|
||||
'kode' => 'pemerhati_teknis',
|
||||
'nama' => 'Pemerhati Teknis',
|
||||
'prioritas' => 'gap',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
$segmen === 'Pemula' &&
|
||||
$d4 === 'rendah' &&
|
||||
$d2 === 'rendah' &&
|
||||
$d6 === 'rendah'
|
||||
) {
|
||||
return [
|
||||
'kode' => 'pemula_struktural',
|
||||
'nama' => 'Pemula Struktural',
|
||||
'prioritas' => 'struktural',
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function buildProfileTitle(
|
||||
string $segmen,
|
||||
?array $specialPattern,
|
||||
$barriers
|
||||
): string {
|
||||
if ($specialPattern) {
|
||||
return $specialPattern['nama'];
|
||||
}
|
||||
|
||||
if ($barriers->isNotEmpty()) {
|
||||
$mainBarrier = $barriers->first();
|
||||
return $segmen . ' dengan Prioritas ' . $mainBarrier['short'];
|
||||
}
|
||||
|
||||
return $segmen . ' dengan Profil Relatif Seimbang';
|
||||
}
|
||||
|
||||
private function buildNarrative(
|
||||
string $segmen,
|
||||
?array $specialPattern,
|
||||
$strengths,
|
||||
$barriers
|
||||
): string {
|
||||
if ($specialPattern) {
|
||||
return match ($specialPattern['kode']) {
|
||||
'perintis_teknis' =>
|
||||
'Petani memiliki fondasi sosial-ekonomi yang relatif siap '
|
||||
. 'untuk berkembang, tetapi penerapannya belum sepenuhnya '
|
||||
. 'tercermin dalam praktik budidaya. Hambatan utama berada '
|
||||
. 'pada aspek teknis di lapangan.',
|
||||
|
||||
'perintis_pasar' =>
|
||||
'Petani memiliki fondasi sosial-ekonomi dan kesiapan '
|
||||
. 'budidaya yang relatif baik, tetapi manfaat ekonominya '
|
||||
. 'masih dibatasi oleh rantai nilai dan akses pasar.',
|
||||
|
||||
'pemerhati_teknis' =>
|
||||
'Petani telah memiliki sebagian fondasi untuk berkembang, '
|
||||
. 'namun praktik budidaya masih menjadi hambatan utama. '
|
||||
. 'Pendekatan berbasis demonstrasi hasil nyata akan lebih '
|
||||
. 'relevan sebelum intervensi teknis yang lebih lanjut.',
|
||||
|
||||
'pemula_struktural' =>
|
||||
'Petani menghadapi hambatan pada beberapa dimensi sekaligus. '
|
||||
. 'Kondisi sosial-ekonomi, praktik budidaya, serta akses '
|
||||
. 'pasar perlu dibaca bersama untuk menentukan hambatan '
|
||||
. 'mendasar yang paling mendesak.',
|
||||
|
||||
default =>
|
||||
$this->buildGenericNarrative($segmen, $strengths, $barriers),
|
||||
};
|
||||
}
|
||||
|
||||
return $this->buildGenericNarrative($segmen, $strengths, $barriers);
|
||||
}
|
||||
|
||||
private function buildGenericNarrative(
|
||||
string $segmen,
|
||||
$strengths,
|
||||
$barriers
|
||||
): string {
|
||||
|
||||
$text = 'Petani berada pada segmen ' . $segmen . '. ';
|
||||
if ($strengths->isNotEmpty()) {
|
||||
$strengthNames = $strengths->pluck('nama')->implode(' dan ');
|
||||
$text .= 'Kekuatan relatif terlihat pada ' . $strengthNames . '. ';
|
||||
}
|
||||
|
||||
if ($barriers->isNotEmpty()) {
|
||||
$barrierNames = $barriers->take(3)->pluck('nama')->implode(', ');
|
||||
$text .=
|
||||
'Area yang masih memerlukan perhatian terutama pada ' . $barrierNames . '. Prioritas intervensi sebaiknya mengikuti ' . 'hambatan dengan skor paling rendah.';
|
||||
} else {
|
||||
$text .= 'Tidak terdapat komponen dengan skor rendah yang ' . 'menonjol. Pendampingan dapat difokuskan pada ' . 'pemeliharaan dan penguatan capaian yang sudah ada.';
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function buildRecommendations(
|
||||
?array $specialPattern,
|
||||
$barriers
|
||||
): array {
|
||||
if ($specialPattern) {
|
||||
$specialRecommendation = match ($specialPattern['kode']) {
|
||||
'perintis_teknis' => [
|
||||
'Prioritaskan pendampingan GAP langsung di lapangan.',
|
||||
'Perkuat koneksi petani terhadap sumber input dan pelatihan teknis.',
|
||||
],
|
||||
'perintis_pasar' => [
|
||||
'Perkuat koneksi ke saluran pasar yang lebih baik.',
|
||||
'Fasilitasi akses pembeli, negosiasi, atau penguatan koperasi.',
|
||||
],
|
||||
'pemerhati_teknis' => [
|
||||
'Gunakan demonstrasi lapangan untuk menunjukkan hasil nyata.',
|
||||
'Lakukan pendampingan teknis secara bertahap sebelum pelatihan formal.',
|
||||
],
|
||||
'pemula_struktural' => [
|
||||
'Identifikasi hambatan dasar seperti lahan, hutang, atau logistik.',
|
||||
'Tangani hambatan struktural sebelum mendorong adopsi praktik baru.',
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
if (!empty($specialRecommendation)) {
|
||||
return $specialRecommendation;
|
||||
}
|
||||
}
|
||||
$recommendationMap = [
|
||||
'motivasi' => 'Gunakan demonstrasi hasil nyata, role model, dan pendekatan perubahan secara bertahap.',
|
||||
'ekonomi' => 'Perkuat ruang gerak ekonomi rumah tangga sebelum mendorong investasi atau perubahan praktik yang berisiko.',
|
||||
'gap' => 'Prioritaskan pendampingan praktik budidaya dan GAP langsung di kebun.',
|
||||
'kelembagaan' => 'Perkuat keterlibatan petani dalam kelompok tani sebagai ruang belajar dan penguatan posisi tawar.',
|
||||
'keuangan' => 'Tinjau akses keuangan formal serta kemungkinan ikatan hutang panen atau ijon yang membatasi ruang gerak petani.',
|
||||
'pasar' => 'Perkuat koneksi dengan pembeli dan saluran pasar alternatif serta kemampuan negosiasi petani.',
|
||||
];
|
||||
|
||||
return $barriers->take(3)->map(
|
||||
fn ($item) =>
|
||||
$recommendationMap[$item['key']] ?? null
|
||||
)->filter()->values()->all();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user