card dashboard produksi

This commit is contained in:
2026-10-14 20:18:15 +07:00
parent 3a9b3dbd7b
commit 3e172cf915
2 changed files with 30 additions and 68 deletions
@@ -183,7 +183,8 @@ class SummaryController extends Controller
$landMetrics = $this->karakteristikLandMetrics($request);
$totalLuasLahan = $landMetrics['total_luas_lahan'];
$avgLuasPerPetani = $landMetrics['ratarata_luas_lahan'];
$productivityCards = $this->productivityKpiCards($lahanIds);
$actualProductivity = $this->actualProductivityByCommodityChart($request);
$productivityCards = $this->productivityKpiCards($actualProductivity);
$praktikBudidaya = $this->filteredPraktikBudidaya($request);
$surveyPanen = $this->filteredSurveyPanen($request);
$aksesPasar = $this->filteredAksesPasar($request);
@@ -243,7 +244,7 @@ class SummaryController extends Controller
),
'praktikSortasiPanen' => $this->enumOptionChart($surveyPanen, 'praktik_sortasi', PraktikSortasi::class),
'praktikFermentasiPascapanen' => $this->fermentationPracticeChart($aksesPasar),
'produktivitasAktualPerKomoditas' => $this->actualProductivityByCommodityChart($request),
'produktivitasAktualPerKomoditas' => $actualProductivity,
],
];
}
@@ -706,43 +707,18 @@ class SummaryController extends Controller
];
}
private function productivityKpiCards($lahanIds): array
private function productivityKpiCards(array $actualProductivity): array
{
$komoditas = Komoditas::query()
->where('is_utama', true)
->orderBy('nama')
->limit(4)
->get(['id', 'nama']);
$produksiRows = DB::table('produksi')
->whereNull('produksi.deleted_at')
->leftJoin('map_lahan as lahan_produksi', 'lahan_produksi.id', '=', 'produksi.lahan_id')
->when($lahanIds->isNotEmpty(), fn ($query) => $query->whereIn('produksi.lahan_id', $lahanIds))
->when($lahanIds->isEmpty(), fn ($query) => $query->whereRaw('1 = 0'))
->selectRaw('COALESCE(produksi.komoditas_id, lahan_produksi.komoditas_id) as komoditas_id')
->addSelect([
'produksi.jumlah_panen',
'produksi.satuan',
'produksi.luas_panen',
'produksi.produktivitas',
])
->get()
->groupBy('komoditas_id');
$variants = ['primary', 'warning', 'info', 'secondary'];
$icon = 'tabler-chart-bar';
return $komoditas
->values()
->map(function ($item, int $index) use ($produksiRows, $variants, $icon) {
$rows = $produksiRows->get($item->id, collect());
$average = $this->averageProductivity($rows);
return collect($actualProductivity['labels'])
->map(function (string $name, int $index) use ($actualProductivity, $variants, $icon) {
return [
'value' => number_format($average, 0, ',', '.'),
'value' => number_format((float) ($actualProductivity['series'][$index] ?? 0), 2, ',', '.'),
'unit' => 'kg/ha',
'label' => 'Produktivitas Rata-rata '.$item->nama,
'description' => 'Rata-rata produktivitas per komoditas',
'label' => 'Produktivitas Aktual '.$name,
'description' => 'Hasil panen per musim dibagi total luas lahan',
'icon' => $icon,
'variant' => $variants[$index % count($variants)],
];
@@ -750,32 +726,6 @@ class SummaryController extends Controller
->all();
}
private function averageProductivity($rows): float
{
if ($rows->isEmpty()) {
return 0;
}
$storedAverage = $rows
->pluck('produktivitas')
->filter(fn ($value) => (float) $value > 0)
->avg();
if ($storedAverage > 0) {
return round((float) $storedAverage, 2);
}
$totalProduksiKg = $rows->sum(fn ($row) => $this->toKilograms(
(float) ($row->jumlah_panen ?? 0),
(string) ($row->satuan ?? 'kg')
));
$totalLuasPanen = $rows->sum(fn ($row) => (float) ($row->luas_panen ?? 0));
return $totalLuasPanen > 0
? round($totalProduksiKg / $totalLuasPanen, 2)
: 0;
}
private function actualProductivityByCommodityChart(Request $request): array
{
$preferredOrder = ['Kakao', 'Vanili', 'Kemiri', 'Kopi'];
@@ -824,15 +774,6 @@ class SummaryController extends Controller
];
}
private function toKilograms(float $value, string $unit): float
{
return match (strtolower($unit)) {
'ton' => $value * 1000,
'kuintal', 'kwintal' => $value * 100,
default => $value,
};
}
private function filteredLahanQuery(Request $request)
{
return DB::table('map_lahan')
@@ -106,3 +106,24 @@ test('actual productivity rounds kg per hectare to two decimals', function () {
expect(($this->chart)()['series'][1])->toBe(33.33);
});
test('productivity cards display the same values and commodities as the chart', function () {
DB::table('map_lahan')->where('petani_id', 5)->update(['luas_lahan' => 0.3]);
$controller = app(SummaryController::class);
$method = new ReflectionMethod($controller, 'productivityKpiCards');
foreach ([[], ['desaKelurahan_id' => 2], ['komoditas_id' => 1]] as $filters) {
$chart = ($this->chart)($filters);
$cards = $method->invoke($controller, $chart);
expect(array_column($cards, 'label'))->toBe(array_map(
fn ($name) => 'Produktivitas Aktual '.$name,
$chart['labels'],
));
expect(array_column($cards, 'value'))->toBe(array_map(
fn ($value) => number_format($value, 2, ',', '.'),
$chart['series'],
));
expect(array_column($cards, 'unit'))->toBe(array_fill(0, count($chart['labels']), 'kg/ha'));
}
});