diff --git a/app/Filament/Widgets/EggProductionChart.php b/app/Filament/Widgets/EggProductionChart.php new file mode 100644 index 0000000..93328db --- /dev/null +++ b/app/Filament/Widgets/EggProductionChart.php @@ -0,0 +1,42 @@ +=', now()->subDays(30)) + ->orderBy('production_date') + ->get() + ->groupBy(fn ($item) => Carbon::parse($item->production_date)->translatedFormat('Y-m-d')) + ->map(fn ($items) => $items->sum('total_eggs')); + + return [ + 'datasets' => [ + [ + 'label' => 'Total Telur', + 'data' => $data->values()->toArray(), + 'fill' => 'start', + 'tension' => 0.4, + ], + ], + 'labels' => $data->keys()->map(fn ($date) => Carbon::parse($date)->translatedFormat('d M'))->toArray(), + ]; + } + + protected function getType(): string + { + return 'line'; + } +} diff --git a/app/Filament/Widgets/OrderTrendChart.php b/app/Filament/Widgets/OrderTrendChart.php new file mode 100644 index 0000000..7f36202 --- /dev/null +++ b/app/Filament/Widgets/OrderTrendChart.php @@ -0,0 +1,40 @@ +=', now()->subDays(30)) + ->orderBy('order_date') + ->get() + ->groupBy(fn ($item) => Carbon::parse($item->order_date)->translatedFormat('Y-m-d')) + ->map(fn ($items) => $items->count()); + + return [ + 'datasets' => [ + [ + 'label' => 'Jumlah Pesanan', + 'data' => $data->values()->toArray(), + 'fill' => 'start', + 'tension' => 0.4, + ], + ], + 'labels' => $data->keys()->map(fn ($date) => Carbon::parse($date)->translatedFormat('d M'))->toArray(), + ]; + } + + protected function getType(): string + { + return 'line'; + } +} diff --git a/app/Filament/Widgets/RevenueExpenseChart.php b/app/Filament/Widgets/RevenueExpenseChart.php new file mode 100644 index 0000000..e70fb8a --- /dev/null +++ b/app/Filament/Widgets/RevenueExpenseChart.php @@ -0,0 +1,79 @@ +reverse()->map(function ($i) { + return now()->subMonths($i)->format('Y-m'); + }); + + $revenues = Order::select( + DB::raw("DATE_FORMAT(order_date, '%Y-%m') as month"), + DB::raw('SUM(total_amount) as total') + ) + ->where('order_date', '>=', now()->subMonths(5)->startOfMonth()) + ->groupBy('month') + ->get() + ->pluck('total', 'month'); + + $expenses = Expense::select( + DB::raw("DATE_FORMAT(expense_date, '%Y-%m') as month"), + DB::raw('SUM(amount) as total') + ) + ->where('expense_date', '>=', now()->subMonths(5)->startOfMonth()) + ->groupBy('month') + ->get() + ->pluck('total', 'month'); + + $feedPurchases = FeedPurchase::select( + DB::raw("DATE_FORMAT(purchase_date, '%Y-%m') as month"), + DB::raw('SUM(total_price) as total') + ) + ->where('purchase_date', '>=', now()->subMonths(5)->startOfMonth()) + ->groupBy('month') + ->get() + ->pluck('total', 'month'); + + $revenueData = $months->map(fn ($month) => (int) $revenues->get($month, 0)); + $expenseData = $months->map(fn ($month) => (int) ($expenses->get($month, 0) + $feedPurchases->get($month, 0))); + + return [ + 'datasets' => [ + [ + 'label' => 'Pendapatan (Order)', + 'data' => $revenueData->values()->toArray(), + 'backgroundColor' => '#10b981', + 'borderColor' => '#10b981', + ], + [ + 'label' => 'Pengeluaran (Operasional + Pakan)', + 'data' => $expenseData->values()->toArray(), + 'backgroundColor' => '#ef4444', + 'borderColor' => '#ef4444', + ], + ], + 'labels' => $months->values()->map(fn ($month) => Carbon::parse($month)->translatedFormat('M Y'))->toArray(), + ]; + } + + protected function getType(): string + { + return 'bar'; + } +} diff --git a/app/Filament/Widgets/StatsOverview.php b/app/Filament/Widgets/StatsOverview.php new file mode 100644 index 0000000..07202a0 --- /dev/null +++ b/app/Filament/Widgets/StatsOverview.php @@ -0,0 +1,79 @@ +count()) + ->description('Jumlah ayam dengan status aktif saat ini.') + ->descriptionIcon('heroicon-m-heart') + ->color('success'), + + Stat::make('Produksi Telur', number_format(EggCollection::sum('total_eggs'), 0, ',', '.').' Butir') + ->description('Total telur yang terkumpul.') + ->descriptionIcon('heroicon-m-circle-stack') + ->color('warning'), + + Stat::make('Order', number_format(Order::count(), 0, ',', '.').' Order') + ->description('Jumlah order yang dibuat.') + ->descriptionIcon('heroicon-m-shopping-cart') + ->color('info'), + + Stat::make('Pendapatan', 'Rp '.number_format(Order::sum('total_amount'), 0, ',', '.')) + ->description('Total pendapatan dari order.') + ->descriptionIcon('heroicon-m-banknotes') + ->color('success'), + + Stat::make('Total Pelanggan', number_format(Customer::count(), 0, ',', '.').' Orang') + ->description('Total pelanggan terdaftar.') + ->descriptionIcon('heroicon-m-users') + ->color('primary'), + + Stat::make('Total Pengeluaran', 'Rp '.number_format(Expense::sum('amount'), 0, ',', '.')) + ->description('Total akumulasi biaya pengeluaran.') + ->descriptionIcon('heroicon-m-credit-card') + ->color('danger'), + + Stat::make('Barang Tertunda', number_format(DelayedGood::count(), 0, ',', '.').' Item') + ->description('Jumlah barang yang masih tertunda.') + ->descriptionIcon('heroicon-m-clock') + ->color('warning'), + + Stat::make('Total Belanja Pakan', 'Rp '.number_format(FeedPurchase::sum('total_price'), 0, ',', '.')) + ->description('Total pengeluaran untuk pakan.') + ->descriptionIcon('heroicon-m-shopping-bag') + ->color('info'), + + Stat::make('Laba Kotor (Estimasi)', 'Rp '.number_format(Order::sum('total_amount') - (Expense::sum('amount') + FeedPurchase::sum('total_price')), 0, ',', '.')) + ->description('Pendapatan - (Pengeluaran + Pakan).') + ->descriptionIcon('heroicon-m-presentation-chart-line') + ->color('success'), + + Stat::make('Piutang Belum Terbayar', 'Rp '.number_format(DelayedGood::where('is_paid', false)->sum('total_amount') - DelayedGood::where('is_paid', false)->sum('paid_amount'), 0, ',', '.')) + ->description('Total piutang dari barang tertunda.') + ->descriptionIcon('heroicon-m-receipt-percent') + ->color('danger'), + + Stat::make('Total Biaya Operasional', 'Rp '.number_format(Expense::sum('amount') + FeedPurchase::sum('total_price'), 0, ',', '.')) + ->description('Total beban biaya saat ini.') + ->descriptionIcon('heroicon-m-calculator') + ->color('warning'), + ]; + } +} diff --git a/app/Filament/Widgets/TopCustomersChart.php b/app/Filament/Widgets/TopCustomersChart.php new file mode 100644 index 0000000..dac39ea --- /dev/null +++ b/app/Filament/Widgets/TopCustomersChart.php @@ -0,0 +1,53 @@ +select('customer_id', DB::raw('SUM(total_amount) as total_spent')) + ->groupBy('customer_id') + ->orderByDesc('total_spent') + ->limit(5) + ->get(); + + return [ + 'datasets' => [ + [ + 'label' => 'Total Pembelian (Rp)', + 'data' => $data->pluck('total_spent')->toArray(), + 'backgroundColor' => [ + '#fbbf24', + '#f59e0b', + '#d97706', + '#b45309', + '#92400e', + ], + ], + ], + 'labels' => $data->map(fn ($item) => $item->customer?->name ?? 'Umum')->toArray(), + ]; + } + + protected function getType(): string + { + return 'bar'; + } + + protected function getOptions(): array + { + return [ + 'indexAxis' => 'y', + ]; + } +}