$warehouseId, 'status' => 'draft', 'remarks' => $remarks, 'created_by' => $userId, ]); return $doc; }); } /** * 執行快照:鎖定當前庫存量 */ public function snapshot(InventoryCountDoc $doc): void { DB::transaction(function () use ($doc) { // 清除舊的 items (如果有) $doc->items()->delete(); // 取得該倉庫所有庫存 (包含 quantity = 0 但未軟刪除的) // 這裡可以根據需求決定是否要過濾掉 0 庫存,通常盤點單會希望能看到所有 "帳上有紀錄" 的東西 $inventories = Inventory::where('warehouse_id', $doc->warehouse_id) ->whereNull('deleted_at') ->get(); $items = []; foreach ($inventories as $inv) { $items[] = [ 'count_doc_id' => $doc->id, 'product_id' => $inv->product_id, 'batch_number' => $inv->batch_number, 'system_qty' => $inv->quantity, 'counted_qty' => null, // 預設未盤點 'diff_qty' => 0, 'created_at' => now(), 'updated_at' => now(), ]; } if (!empty($items)) { InventoryCountItem::insert($items); } $doc->update([ 'status' => 'counting', 'snapshot_date' => now(), ]); }); } /** * 完成盤點:過帳差異 */ public function complete(InventoryCountDoc $doc, int $userId): void { DB::transaction(function () use ($doc, $userId) { foreach ($doc->items as $item) { // 如果沒有輸入實盤數量,預設跳過或是視為 0? // 安全起見:如果 counted_qty 是 null,表示沒盤到,跳過不處理 (或者依業務邏輯視為0) // 這裡假設前端會確保有送出資料,若 null 則不做異動 if (is_null($item->counted_qty)) { continue; } $diff = $item->counted_qty - $item->system_qty; // 如果無差異,更新 item 狀態即可 (diff_qty 已經是 computed field 或在儲存時計算) // 這裡 update 一下 diff_qty 以防萬一 $item->update(['diff_qty' => $diff]); if (abs($diff) > 0.0001) { // 找回原本的 Inventory $inventory = Inventory::where('warehouse_id', $doc->warehouse_id) ->where('product_id', $item->product_id) ->where('batch_number', $item->batch_number) ->first(); if (!$inventory) { // 如果原本沒庫存紀錄 (例如是新增的盤點項目),需要新建 Inventory // 但目前 snapshot 邏輯只抓現有。若允許 "盤盈" (發現不在帳上的),需要額外邏輯 // 暫時略過 "新增 Inventory" 的複雜邏輯,假設只能針對 existing batch 調整 continue; } $oldQty = $inventory->quantity; $newQty = $oldQty + $diff; $inventory->quantity = $newQty; $inventory->total_value = $inventory->unit_cost * $newQty; $inventory->save(); // 寫入 Transaction $inventory->transactions()->create([ 'type' => '盤點調整', 'quantity' => $diff, 'unit_cost' => $inventory->unit_cost, 'balance_before' => $oldQty, 'balance_after' => $newQty, 'reason' => "盤點單 {$doc->doc_no} 過帳", 'actual_time' => now(), 'user_id' => $userId, ]); } } $doc->update([ 'status' => 'completed', 'completed_at' => now(), 'completed_by' => $userId, ]); }); } /** * 更新盤點數量 */ public function updateCount(InventoryCountDoc $doc, array $itemsData): void { DB::transaction(function () use ($doc, $itemsData) { foreach ($itemsData as $data) { $item = $doc->items()->find($data['id']); if ($item) { $countedQty = $data['counted_qty']; $diff = is_numeric($countedQty) ? ($countedQty - $item->system_qty) : 0; $item->update([ 'counted_qty' => $countedQty, 'diff_qty' => $diff, 'notes' => $data['notes'] ?? $item->notes, ]); } } }); } }