refactor(inventory): 重構倉庫管理邏輯,移除 is_sellable 欄位並改由類型判定可用庫存
This commit is contained in:
@@ -26,9 +26,12 @@ class WarehouseController extends Controller
|
||||
|
||||
$warehouses = $query->withSum('inventories as book_stock', 'quantity') // 帳面庫存 = 所有庫存總和
|
||||
->withSum(['inventories as available_stock' => function ($query) {
|
||||
// 可用庫存 = 庫存 > 0 且 品質正常 且 (未過期 或 無效期)
|
||||
// 可用庫存 = 庫存 > 0 且 品質正常 且 (未過期 或 無效期) 且 倉庫類型不為瑕疵倉
|
||||
$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());
|
||||
@@ -38,20 +41,15 @@ class WarehouseController extends Controller
|
||||
->paginate(10)
|
||||
->withQueryString();
|
||||
|
||||
// 修正各倉庫列表中的可用庫存計算:若倉庫不可銷售,則可用庫存為 0
|
||||
$warehouses->getCollection()->transform(function ($w) {
|
||||
if (!$w->is_sellable) {
|
||||
$w->available_stock = 0;
|
||||
}
|
||||
return $w;
|
||||
});
|
||||
// 移除原本對 is_sellable 的手動修正邏輯,現在由 type 自動過濾
|
||||
|
||||
|
||||
// 計算全域總計 (不分頁)
|
||||
$totals = [
|
||||
'available_stock' => \App\Modules\Inventory\Models\Inventory::where('quantity', '>', 0)
|
||||
->where('quality_status', 'normal')
|
||||
->whereHas('warehouse', function ($q) {
|
||||
$q->where('is_sellable', true);
|
||||
$q->where('type', '!=', \App\Enums\WarehouseType::QUARANTINE);
|
||||
})
|
||||
->where(function ($q) {
|
||||
$q->whereNull('expiry_date')
|
||||
@@ -73,7 +71,6 @@ class WarehouseController extends Controller
|
||||
'name' => 'required|string|max:50',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'is_sellable' => 'nullable|boolean',
|
||||
'type' => 'required|string',
|
||||
'license_plate' => 'nullable|string|max:20',
|
||||
'driver_name' => 'nullable|string|max:50',
|
||||
@@ -98,7 +95,6 @@ class WarehouseController extends Controller
|
||||
'name' => 'required|string|max:50',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'is_sellable' => 'nullable|boolean',
|
||||
'type' => 'required|string',
|
||||
'license_plate' => 'nullable|string|max:20',
|
||||
'driver_name' => 'nullable|string|max:50',
|
||||
|
||||
@@ -18,13 +18,11 @@ class Warehouse extends Model
|
||||
'type',
|
||||
'address',
|
||||
'description',
|
||||
'is_sellable',
|
||||
'license_plate',
|
||||
'driver_name',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_sellable' => 'boolean',
|
||||
'type' => \App\Enums\WarehouseType::class,
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('warehouses', function (Blueprint $table) {
|
||||
$table->dropColumn('is_sellable');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('warehouses', function (Blueprint $table) {
|
||||
$table->boolean('is_sellable')->default(true)->after('description')->comment('是否可銷售');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -100,12 +100,18 @@ export default function WarehouseCard({
|
||||
|
||||
{/* 統計區塊 - 狀態標籤 */}
|
||||
<div className="space-y-3">
|
||||
{/* 銷售狀態 */}
|
||||
{/* 銷售狀態與可用性說明 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-gray-500">銷售狀態</span>
|
||||
<Badge variant={warehouse.is_sellable ? "default" : "secondary"} className={warehouse.is_sellable ? "bg-green-600" : "bg-gray-400"}>
|
||||
{warehouse.is_sellable ? "可銷售" : "暫停銷售"}
|
||||
</Badge>
|
||||
<span className="text-sm text-gray-500">庫存可用性</span>
|
||||
{warehouse.type === 'quarantine' ? (
|
||||
<Badge variant="secondary" className="bg-red-100 text-red-700 border-red-200">
|
||||
不計入可用
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="default" className="bg-green-600">
|
||||
計入可用
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 低庫存警告狀態 */}
|
||||
|
||||
@@ -62,7 +62,6 @@ export default function WarehouseDialog({
|
||||
address: string;
|
||||
description: string;
|
||||
type: WarehouseType;
|
||||
is_sellable: boolean;
|
||||
license_plate: string;
|
||||
driver_name: string;
|
||||
}>({
|
||||
@@ -71,7 +70,6 @@ export default function WarehouseDialog({
|
||||
address: "",
|
||||
description: "",
|
||||
type: "standard",
|
||||
is_sellable: true,
|
||||
license_plate: "",
|
||||
driver_name: "",
|
||||
});
|
||||
@@ -86,7 +84,6 @@ export default function WarehouseDialog({
|
||||
address: warehouse.address || "",
|
||||
description: warehouse.description || "",
|
||||
type: warehouse.type || "standard",
|
||||
is_sellable: warehouse.is_sellable ?? true,
|
||||
license_plate: warehouse.license_plate || "",
|
||||
driver_name: warehouse.driver_name || "",
|
||||
});
|
||||
@@ -97,7 +94,6 @@ export default function WarehouseDialog({
|
||||
address: "",
|
||||
description: "",
|
||||
type: "standard",
|
||||
is_sellable: true,
|
||||
license_plate: "",
|
||||
driver_name: "",
|
||||
});
|
||||
@@ -219,25 +215,7 @@ export default function WarehouseDialog({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 銷售設定 */}
|
||||
<div className="space-y-4">
|
||||
<div className="border-b pb-2">
|
||||
<h4 className="text-sm text-gray-700">銷售設定</h4>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="is_sellable"
|
||||
className="h-4 w-4 rounded border-gray-300 text-primary-main focus:ring-primary-main"
|
||||
checked={formData.is_sellable}
|
||||
onChange={(e) => setFormData({ ...formData, is_sellable: e.target.checked })}
|
||||
/>
|
||||
<Label htmlFor="is_sellable">此倉庫可進行銷售扣庫</Label>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 ml-6">
|
||||
啟用後,該倉庫庫存可用於 POS 或訂單銷售扣減。總倉通常不啟用,門市與行動販賣車需啟用。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 區塊 B:位置 */}
|
||||
<div className="space-y-4">
|
||||
|
||||
@@ -25,7 +25,6 @@ export interface Warehouse {
|
||||
total_quantity?: number;
|
||||
low_stock_count?: number;
|
||||
type?: WarehouseType;
|
||||
is_sellable?: boolean;
|
||||
license_plate?: string; // 車牌號碼 (移動倉)
|
||||
driver_name?: string; // 司機姓名 (移動倉)
|
||||
book_stock?: number;
|
||||
|
||||
Reference in New Issue
Block a user