feat(warehouse): 庫存統計卡片加入總金額顯示 (可用/帳面)
All checks were successful
Koori-ERP-Deploy-System / deploy-demo (push) Has been skipped
Koori-ERP-Deploy-System / deploy-production (push) Successful in 48s

This commit is contained in:
2026-02-05 13:18:22 +08:00
parent dada3a6512
commit ba3c10ac13
2 changed files with 46 additions and 10 deletions

View File

@@ -30,8 +30,9 @@ class WarehouseController extends Controller
}
$warehouses = $query->withSum('inventories as book_stock', 'quantity') // 帳面庫存 = 所有庫存總和
->withSum('inventories as book_amount', 'total_value') // 帳面金額
->withSum(['inventories as available_stock' => function ($query) {
// 可用庫存 = 庫存 > 0 且 品質正常 且 (未過期 或 無效期) 且 倉庫類型不為瑕疵倉
// 可用庫存條件
$query->where('quantity', '>', 0)
->where('quality_status', 'normal')
->whereHas('warehouse', function ($q) {
@@ -42,6 +43,18 @@ class WarehouseController extends Controller
->orWhere('expiry_date', '>=', now());
});
}], 'quantity')
->withSum(['inventories as available_amount' => function ($query) {
// 可用金額條件 (與可用庫存一致)
$query->where('quantity', '>', 0)
->where('quality_status', 'normal')
->whereHas('warehouse', function ($q) {
$q->where('type', '!=', \App\Enums\WarehouseType::QUARANTINE);
})
->where(function ($q) {
$q->whereNull('expiry_date')
->orWhere('expiry_date', '>=', now());
});
}], 'total_value')
->addSelect(['low_stock_count' => function ($query) {
$query->selectRaw('count(*)')
->from('warehouse_product_safety_stocks as ss')
@@ -52,9 +65,6 @@ class WarehouseController extends Controller
->paginate($perPage)
->withQueryString();
// 移除原本對 is_sellable 的手動修正邏輯,現在由 type 自動過濾
// 計算全域總計 (不分頁)
$totals = [
'available_stock' => \App\Modules\Inventory\Models\Inventory::where('quantity', '>', 0)
@@ -66,7 +76,17 @@ class WarehouseController extends Controller
$q->whereNull('expiry_date')
->orWhere('expiry_date', '>=', now());
})->sum('quantity'),
'available_amount' => \App\Modules\Inventory\Models\Inventory::where('quantity', '>', 0)
->where('quality_status', 'normal')
->whereHas('warehouse', function ($q) {
$q->where('type', '!=', \App\Enums\WarehouseType::QUARANTINE);
})
->where(function ($q) {
$q->whereNull('expiry_date')
->orWhere('expiry_date', '>=', now());
})->sum('total_value'),
'book_stock' => \App\Modules\Inventory\Models\Inventory::sum('quantity'),
'book_amount' => \App\Modules\Inventory\Models\Inventory::sum('total_value'),
];
return Inertia::render('Warehouse/Index', [

View File

@@ -34,7 +34,9 @@ interface PageProps {
};
totals: {
available_stock: number;
available_amount: number;
book_stock: number;
book_amount: number;
};
filters: {
search?: string;
@@ -169,9 +171,16 @@ export default function WarehouseIndex({ warehouses, totals, filters }: PageProp
<CardContent className="p-6">
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-500 mb-1"></span>
<span className="text-3xl font-bold text-primary-main">
{totals.available_stock.toLocaleString()}
</span>
<div className="flex items-baseline gap-2">
<span className="text-3xl font-bold text-primary-main">
{totals.available_stock.toLocaleString()}
</span>
<Can permission="inventory.view_cost">
<span className="text-lg font-medium text-gray-400">
( ${totals.available_amount?.toLocaleString()} )
</span>
</Can>
</div>
</div>
</CardContent>
</Card>
@@ -180,9 +189,16 @@ export default function WarehouseIndex({ warehouses, totals, filters }: PageProp
<CardContent className="p-6">
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-500 mb-1"></span>
<span className="text-3xl font-bold text-gray-700">
{totals.book_stock.toLocaleString()}
</span>
<div className="flex items-baseline gap-2">
<span className="text-3xl font-bold text-gray-700">
{totals.book_stock.toLocaleString()}
</span>
<Can permission="inventory.view_cost">
<span className="text-lg font-medium text-gray-400">
( ${totals.book_amount?.toLocaleString()} )
</span>
</Can>
</div>
</div>
</CardContent>
</Card>