feat(overview): membuat counting data

This commit is contained in:
Yoga Pangestu 2025-11-11 10:47:05 +07:00
parent f38252cd34
commit 33ebebbe68
2 changed files with 264 additions and 1 deletions

View File

@ -2,12 +2,246 @@
namespace App\Livewire\Studio\Dashboard;
use App\Models\Expense;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Perfume;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Ringkasan')]
class Overview extends Component
{
public array $outlets = [];
public array $selectedOutletIds = [];
public array $stats = [];
public function mount()
{
$this->outlets = auth()->user()->outlets()->get()->pluck('name', 'id')->toArray();
$this->loadStats();
}
public function updatedSelectedOutletIds()
{
$this->loadStats();
}
protected function loadStats()
{
$outletIds = $this->selectedOutletIds;
$todayOrder = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->today()
->count();
$yesterdayOrder = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->yesterday()
->count();
$todayIncome = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->paid()
->today()
->sum('total');
$yesterdayIncome = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->paid()
->yesterday()
->sum('total');
$todayCogs = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->paid()
->today()
->sum('cogs');
$yesterdayCogs = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->paid()
->yesterday()
->sum('cogs');
$todayDiscount = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->paid()
->today()
->sum('discount');
$yesterdayDiscount = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->paid()
->yesterday()
->sum('discount');
$todayVoucher = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->today()
->whereNotNull('voucher_id')
->count();
$yesterdayVoucher = Order::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->yesterday()
->whereNotNull('voucher_id')
->count();
$todayExpense = Expense::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->today()
->sum('amount');
$yesterdayExpense = Expense::query()
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->yesterday()
->sum('amount');
$todayGrossProfit = $todayIncome - $todayCogs - $todayDiscount;
$yesterdayGrossProfit = $yesterdayIncome - $yesterdayCogs - $yesterdayDiscount;
$todayNetProfit = $todayGrossProfit - $todayExpense;
$yesterdayNetProfit = $yesterdayGrossProfit - $yesterdayExpense;
$todaySoldPerfume = OrderItem::where('orderable_type', Perfume::class)
->whereHas(
'order',
fn ($q) => $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
)
->sum('quantity');
$yesterdaySoldPerfume = OrderItem::where('orderable_type', Perfume::class)
->whereHas(
'order',
fn ($q) => $q->yesterday()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
)
->sum('quantity');
$todayTopPerfume = OrderItem::where('orderable_type', Perfume::class)
->whereHas(
'order',
fn ($q) => $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
)
->select('orderable_id', 'orderable_type', DB::raw('SUM(quantity) as total_sold'))
->groupBy('orderable_id', 'orderable_type')
->orderByDesc('total_sold')
->with('orderable')
->first();
$yesterdayTopPerfume = OrderItem::where('orderable_type', Perfume::class)
->whereHas(
'order',
fn ($q) => $q->yesterday()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
)
->select('orderable_id', 'orderable_type', DB::raw('SUM(quantity) as total_sold'))
->groupBy('orderable_id', 'orderable_type')
->orderByDesc('total_sold')
->with('orderable')
->first();
$this->stats = [
[
'title' => 'Total Order',
'value' => $todayOrder,
'previous' => $yesterdayOrder,
'trend' => $yesterdayOrder > 0
? round((($todayOrder - $yesterdayOrder) / $yesterdayOrder) * 100, 1).'%'
: '∞%',
'trendUp' => $todayOrder > $yesterdayOrder,
],
[
'title' => 'Pendapatan',
'value' => currency($todayIncome, 'Rp'),
'previous' => currency($yesterdayIncome, 'Rp'),
'trend' => $yesterdayIncome > 0
? round((($todayIncome - $yesterdayIncome) / $yesterdayIncome) * 100, 1).'%'
: '∞%',
'trendUp' => $todayIncome > $yesterdayIncome,
'formatted' => currency($todayIncome, 'Rp'),
],
[
'title' => 'HPP',
'value' => currency($todayCogs, 'Rp'),
'previous' => currency($yesterdayCogs, 'Rp'),
'trend' => $yesterdayCogs > 0
? round((($todayCogs - $yesterdayCogs) / $yesterdayCogs) * 100, 1).'%'
: '∞%',
'trendUp' => $todayCogs > $yesterdayCogs,
'formatted' => currency($todayCogs, 'Rp'),
],
[
'title' => 'Diskon',
'value' => currency($todayDiscount, 'Rp'),
'previous' => currency($yesterdayDiscount, 'Rp'),
'trend' => $yesterdayDiscount > 0
? round((($todayDiscount - $yesterdayDiscount) / $yesterdayDiscount) * 100, 1).'%'
: '∞%',
'trendUp' => $todayDiscount > $yesterdayDiscount,
'formatted' => currency($todayDiscount, 'Rp'),
],
[
'title' => 'Voucher Terpakai',
'value' => $todayVoucher,
'previous' => $yesterdayVoucher,
'trend' => $yesterdayVoucher > 0
? round((($todayVoucher - $yesterdayVoucher) / $yesterdayVoucher) * 100, 1).'%'
: '∞%',
'trendUp' => $todayVoucher > $yesterdayVoucher,
],
[
'title' => 'Pengeluaran',
'value' => currency($todayExpense, 'Rp'),
'previous' => currency($yesterdayExpense, 'Rp'),
'trend' => $yesterdayExpense > 0
? round((($todayExpense - $yesterdayExpense) / $yesterdayExpense) * 100, 1).'%'
: '∞%',
'trendUp' => $todayExpense > $yesterdayExpense,
],
[
'title' => 'Laba Kotor',
'value' => currency($todayGrossProfit, 'Rp'),
'previous' => currency($yesterdayGrossProfit, 'Rp'),
'trend' => $yesterdayGrossProfit > 0
? round((($todayGrossProfit - $yesterdayGrossProfit) / $yesterdayGrossProfit) * 100, 1).'%'
: '∞%',
'trendUp' => $todayGrossProfit > $yesterdayGrossProfit,
],
[
'title' => 'Laba Bersih',
'value' => currency($todayNetProfit, 'Rp'),
'previous' => currency($yesterdayNetProfit, 'Rp'),
'trend' => $yesterdayNetProfit > 0
? round((($todayNetProfit - $yesterdayNetProfit) / $yesterdayNetProfit) * 100, 1).'%'
: '∞%',
'trendUp' => $todayNetProfit > $yesterdayNetProfit,
],
[
'title' => 'Parfum Terjual',
'value' => $todaySoldPerfume.' ml',
'previous' => $yesterdaySoldPerfume.' ml',
'trend' => $yesterdaySoldPerfume > 0
? round((($todaySoldPerfume - $yesterdaySoldPerfume) / $yesterdaySoldPerfume) * 100, 1).'%'
: '∞%',
'trendUp' => $todaySoldPerfume > $yesterdaySoldPerfume,
],
[
'title' => 'Top Parfum',
'value' => optional($todayTopPerfume?->orderable)->name.' ('.$todayTopPerfume?->total_sold.'ml)' ?? '-',
'previous' => optional($yesterdayTopPerfume?->orderable)->name.'('.$yesterdayTopPerfume?->total_sold.'ml)' ?? '-',
'trend' => ($yesterdayTopPerfume && $yesterdayTopPerfume->total_sold > 0)
? round((($todayTopPerfume?->total_sold - $yesterdayTopPerfume?->total_sold) / $yesterdayTopPerfume?->total_sold) * 100, 1).'%'
: '∞%',
'trendUp' => ($todayTopPerfume?->total_sold ?? 0) > ($yesterdayTopPerfume?->total_sold ?? 0),
],
];
}
public function render()
{
return view('livewire.studio.dashboard.overview');

View File

@ -1,5 +1,34 @@
<flux:main>
<flux:heading size="xl" level="1">Haloo, {{ auth()->user()?->employee?->full_name }}</flux:heading>
<flux:text class="mb-6 mt-2 text-base">Selamat datang di Studio Yadi Parfum.</flux:text>
<flux:separator variant="subtle" />
<flux:separator />
<div class="mt-6">
<div class="mb-6 grid grid-cols-1 lg:grid-cols-2 gap-4">
<flux:checkbox.group wire:model.live="selectedOutletIds" variant="buttons">
@foreach ($outlets as $key => $value)
<flux:checkbox value="{{ $key }}" label="{{ $value }}" />
@endforeach
</flux:checkbox.group>
</div>
<flux:subheading>Data yang ditampilkan di bawah ini adalah data hari ini dan hari kemarin.</flux:subheading>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-6 mt-2">
@foreach ($stats as $stat)
<div
class="@if ($stat['title'] === 'Top Parfum') md:col-span-2 xl:col-span-2 @endif rounded-lg px-6 py-4 bg-zinc-50 dark:bg-zinc-700">
<flux:subheading>{{ $stat['title'] }}</flux:subheading>
<div class="flex items-center justify-between">
<flux:heading size="xl">{{ $stat['value'] }}</flux:heading>
<flux:subheading size="xs">{{ $stat['previous'] }}</flux:subheading>
</div>
<div
class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-green-600 dark:text-green-400 @else text-red-500 dark:text-red-400 @endif">
<flux:icon :icon="$stat['trendUp'] ? 'arrow-trending-up' : 'arrow-trending-down'"
variant="micro" />
{{ $stat['trend'] }}
</div>
</div>
@endforeach
</div>
</div>
</flux:main>