adjustService = $adjustService; } public function index(Request $request) { $query = InventoryAdjustDoc::query() ->with(['createdBy', 'postedBy', 'warehouse']); // 搜尋 if ($request->filled('search')) { $search = $request->search; $query->where(function($q) use ($search) { $q->where('doc_no', 'like', "%{$search}%") ->orWhere('reason', 'like', "%{$search}%") ->orWhere('remarks', 'like', "%{$search}%"); }); } if ($request->filled('warehouse_id')) { $query->where('warehouse_id', $request->warehouse_id); } $perPage = $request->input('per_page', 15); $docs = $query->orderByDesc('created_at') ->paginate($perPage) ->withQueryString() ->through(function ($doc) { return [ 'id' => (string) $doc->id, 'doc_no' => $doc->doc_no, 'status' => $doc->status, 'warehouse_name' => $doc->warehouse->name, 'reason' => $doc->reason, 'created_at' => $doc->created_at->format('Y-m-d H:i'), 'posted_at' => $doc->posted_at ? $doc->posted_at->format('Y-m-d H:i') : '-', 'created_by' => $doc->createdBy?->name, 'remarks' => $doc->remarks, ]; }); return Inertia::render('Inventory/Adjust/Index', [ 'docs' => $docs, 'warehouses' => Warehouse::all()->map(fn($w) => ['id' => (string)$w->id, 'name' => $w->name]), 'filters' => $request->only(['warehouse_id', 'search', 'per_page']), ]); } public function store(Request $request) { // 模式 1: 從盤點單建立 if ($request->filled('count_doc_id')) { $countDoc = InventoryCountDoc::findOrFail($request->count_doc_id); // 檢查是否已存在對應的盤調單 (避免重複建立) if (InventoryAdjustDoc::where('count_doc_id', $countDoc->id)->exists()) { return redirect()->back()->with('error', '此盤點單已建立過盤調單'); } $doc = $this->adjustService->createFromCountDoc($countDoc, auth()->id()); return redirect()->route('inventory.adjust.show', [$doc->id]) ->with('success', '已從盤點單生成盤調單'); } // 模式 2: 一般手動調整 (保留原始邏輯但更新訊息) $validated = $request->validate([ 'warehouse_id' => 'required', 'reason' => 'required|string', 'remarks' => 'nullable|string', ]); $doc = $this->adjustService->createDoc( $validated['warehouse_id'], $validated['reason'], $validated['remarks'], auth()->id() ); return redirect()->route('inventory.adjust.show', [$doc->id]) ->with('success', '已建立盤調單'); } /** * API: 獲取可盤調的已完成盤點單 (支援掃描單號) */ public function getPendingCounts(Request $request) { $query = InventoryCountDoc::where('status', 'completed') ->whereNotExists(function ($query) { $query->select(DB::raw(1)) ->from('inventory_adjust_docs') ->whereColumn('inventory_adjust_docs.count_doc_id', 'inventory_count_docs.id'); }); if ($request->filled('search')) { $search = $request->search; $query->where('doc_no', 'like', "%{$search}%"); } $counts = $query->limit(10)->get()->map(function($c) { return [ 'id' => (string)$c->id, 'doc_no' => $c->doc_no, 'warehouse_name' => $c->warehouse->name, 'completed_at' => $c->completed_at->format('Y-m-d H:i'), ]; }); return response()->json($counts); } public function show(InventoryAdjustDoc $doc) { $doc->load(['items.product.baseUnit', 'createdBy', 'postedBy', 'warehouse', 'countDoc']); $docData = [ 'id' => (string) $doc->id, 'doc_no' => $doc->doc_no, 'warehouse_id' => (string) $doc->warehouse_id, 'warehouse_name' => $doc->warehouse->name, 'status' => $doc->status, 'reason' => $doc->reason, 'remarks' => $doc->remarks, 'created_at' => $doc->created_at->format('Y-m-d H:i'), 'created_by' => $doc->createdBy?->name, 'count_doc_id' => $doc->count_doc_id ? (string)$doc->count_doc_id : null, 'count_doc_no' => $doc->countDoc?->doc_no, 'items' => $doc->items->map(function ($item) { return [ 'id' => (string) $item->id, 'product_id' => (string) $item->product_id, 'product_name' => $item->product->name, 'product_code' => $item->product->code, 'batch_number' => $item->batch_number, 'unit' => $item->product->baseUnit?->name, 'qty_before' => (float) $item->qty_before, 'adjust_qty' => (float) $item->adjust_qty, 'notes' => $item->notes, ]; }), ]; return Inertia::render('Inventory/Adjust/Show', [ 'doc' => $docData, ]); } public function update(Request $request, InventoryAdjustDoc $doc) { if ($doc->status !== 'draft') { return redirect()->back()->with('error', '只能修改草稿狀態的單據'); } // 提交 (items 更新 或 過帳) if ($request->input('action') === 'post') { $this->adjustService->post($doc, auth()->id()); return redirect()->route('inventory.adjust.index') ->with('success', '盤調單已過帳生效'); } // 僅儲存資料 $validated = $request->validate([ 'items' => 'array', 'items.*.product_id' => 'required|exists:products,id', 'items.*.adjust_qty' => 'required|numeric', // 可以是負數 'items.*.batch_number' => 'nullable|string', 'items.*.notes' => 'nullable|string', ]); if ($request->has('items')) { $this->adjustService->updateItems($doc, $validated['items']); } // 更新表頭 $doc->update($request->only(['reason', 'remarks'])); return redirect()->back()->with('success', '儲存成功'); } public function destroy(InventoryAdjustDoc $doc) { if ($doc->status !== 'draft') { return redirect()->back()->with('error', '只能刪除草稿狀態的單據'); } $doc->items()->delete(); $doc->delete(); return redirect()->route('inventory.adjust.index') ->with('success', '盤調單已刪除'); } }