feat: Separate dashboard asset calculations for outlets and warehouses, update related descriptions, and refine perfume form layout.

This commit is contained in:
Yoga Pangestu 2026-02-12 23:11:57 +07:00
parent ee435131fc
commit 63ce676385
3 changed files with 55 additions and 47 deletions

View File

@ -123,7 +123,7 @@ public function render(): View
[ [
'title' => 'Outlet', 'title' => 'Outlet',
'value' => Outlet::when($dateQuery || ($startDate && $endDate), $filterDate)->count(), 'value' => Outlet::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
'description' => 'Total jumlah outlet atau cabang toko yang terdaftar.', 'description' => 'Total jumlah outlet atau cabang outlet yang terdaftar.',
], ],
[ [
'title' => 'Pegawai', 'title' => 'Pegawai',
@ -222,34 +222,32 @@ public function render(): View
$itemsPerOrder = $totalOrdersCount > 0 ? $totalItemsCount / $totalOrdersCount : 0; $itemsPerOrder = $totalOrdersCount > 0 ? $totalItemsCount / $totalOrdersCount : 0;
// Total Asset Calculation // Total Asset Calculation
$totalAsset = (int) Perfume::query() $totalOutletAsset = (int) Perfume::query()
->join('outlet_perfume', 'perfumes.id', '=', 'outlet_perfume.perfume_id') ->join('outlet_perfume', 'perfumes.id', '=', 'outlet_perfume.perfume_id')
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_perfume.outlet_id', $outletIds)) ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_perfume.outlet_id', $outletIds))
->sum(DB::raw('CAST(outlet_perfume.stock AS DECIMAL) * perfumes.cost_price')); ->sum(DB::raw('CAST(outlet_perfume.stock AS DECIMAL) * perfumes.cost_price'));
$totalAsset += (int) Product::query() $totalOutletAsset += (int) Product::query()
->join('outlet_product', 'products.id', '=', 'outlet_product.product_id') ->join('outlet_product', 'products.id', '=', 'outlet_product.product_id')
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_product.outlet_id', $outletIds)) ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_product.outlet_id', $outletIds))
->sum(DB::raw('CAST(outlet_product.stock AS DECIMAL) * products.cost_price')); ->sum(DB::raw('CAST(outlet_product.stock AS DECIMAL) * products.cost_price'));
$totalAsset += (int) Bottle::query() $totalOutletAsset += (int) Bottle::query()
->join('bottle_outlet', 'bottles.id', '=', 'bottle_outlet.bottle_id') ->join('bottle_outlet', 'bottles.id', '=', 'bottle_outlet.bottle_id')
->when(! empty($outletIds), fn ($q) => $q->whereIn('bottle_outlet.outlet_id', $outletIds)) ->when(! empty($outletIds), fn ($q) => $q->whereIn('bottle_outlet.outlet_id', $outletIds))
->sum(DB::raw('CAST(bottle_outlet.stock AS DECIMAL) * bottles.cost_price')); ->sum(DB::raw('CAST(bottle_outlet.stock AS DECIMAL) * bottles.cost_price'));
if (empty($this->selectedOutletIds)) { $totalWarehouseAsset = (int) Perfume::query()
$totalAsset += (int) Perfume::query()
->join('perfume_warehouse', 'perfumes.id', '=', 'perfume_warehouse.perfume_id') ->join('perfume_warehouse', 'perfumes.id', '=', 'perfume_warehouse.perfume_id')
->sum(DB::raw('CAST(perfume_warehouse.stock AS DECIMAL) * perfumes.cost_price')); ->sum(DB::raw('CAST(perfume_warehouse.stock AS DECIMAL) * perfumes.cost_price'));
$totalAsset += (int) Product::query() $totalWarehouseAsset += (int) Product::query()
->join('product_warehouse', 'products.id', '=', 'product_warehouse.product_id') ->join('product_warehouse', 'products.id', '=', 'product_warehouse.product_id')
->sum(DB::raw('CAST(product_warehouse.stock AS DECIMAL) * products.cost_price')); ->sum(DB::raw('CAST(product_warehouse.stock AS DECIMAL) * products.cost_price'));
$totalAsset += (int) Bottle::query() $totalWarehouseAsset += (int) Bottle::query()
->join('bottle_warehouse', 'bottles.id', '=', 'bottle_warehouse.bottle_id') ->join('bottle_warehouse', 'bottles.id', '=', 'bottle_warehouse.bottle_id')
->sum(DB::raw('CAST(bottle_warehouse.stock AS DECIMAL) * bottles.cost_price')); ->sum(DB::raw('CAST(bottle_warehouse.stock AS DECIMAL) * bottles.cost_price'));
}
$customerOrders = (clone $orderQuery)->select('customer_id', DB::raw('count(*) as count')) $customerOrders = (clone $orderQuery)->select('customer_id', DB::raw('count(*) as count'))
->whereNotNull('customer_id') ->whereNotNull('customer_id')
@ -271,9 +269,14 @@ public function render(): View
'description' => 'Persentase keuntungan bersih dibandingkan dengan total pendapatan.', 'description' => 'Persentase keuntungan bersih dibandingkan dengan total pendapatan.',
] : null, ] : null,
$user->hasRole(['Developer', 'Owner']) ? [ $user->hasRole(['Developer', 'Owner']) ? [
'title' => 'Total Aset', 'title' => 'Aset Outlet',
'value' => formatCurrencyNumber($totalAsset, 'Rp'), 'value' => formatCurrencyNumber($totalOutletAsset, 'Rp'),
'description' => 'Total nilai aset dari stok barang yang ada (Parfum, Produk, Botol) berdasarkan harga modal.', 'description' => 'Total nilai aset dari stok barang yang ada di outlet (Parfum, Produk, Botol) berdasarkan harga modal.',
] : null,
$user->hasRole(['Developer', 'Owner']) ? [
'title' => 'Aset Gudang',
'value' => formatCurrencyNumber($totalWarehouseAsset, 'Rp'),
'description' => 'Total nilai aset dari stok barang yang ada di gudang (Parfum, Produk, Botol) berdasarkan harga modal.',
] : null, ] : null,
[ [
'title' => 'Loyalty Rate', 'title' => 'Loyalty Rate',
@ -357,14 +360,14 @@ public function render(): View
$expenses = array_filter([ $expenses = array_filter([
[ [
'title' => 'Beban Toko', 'title' => 'Beban Outlet',
'value' => formatCurrencyNumber( 'value' => formatCurrencyNumber(
Expense::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds)) Expense::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
->when($dateQuery || ($startDate && $endDate), $filterDate) ->when($dateQuery || ($startDate && $endDate), $filterDate)
->sum('amount'), ->sum('amount'),
'Rp' 'Rp'
), ),
'description' => 'Total biaya operasional atau pengeluaran toko yang tercatat selama periode ini.', 'description' => 'Total biaya operasional atau pengeluaran outlet yang tercatat selama periode ini.',
], ],
$user->hasRole(['Developer', 'Owner']) ? [ $user->hasRole(['Developer', 'Owner']) ? [

View File

@ -166,35 +166,33 @@ public function render(): View
$todayProfitMargin = $todayIncome > 0 ? ($todayNetProfit / $todayIncome) * 100 : 0; $todayProfitMargin = $todayIncome > 0 ? ($todayNetProfit / $todayIncome) * 100 : 0;
$yesterdayProfitMargin = $yesterdayIncome > 0 ? ($yesterdayNetProfit / $yesterdayIncome) * 100 : 0; $yesterdayProfitMargin = $yesterdayIncome > 0 ? ($yesterdayNetProfit / $yesterdayIncome) * 100 : 0;
// New Card: Total Asset // Total Asset Calculation
$totalAsset = (int) Perfume::query() $totalOutletAsset = (int) Perfume::query()
->join('outlet_perfume', 'perfumes.id', 'outlet_perfume.perfume_id') ->join('outlet_perfume', 'perfumes.id', 'outlet_perfume.perfume_id')
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_perfume.outlet_id', $outletIds)) ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_perfume.outlet_id', $outletIds))
->sum(DB::raw('CAST(outlet_perfume.stock AS DECIMAL) * perfumes.cost_price')); ->sum(DB::raw('CAST(outlet_perfume.stock AS DECIMAL) * perfumes.cost_price'));
$totalAsset += (int) Product::query() $totalOutletAsset += (int) Product::query()
->join('outlet_product', 'products.id', 'outlet_product.product_id') ->join('outlet_product', 'products.id', 'outlet_product.product_id')
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_product.outlet_id', $outletIds)) ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_product.outlet_id', $outletIds))
->sum(DB::raw('CAST(outlet_product.stock AS DECIMAL) * products.cost_price')); ->sum(DB::raw('CAST(outlet_product.stock AS DECIMAL) * products.cost_price'));
$totalAsset += (int) Bottle::query() $totalOutletAsset += (int) Bottle::query()
->join('bottle_outlet', 'bottles.id', 'bottle_outlet.bottle_id') ->join('bottle_outlet', 'bottles.id', 'bottle_outlet.bottle_id')
->when(! empty($outletIds), fn ($q) => $q->whereIn('bottle_outlet.outlet_id', $outletIds)) ->when(! empty($outletIds), fn ($q) => $q->whereIn('bottle_outlet.outlet_id', $outletIds))
->sum(DB::raw('CAST(bottle_outlet.stock AS DECIMAL) * bottles.cost_price')); ->sum(DB::raw('CAST(bottle_outlet.stock AS DECIMAL) * bottles.cost_price'));
if (empty($this->selectedOutletIds)) { $totalWarehouseAsset = (int) Perfume::query()
$totalAsset += (int) Perfume::query()
->join('perfume_warehouse', 'perfumes.id', 'perfume_warehouse.perfume_id') ->join('perfume_warehouse', 'perfumes.id', 'perfume_warehouse.perfume_id')
->sum(DB::raw('CAST(perfume_warehouse.stock AS DECIMAL) * perfumes.cost_price')); ->sum(DB::raw('CAST(perfume_warehouse.stock AS DECIMAL) * perfumes.cost_price'));
$totalAsset += (int) Product::query() $totalWarehouseAsset += (int) Product::query()
->join('product_warehouse', 'products.id', 'product_warehouse.product_id') ->join('product_warehouse', 'products.id', 'product_warehouse.product_id')
->sum(DB::raw('CAST(product_warehouse.stock AS DECIMAL) * products.cost_price')); ->sum(DB::raw('CAST(product_warehouse.stock AS DECIMAL) * products.cost_price'));
$totalAsset += (int) Bottle::query() $totalWarehouseAsset += (int) Bottle::query()
->join('bottle_warehouse', 'bottles.id', 'bottle_warehouse.bottle_id') ->join('bottle_warehouse', 'bottles.id', 'bottle_warehouse.bottle_id')
->sum(DB::raw('CAST(bottle_warehouse.stock AS DECIMAL) * bottles.cost_price')); ->sum(DB::raw('CAST(bottle_warehouse.stock AS DECIMAL) * bottles.cost_price'));
}
// --- Chart Data Logic --- // --- Chart Data Logic ---
@ -336,9 +334,15 @@ public function render(): View
] : null, ] : null,
$user->hasRole(['Developer', 'Owner']) ? [ $user->hasRole(['Developer', 'Owner']) ? [
'title' => 'Total Aset', 'title' => 'Aset Outlet',
'value' => formatCurrencyNumber($totalAsset, 'Rp'), 'value' => formatCurrencyNumber($totalOutletAsset, 'Rp'),
'description' => 'Total nilai aset dari stok barang yang ada (Parfum, Produk, Botol) berdasarkan harga modal.', 'description' => 'Total nilai aset dari stok barang yang ada di outlet (Parfum, Produk, Botol) berdasarkan harga modal.',
] : null,
$user->hasRole(['Developer', 'Owner']) ? [
'title' => 'Aset Gudang',
'value' => formatCurrencyNumber($totalWarehouseAsset, 'Rp'),
'description' => 'Total nilai aset dari stok barang yang ada di gudang (Parfum, Produk, Botol) berdasarkan harga modal.',
] : null, ] : null,
[ [
@ -411,14 +415,14 @@ public function render(): View
], ],
[ [
'title' => 'Beban Toko', 'title' => 'Beban Outlet',
'value' => formatCurrencyNumber($todayExpense, 'Rp'), 'value' => formatCurrencyNumber($todayExpense, 'Rp'),
'previous' => formatCurrencyNumber($yesterdayExpense, 'Rp'), 'previous' => formatCurrencyNumber($yesterdayExpense, 'Rp'),
'trend' => $yesterdayExpense > 0 'trend' => $yesterdayExpense > 0
? round((($todayExpense - $yesterdayExpense) / $yesterdayExpense) * 100, 1).'%' ? round((($todayExpense - $yesterdayExpense) / $yesterdayExpense) * 100, 1).'%'
: '∞%', : '∞%',
'trendUp' => $todayExpense > $yesterdayExpense, 'trendUp' => $todayExpense > $yesterdayExpense,
'description' => 'Total biaya operasional atau pengeluaran toko yang tercatat selama periode ini.', 'description' => 'Total biaya operasional atau pengeluaran outlet yang tercatat selama periode ini.',
], ],
$user->hasRole(['Developer', 'Owner']) ? [ $user->hasRole(['Developer', 'Owner']) ? [

View File

@ -18,13 +18,14 @@
<div class="col-span-1 lg:col-span-2"> <div class="col-span-1 lg:col-span-2">
<flux:card class="space-y-6 p-6"> <flux:card class="space-y-6 p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="md:col-span-2">
<flux:field> <flux:field>
<flux:label>Nama <span class="text-red-500 ms-1">*</span></flux:label> <flux:label>Nama <span class="text-red-500 ms-1">*</span></flux:label>
<flux:input placeholder="Blue Emotion" wire:model="form.name" autofocus <flux:input placeholder="Blue Emotion" wire:model="form.name" autofocus
autocomplete="off" /> autocomplete="off" />
<flux:error name="form.name" /> <flux:error name="form.name" />
</flux:field> </flux:field>
</div>
<div class="lg:col-span-2"> <div class="lg:col-span-2">
<div <div