feat(overview): membuat counting data
This commit is contained in:
parent
f38252cd34
commit
33ebebbe68
@ -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');
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user