transferOrder = $transferOrder; } public function collection(Collection $rows) { if ($rows->isEmpty()) { throw new Exception("檔案中沒有資料。"); } // 移除標題列並解析索引 $headerRow = $rows->shift(); $headers = $headerRow->toArray(); // 建立標題對應索引 (支援中文與英文) $colMap = [ 'product_code' => -1, 'batch_number' => -1, 'quantity' => -1, 'position' => -1, 'notes' => -1, ]; foreach ($headers as $index => $label) { $label = trim((string)$label); if (in_array($label, ['商品代碼', 'product_code', 'shang_pin_dai_ma'])) $colMap['product_code'] = $index; if (in_array($label, ['批號', 'batch_number', 'pi_hao'])) $colMap['batch_number'] = $index; if (in_array($label, ['數量', 'quantity', 'shu_liang'])) $colMap['quantity'] = $index; if (in_array($label, ['貨道/儲位', '貨道', 'position', 'slot', 'huo_dao'])) $colMap['position'] = $index; if (in_array($label, ['備註', 'notes', 'bei_zhu'])) $colMap['notes'] = $index; } // 檢查必要欄位是否有找到 if ($colMap['product_code'] === -1 || $colMap['quantity'] === -1) { $foundHeaders = implode(', ', array_filter($headers)); throw new Exception("找不到必要的欄位「商品代碼」或「數量」。讀取到的標題為:{$foundHeaders}。請確認使用的是正確的範本。"); } // 預先載入商品 (優化效能) $productCodes = $rows->map(fn($row) => trim((string)($row[$colMap['product_code']] ?? '')))->filter()->unique()->toArray(); $products = Product::whereIn('code', $productCodes)->get()->keyBy('code'); $newItems = []; $errors = []; foreach ($rows as $index => $row) { $productCode = trim((string)($row[$colMap['product_code']] ?? '')); $quantity = $row[$colMap['quantity']] ?? null; $batchNumber = $colMap['batch_number'] !== -1 ? trim((string)($row[$colMap['batch_number']] ?? '')) : ''; $position = $colMap['position'] !== -1 ? trim((string)($row[$colMap['position']] ?? '')) : null; $notes = $colMap['notes'] !== -1 ? ($row[$colMap['notes']] ?? null) : null; // 跳過全空行 if (empty($productCode) && ($quantity === null || $quantity === '')) { continue; } $lineNum = $index + 2; // 因為 shift 過,且 Excel 從 1 開始 if (empty($productCode)) { $errors[] = "第 {$lineNum} 行:商品代碼不能為空"; continue; } $product = $products->get($productCode); if (!$product) { $errors[] = "第 {$lineNum} 行:找不到商品代碼 '{$productCode}'"; continue; } if (!is_numeric($quantity) || (float)$quantity <= 0) { $errors[] = "第 {$lineNum} 行:數量必須為大於 0 的數字 (目前值: " . ($quantity ?? '空') . ")"; continue; } if (empty($batchNumber)) { $batchNumber = 'NO-BATCH'; } $newItems[] = [ 'transfer_order_id' => $this->transferOrder->id, 'product_id' => $product->id, 'batch_number' => $batchNumber, 'quantity' => (float)$quantity, 'position' => $position, 'notes' => $notes, 'created_at' => now(), 'updated_at' => now(), ]; } if (count($errors) > 0) { throw new Exception(implode("\n", $errors)); } if (count($newItems) === 0) { throw new Exception("檔案中沒有可匯入的有效資料。"); } InventoryTransferItem::insert($newItems); $this->transferOrder->touch(); } /** * 指定只匯入第一個分頁 (明細匯入) */ public function sheets(): array { return [ 0 => $this, ]; } }