From f22df90e0120df2776871b52816c99ccc0d599bf Mon Sep 17 00:00:00 2001 From: sky121113 Date: Fri, 6 Feb 2026 17:35:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(Inventory):=20=E4=BF=AE=E5=BE=A9=E5=BA=AB?= =?UTF-8?q?=E5=AD=98=E5=88=97=E8=A1=A8=E6=89=B9=E8=99=9F=E6=AC=84=E4=BD=8D?= =?UTF-8?q?=E8=88=87=E6=96=B0=E5=A2=9E=E5=BA=AB=E5=AD=98=E9=A0=81=E9=9D=A2?= =?UTF-8?q?=E5=84=B2=E4=BD=8D=E6=AC=84=E4=BD=8D=E9=81=BA=E5=A4=B1=E5=95=8F?= =?UTF-8?q?=E9=A1=8C=EF=BC=8C=E4=B8=A6=E9=82=84=E5=8E=9F=E6=89=B9=E8=99=9F?= =?UTF-8?q?=E8=BC=B8=E5=85=A5=E4=BD=88=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/InventoryController.php | 3 +++ .../Exports/InventoryTemplateExport.php | 16 +++++++++++++--- .../Inventory/Imports/InventoryImport.php | 9 +++++++-- .../Inventory/InventoryImportDialog.tsx | 2 +- .../Warehouse/Inventory/InventoryTable.tsx | 10 ++++++++-- resources/js/Pages/Warehouse/AddInventory.tsx | 13 +++++++++++++ resources/js/Pages/Warehouse/Inventory.tsx | 1 + resources/js/types/warehouse.ts | 2 ++ 8 files changed, 48 insertions(+), 8 deletions(-) diff --git a/app/Modules/Inventory/Controllers/InventoryController.php b/app/Modules/Inventory/Controllers/InventoryController.php index eb768e7..b3a6502 100644 --- a/app/Modules/Inventory/Controllers/InventoryController.php +++ b/app/Modules/Inventory/Controllers/InventoryController.php @@ -98,6 +98,7 @@ class InventoryController extends Controller 'safetyStock' => null, // 批號層級不再有安全庫存 'status' => '正常', 'batchNumber' => $inv->batch_number ?? 'BATCH-' . $inv->id, + 'location' => $inv->location, 'expiryDate' => $inv->expiry_date ? $inv->expiry_date->format('Y-m-d') : null, 'lastInboundDate' => $inv->lastIncomingTransaction ? ($inv->lastIncomingTransaction->actual_time ? $inv->lastIncomingTransaction->actual_time->format('Y-m-d') : $inv->lastIncomingTransaction->created_at->format('Y-m-d')) : null, 'lastOutboundDate' => $inv->lastOutgoingTransaction ? ($inv->lastOutgoingTransaction->actual_time ? $inv->lastOutgoingTransaction->actual_time->format('Y-m-d') : $inv->lastOutgoingTransaction->created_at->format('Y-m-d')) : null, @@ -171,6 +172,7 @@ class InventoryController extends Controller 'items.*.inventoryId' => 'required_if:items.*.batchMode,existing|nullable|exists:inventories,id', 'items.*.originCountry' => 'required_if:items.*.batchMode,new|nullable|string|max:2', 'items.*.expiryDate' => 'nullable|date', + 'items.*.location' => 'nullable|string|max:50', ]); return DB::transaction(function () use ($validated, $warehouse) { @@ -233,6 +235,7 @@ class InventoryController extends Controller 'quantity' => 0, 'unit_cost' => $item['unit_cost'] ?? 0, // 新增 'total_value' => 0, // 稍後計算 + 'location' => $item['location'] ?? null, 'arrival_date' => $validated['inboundDate'], 'expiry_date' => $item['expiryDate'] ?? null, 'origin_country' => $originCountry, diff --git a/app/Modules/Inventory/Exports/InventoryTemplateExport.php b/app/Modules/Inventory/Exports/InventoryTemplateExport.php index 139c1bf..fb2b861 100644 --- a/app/Modules/Inventory/Exports/InventoryTemplateExport.php +++ b/app/Modules/Inventory/Exports/InventoryTemplateExport.php @@ -34,7 +34,9 @@ class InventoryDataSheet implements FromArray, WithHeadings, WithTitle, ShouldAu '商品代號', '商品名稱', '數量', + '單位', '入庫單價', + '儲位/貨道', '批號', '產地', '效期', @@ -56,14 +58,22 @@ class InventoryInstructionSheet implements FromArray, WithHeadings, WithTitle, S ['商品代號', '擇一輸入', '若條碼未填寫,系統會依據代號匹配商品'], ['商品名稱', '選填', '僅供對照參考,匯入時系統會自動忽略此欄位內容'], ['數量', '必填', '入庫的商品數量,須為大於 0 的數字'], + ['單位', '必填', '單位 (如:個、件)'], ['入庫單價', '選填', '未填寫時將預設使用商品的「採購成本價」'], + ['儲位/貨道', '選填', '一般倉庫請填寫「儲位(位址)」,販賣機倉庫請填寫「貨道編號」(如: A1)'], ['批號', '選填', '如需批次控管請填寫,若留空系統會自動標記為 "NO-BATCH"'], ['產地', '選填', '商品的生產地資訊 (如:TW)'], ['效期', '選填', '格式請務必使用 YYYY-MM-DD (例如: 2026-12-31)'], ['', '', ''], - ['匹配規則說明', '', '1. 系統會優先比對「商品條碼」。'], - ['', '', '2. 若條碼欄位為空,則嘗試比對「商品代號」。'], - ['', '', '3. 若上述兩者皆無法匹配到既有商品,該列資料將匯入失敗。'], + ['倉庫類型參考', '', '系統支援以下倉庫性質:'], + ['標準倉', '', '一般總倉、儲備倉'], + ['生產倉', '', '加工廠、中央廚房、原材料存放處'], + ['門市倉', '', '前台通路、店舖銷售現場'], + ['販賣機', '', 'IoT 自動販賣機設備,建議搭配「貨道」填寫'], + ['', '', ''], + ['匹配與匯入規則', '', '1. 系統會優先比對「商品條碼」,其次為「商品代號」。'], + ['', '', '2. 庫存將匯入至您在匯入前於系統介面所選擇的目標倉庫。'], + ['', '', '3. 若需區分不同貨道或批次,請分行填寫。'], ]; } diff --git a/app/Modules/Inventory/Imports/InventoryImport.php b/app/Modules/Inventory/Imports/InventoryImport.php index 13f9813..b6cd9ec 100644 --- a/app/Modules/Inventory/Imports/InventoryImport.php +++ b/app/Modules/Inventory/Imports/InventoryImport.php @@ -55,18 +55,20 @@ class InventoryImport implements ToModel, WithHeadingRow, WithValidation, WithMa $quantity = (float) $row['數量']; $unitCost = isset($row['入庫單價']) ? (float) $row['入庫單價'] : ($product->cost_price ?? 0); + $location = $row['儲位/貨道'] ?? null; // 批號邏輯:若 Excel 留空則使用 NO-BATCH $batchNumber = !empty($row['批號']) ? $row['批號'] : 'NO-BATCH'; $originCountry = $row['產地'] ?? 'TW'; $expiryDate = !empty($row['效期']) ? $row['效期'] : null; - return DB::transaction(function () use ($product, $quantity, $unitCost, $batchNumber, $originCountry, $expiryDate) { + return DB::transaction(function () use ($product, $quantity, $unitCost, $location, $batchNumber, $originCountry, $expiryDate) { // 使用與 InventoryController 相同的 firstOrNew 邏輯 $inventory = $this->warehouse->inventories()->withTrashed()->firstOrNew( [ 'product_id' => $product->id, - 'batch_number' => $batchNumber + 'batch_number' => $batchNumber, + 'location' => $location, // 加入儲位/貨道作為區分關鍵字 ], [ 'quantity' => 0, @@ -114,7 +116,10 @@ class InventoryImport implements ToModel, WithHeadingRow, WithValidation, WithMa '商品條碼' => ['nullable', 'string'], '商品代號' => ['nullable', 'string'], '數量' => ['required', 'numeric', 'min:0.01'], + '單位' => ['required', 'string'], '入庫單價' => ['nullable', 'numeric', 'min:0'], + '儲位/貨道' => ['nullable', 'string', 'max:50'], + '批號' => ['nullable', 'string'], '效期' => ['nullable', 'date'], '產地' => ['nullable', 'string', 'max:2'], ]; diff --git a/resources/js/Components/Warehouse/Inventory/InventoryImportDialog.tsx b/resources/js/Components/Warehouse/Inventory/InventoryImportDialog.tsx index 5695cb3..904d610 100644 --- a/resources/js/Components/Warehouse/Inventory/InventoryImportDialog.tsx +++ b/resources/js/Components/Warehouse/Inventory/InventoryImportDialog.tsx @@ -162,7 +162,7 @@ export default function InventoryImportDialog({ open, onOpenChange, warehouseId
diff --git a/resources/js/Components/Warehouse/Inventory/InventoryTable.tsx b/resources/js/Components/Warehouse/Inventory/InventoryTable.tsx index c5fbe15..d54034c 100644 --- a/resources/js/Components/Warehouse/Inventory/InventoryTable.tsx +++ b/resources/js/Components/Warehouse/Inventory/InventoryTable.tsx @@ -42,7 +42,11 @@ export default function InventoryTable({ onView, onDelete, onViewProduct, -}: InventoryTableProps) { + warehouse, +}: InventoryTableProps & { warehouse: any }) { + // 判斷是否為販賣機倉庫 + const isVending = warehouse?.type === "vending"; + // 每個商品的展開/折疊狀態 const [expandedProducts, setExpandedProducts] = useState>(new Set()); @@ -197,7 +201,8 @@ export default function InventoryTable({ # - 批號 + 批號 + {isVending ? "貨道" : "儲位"} 庫存數量 單位成本 @@ -215,6 +220,7 @@ export default function InventoryTable({ {index + 1} {batch.batchNumber || "-"} + {batch.location || "-"} {batch.quantity} {batch.unit} diff --git a/resources/js/Pages/Warehouse/AddInventory.tsx b/resources/js/Pages/Warehouse/AddInventory.tsx index 5fe0e59..c348cff 100644 --- a/resources/js/Pages/Warehouse/AddInventory.tsx +++ b/resources/js/Pages/Warehouse/AddInventory.tsx @@ -510,6 +510,9 @@ export default function AddInventoryPage({ warehouse, products }: Props) { 數量 * 單位 + + {warehouse.type === 'vending' ? '貨道' : '儲位'} + @@ -714,6 +717,16 @@ export default function AddInventoryPage({ warehouse, products }: Props) { )} + {/* 儲位/貨道 */} + + handleUpdateItem(item.tempId, { location: e.target.value })} + className="border-gray-300" + placeholder={warehouse.type === 'vending' ? "貨道 (如: A1)" : "儲位 (選填)"} + /> + + {/* 刪除按鈕 */}
!open && setDeleteId(null)}> diff --git a/resources/js/types/warehouse.ts b/resources/js/types/warehouse.ts index 3347767..14841d5 100644 --- a/resources/js/types/warehouse.ts +++ b/resources/js/types/warehouse.ts @@ -47,6 +47,7 @@ export interface WarehouseInventory { safetyStock: number | null; status?: '正常' | '低於'; // 後端可能回傳的狀態 batchNumber: string; // 批號 (Mock for now) + location?: string; // 儲位/貨道 expiryDate: string; lastInboundDate: string | null; lastOutboundDate: string | null; @@ -177,6 +178,7 @@ export interface InboundItem { batchMode?: 'existing' | 'new' | 'none'; // 批號模式 inventoryId?: string; // 選擇現有批號時的 ID batchNumber?: string; + location?: string; // 儲位/貨道 originCountry?: string; // 新增產地 expiryDate?: string; }