layer-chicken/app/Filament/Pages/Dashboard.php

145 lines
6.1 KiB
PHP

<?php
namespace App\Filament\Pages;
use App\Enums\RoleEnum;
use App\Models\Customer;
use App\Models\DelayedGood;
use App\Models\EggCollectionItem;
use App\Models\Expense;
use App\Models\FeedPurchase;
use App\Models\Order;
use App\Models\Payroll;
use Filament\Pages\Dashboard as BaseDashboard;
use Filament\Widgets\AccountWidget;
class Dashboard extends BaseDashboard
{
protected static ?string $title = 'Dasbor';
protected string $view = 'filament.pages.dashboard';
public function getHeaderWidgets(): array
{
return [
AccountWidget::class,
];
}
public function getViewData(): array
{
$formatNumber = fn ($val) => number_format((float) $val, $val == floor($val) ? 0 : 2, ',', '.');
$now = now();
$today = $now->format('Y-m-d');
// 1. Egg Production by Unit - Single optimized query with joins
$totalEggsByUnit = EggCollectionItem::query()
->join('egg_collections', 'egg_collection_items.egg_collection_id', 'egg_collections.id')
->join('units', 'egg_collection_items.unit_id', 'units.id')
->whereNull('egg_collections.deleted_at')
->where('egg_collections.production_date', $today)
->selectRaw('units.name as unit_name,
sum(case when is_broken = 0 then quantity else 0 end) as total_good,
sum(case when is_broken = 1 then quantity else 0 end) as total_broken')
->groupBy('units.name')
->get()
->map(fn ($item) => [
'unit_name' => $item->unit_name,
'total_good' => $formatNumber($item->total_good),
'total_broken' => $formatNumber($item->total_broken),
]);
// 2. Orders Stats - Combined count and sum
$orderStats = Order::whereDate('order_date', $today)
->selectRaw('count(*) as count, sum(total_amount) as total')
->first();
$orderCount = (int) ($orderStats->count ?? 0);
$orderRevenue = (float) ($orderStats->total ?? 0);
// 3. Delayed Goods Stats - Combined sum and paid_amount
$delayedStatsByUnit = DelayedGood::query()
->join('units', 'delayed_goods.unit_id', 'units.id')
->whereDate('delayed_goods.stored_date', $today)
->selectRaw('units.name as unit_name, sum(quantity) as total')
->groupBy('units.name')
->get()
->map(fn ($item) => [
'unit_name' => $item->unit_name,
'total' => $formatNumber($item->total),
]);
$delayedStatsTotals = DelayedGood::whereDate('stored_date', $today)
->selectRaw('sum(total_amount) as total, sum(paid_amount) as paid')
->first();
$delayedRevenue = (float) ($delayedStatsTotals->total ?? 0);
$paidToday = (float) ($delayedStatsTotals->paid ?? 0);
$totalRevenue = $orderRevenue + $delayedRevenue;
// 4. Expenses & Financials Today
$totalExpenses = (float) Expense::whereDate('expense_date', $today)->sum('amount');
$monthlyPayroll = (float) Payroll::where('period_month', $now->format('Y-m'))->sum('total_salary');
$totalFeedPurchase = (float) FeedPurchase::whereDate('purchase_date', $today)->sum('total_price');
$grossProfit = $totalRevenue - $totalFeedPurchase;
$netProfit = $grossProfit - $totalExpenses - $monthlyPayroll;
$totalReceivablesToday = $delayedRevenue - $paidToday;
$mainStats = [
['label' => 'Pesanan', 'desc' => 'Jumlah transaksi', 'value' => $orderCount, 'prefix' => ''],
['label' => 'Laba Bersih', 'desc' => 'Setelah dikurangi pengeluaran harian', 'value' => $formatNumber($netProfit), 'prefix' => 'Rp'],
['label' => 'Piutang', 'desc' => 'Piutang barang tertunda', 'value' => $formatNumber($totalReceivablesToday), 'prefix' => 'Rp'],
['label' => 'Pendapatan', 'desc' => 'Akumulasi pemasukan', 'value' => $formatNumber($totalRevenue), 'prefix' => 'Rp'],
['label' => 'Belanja Pakan', 'desc' => 'Baru dibeli', 'value' => $formatNumber($totalFeedPurchase), 'prefix' => 'Rp'],
];
// 5. Top Customers Today - Optimized summing
$topCustomers = Customer::query()
->select('id', 'name', 'phone_number')
->withSum(['orders' => fn ($q) => $q->whereDate('order_date', $today)], 'total_amount')
->withSum(['delayedGoods' => fn ($q) => $q->whereDate('stored_date', $today)], 'total_amount')
->get()
->map(function ($customer) {
$customer->total_spent = ($customer->orders_sum_total_amount ?? 0) + ($customer->delayed_goods_sum_total_amount ?? 0);
return $customer;
})
->filter(fn ($c) => $c->total_spent > 0)
->sortByDesc('total_spent')
->take(5)
->values();
// 6. Distribution Charts Data
$revenueSplitData = [
'labels' => ['Penjualan Langsung', 'Barang Tertunda'],
'data' => [$orderRevenue, $delayedRevenue],
];
$expenseDistributionData = [
'labels' => ['Belanja Pakan', 'Pengeluaran Umum'],
'data' => [$totalFeedPurchase, $totalExpenses],
];
$salesByUnit = Order::whereDate('order_date', $today)
->join('units', 'orders.unit_id', 'units.id')
->selectRaw('units.name, sum(total_amount) as total')
->groupBy('units.name')
->get();
return [
'isAdministrator' => auth()->user()->hasRole(RoleEnum::ADMINISTRATOR->value),
'mainStats' => $mainStats,
'totalEggsByUnit' => $totalEggsByUnit,
'totalDelayedByUnit' => $delayedStatsByUnit,
'topCustomers' => $topCustomers,
'revenueSplit' => $revenueSplitData,
'expenseDistribution' => $expenseDistributionData,
'salesByUnit' => [
'labels' => $salesByUnit->pluck('name')->values(),
'data' => $salesByUnit->pluck('total')->map(fn ($v) => (float) $v)->values(),
],
'formatNumber' => $formatNumber,
];
}
}