From 200d1989bd72018d1d969fdafb7f5ab1f0d7d9a2 Mon Sep 17 00:00:00 2001 From: sky121113 Date: Fri, 6 Feb 2026 15:56:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(inventory):=20=E6=94=AF=E6=8F=B4=E5=BA=AB?= =?UTF-8?q?=E5=AD=98=E6=96=B0=E5=A2=9E=E4=B8=8D=E4=BD=BF=E7=94=A8=E6=89=B9?= =?UTF-8?q?=E8=99=9F=E6=A8=A1=E5=BC=8F=E8=88=87=E8=87=AA=E5=8B=95=E7=B4=AF?= =?UTF-8?q?=E5=8A=A0=E9=82=8F=E8=BC=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/InventoryController.php | 22 ++++- resources/js/Pages/Warehouse/AddInventory.tsx | 91 +++++++++++-------- resources/js/types/warehouse.ts | 2 +- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/app/Modules/Inventory/Controllers/InventoryController.php b/app/Modules/Inventory/Controllers/InventoryController.php index 68eada4..d77f6ab 100644 --- a/app/Modules/Inventory/Controllers/InventoryController.php +++ b/app/Modules/Inventory/Controllers/InventoryController.php @@ -163,7 +163,7 @@ class InventoryController extends Controller 'items.*.productId' => 'required|exists:products,id', 'items.*.quantity' => 'required|numeric|min:0.01', 'items.*.unit_cost' => 'nullable|numeric|min:0', // 新增成本驗證 - 'items.*.batchMode' => 'required|in:existing,new', + 'items.*.batchMode' => 'required|in:existing,new,none', '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', @@ -188,6 +188,26 @@ class InventoryController extends Controller if (isset($item['unit_cost'])) { $inventory->unit_cost = $item['unit_cost']; } + } elseif ($item['batchMode'] === 'none') { + // 模式 C:不使用批號 (自動累加至 NO-BATCH) + $inventory = $warehouse->inventories()->withTrashed()->firstOrNew( + [ + 'product_id' => $item['productId'], + 'batch_number' => 'NO-BATCH' + ], + [ + 'quantity' => 0, + 'unit_cost' => $item['unit_cost'] ?? 0, + 'total_value' => 0, + 'arrival_date' => $validated['inboundDate'], + 'expiry_date' => null, + 'origin_country' => 'TW', + ] + ); + + if ($inventory->trashed()) { + $inventory->restore(); + } } else { // 模式 B:建立新批號 $originCountry = $item['originCountry'] ?? 'TW'; diff --git a/resources/js/Pages/Warehouse/AddInventory.tsx b/resources/js/Pages/Warehouse/AddInventory.tsx index 8110059..5fe0e59 100644 --- a/resources/js/Pages/Warehouse/AddInventory.tsx +++ b/resources/js/Pages/Warehouse/AddInventory.tsx @@ -548,7 +548,7 @@ export default function AddInventoryPage({ warehouse, products }: Props) {
{ if (value === 'new_batch') { handleUpdateItem(item.tempId, { @@ -557,6 +557,15 @@ export default function AddInventoryPage({ warehouse, products }: Props) { originCountry: 'TW', expiryDate: undefined }); + } else if (value === 'no_batch') { + // 嘗試匹配現有的 NO-BATCH 紀錄 + const existingNoBatch = (batchesCache[item.productId]?.batches || []).find(b => b.batchNumber === 'NO-BATCH'); + handleUpdateItem(item.tempId, { + batchMode: 'none', + inventoryId: existingNoBatch?.inventoryId || undefined, + originCountry: 'TW', + expiryDate: undefined + }); } else { const selectedBatch = (batchesCache[item.productId]?.batches || []).find(b => b.inventoryId === value); handleUpdateItem(item.tempId, { @@ -568,9 +577,10 @@ export default function AddInventoryPage({ warehouse, products }: Props) { } }} options={[ + { label: "📦 不使用批號 (自動累加)", value: "no_batch" }, { label: "+ 建立新批號", value: "new_batch" }, ...(batchesCache[item.productId]?.batches || []).map(b => ({ - label: `${b.batchNumber} - 庫存: ${b.quantity}`, + label: `${b.batchNumber === 'NO-BATCH' ? '(無批號紀錄)' : b.batchNumber} - 庫存: ${b.quantity}`, value: b.inventoryId })) ]} @@ -582,50 +592,55 @@ export default function AddInventoryPage({ warehouse, products }: Props) { {errors[`item-${index}-batch`]}

)} - {item.batchMode === 'new' && ( - <> -
-
- { - const val = e.target.value.toUpperCase().slice(0, 2); - handleUpdateItem(item.tempId, { originCountry: val }); - }} - maxLength={2} - placeholder="產地" - className="h-8 text-xs text-center border-gray-300" - /> -
-
- {getBatchPreview(item.productId, product?.code, item.originCountry || 'TW', inboundDate)} -
+
+
+ { + const val = e.target.value.toUpperCase().slice(0, 2); + handleUpdateItem(item.tempId, { originCountry: val }); + }} + maxLength={2} + placeholder="產地" + className="h-8 text-xs text-center border-gray-300" + />
- {/* 新增效期輸入 (在新增批號模式下) */} -
- 效期: -
- - - handleUpdateItem(item.tempId, { - expiryDate: e.target.value, - }) - } - className="h-8 pl-8 text-xs border-gray-300 w-full" - /> -
+
+ {getBatchPreview(item.productId, product?.code, item.originCountry || 'TW', inboundDate)}
- +
+ )} + {/* 新增效期輸入 (僅在建立新批號模式下) */} + {item.batchMode === 'new' && ( +
+ 效期: +
+ + + handleUpdateItem(item.tempId, { + expiryDate: e.target.value, + }) + } + className="h-8 pl-8 text-xs border-gray-300 w-full" + /> +
+
+ )} + {item.batchMode === 'none' && ( +
+ INFO + 系統將自動累加至該商品的通用庫存紀錄 +
)} {item.batchMode === 'existing' && item.inventoryId && (
- 效期: {item.expiryDate || '未設定'} + 效期: {item.expiryDate || '無效期紀錄'}
)} diff --git a/resources/js/types/warehouse.ts b/resources/js/types/warehouse.ts index 2d90ccc..3347767 100644 --- a/resources/js/types/warehouse.ts +++ b/resources/js/types/warehouse.ts @@ -174,7 +174,7 @@ export interface InboundItem { largeUnit?: string; conversionRate?: number; selectedUnit?: 'base' | 'large'; - batchMode?: 'existing' | 'new'; // 批號模式 + batchMode?: 'existing' | 'new' | 'none'; // 批號模式 inventoryId?: string; // 選擇現有批號時的 ID batchNumber?: string; originCountry?: string; // 新增產地