feat(Inventory): 實作批號溯源完整功能與 UI 呈現,包含文字敘述卡片與更完整的關聯屬性

This commit is contained in:
2026-02-26 10:39:24 +08:00
parent 63e4f88a14
commit f960aaaeb2
16 changed files with 1085 additions and 694 deletions

View File

@@ -122,8 +122,13 @@ class StoreRequisitionService
$processedItems = []; // 暫存處理後的明細,用於轉入調撥單
if (isset($data['items'])) {
$requisition->load('items.product');
$reqItemMap = $requisition->items->keyBy('id');
foreach ($data['items'] as $itemData) {
$reqItemId = $itemData['id'];
$reqItem = $reqItemMap->get($reqItemId);
$productName = $reqItem?->product?->name ?? '未知商品';
$totalApprovedQty = 0;
$batches = $itemData['batches'] ?? [];
@@ -133,7 +138,22 @@ class StoreRequisitionService
foreach ($batches as $batch) {
$qty = (float)($batch['qty'] ?? 0);
$bNum = $batch['batch_number'] ?? null;
$invId = $batch['inventory_id'] ?? null;
if ($qty > 0) {
if ($invId) {
$inventory = \App\Modules\Inventory\Models\Inventory::lockForUpdate()->find($invId);
if ($inventory) {
$available = max(0, $inventory->quantity - $inventory->reserved_quantity);
if ($qty > $available) {
$batchStr = $bNum ? "批號 {$bNum}" : "無批號";
throw ValidationException::withMessages([
'items' => "{$productName}」的 {$batchStr} 數量({$qty})不可大於可用庫存({$available})",
]);
}
}
}
$totalApprovedQty += $qty;
$batchKey = $bNum ?? '';
$batchGroups[$batchKey] = ($batchGroups[$batchKey] ?? 0) + $qty;
@@ -151,6 +171,18 @@ class StoreRequisitionService
// 無批號,傳統輸入
$qty = (float)($itemData['approved_qty'] ?? 0);
if ($qty > 0) {
$supplyWarehouseId = $requisition->supply_warehouse_id;
$totalAvailable = \App\Modules\Inventory\Models\Inventory::where('warehouse_id', $supplyWarehouseId)
->where('product_id', $reqItem->product_id)
->selectRaw('SUM(quantity - reserved_quantity) as available')
->value('available') ?? 0;
if ($qty > $totalAvailable) {
throw ValidationException::withMessages([
'items' => "{$productName}」的數量({$qty})不可大於供貨倉可用總庫存({$totalAvailable})",
]);
}
$totalApprovedQty += $qty;
$processedItems[] = [
'req_item_id' => $reqItemId,