feat(inventory): 完善庫存盤調更新與日誌邏輯,新增「無需盤調」狀態判定

1. 修正 AdjustDocController 缺失 update 方法導致的錯誤。
2. 修正 ActivityDetailDialog 前端 map 渲染 undefined 的 TypeError。
3. 優化盤調單「過帳」日誌,現在會同步包含當時的商品明細快照。
4. 實作盤點單「無需盤調」(no_adjust) 自動判定邏輯:
   - 當盤點數量與庫存完全一致時,自動標記為 no_adjust 結案。
   - 更新前端標籤樣式與操作按鈕對應邏輯。
   - 限制 no_adjust 單據不可重複建立盤調單。
5. 統一盤點單與盤調單的日誌配置,優化 ID 轉名稱顯示。
This commit is contained in:
2026-02-04 16:56:08 +08:00
parent 88415505fb
commit 2eb136d280
10 changed files with 281 additions and 72 deletions

View File

@@ -69,6 +69,12 @@ class AdjustDocController extends Controller
// 模式 1: 從盤點單建立
if ($request->filled('count_doc_id')) {
$countDoc = InventoryCountDoc::findOrFail($request->count_doc_id);
if ($countDoc->status !== 'completed') {
$errorMsg = $countDoc->status === 'no_adjust'
? '此盤點單無庫存差異,無需建立盤調單'
: '只有已完成盤點的單據可以建立盤調單';
return redirect()->back()->with('error', $errorMsg);
}
// 檢查是否已存在對應的盤調單 (避免重複建立)
if (InventoryAdjustDoc::where('count_doc_id', $countDoc->id)->exists()) {
@@ -76,21 +82,6 @@ class AdjustDocController extends Controller
}
$doc = $this->adjustService->createFromCountDoc($countDoc, auth()->id());
// 記錄活動
activity()
->performedOn($doc)
->causedBy(auth()->user())
->event('created')
->withProperties([
'attributes' => $doc->toArray(),
'snapshot' => [
'doc_no' => $doc->doc_no,
'warehouse_name' => $doc->warehouse?->name,
'count_doc_no' => $countDoc->doc_no,
]
])
->log('created_from_count');
return redirect()->route('inventory.adjust.show', [$doc->id])
->with('success', '已從盤點單生成盤調單');
@@ -143,6 +134,49 @@ class AdjustDocController extends Controller
return response()->json($counts);
}
public function update(Request $request, InventoryAdjustDoc $doc)
{
$action = $request->input('action', 'update');
if ($action === 'post') {
if ($doc->status !== 'draft') {
return redirect()->back()->with('error', '只有草稿狀態的單據可以過帳');
}
$this->adjustService->post($doc, auth()->id());
return redirect()->back()->with('success', '單據已過帳');
}
if ($action === 'void') {
if ($doc->status !== 'draft') {
return redirect()->back()->with('error', '只有草稿狀態的單據可以作廢');
}
$this->adjustService->void($doc, auth()->id());
return redirect()->back()->with('success', '單據已作廢');
}
// 一般更新 (更新品項與基本資訊)
if ($doc->status !== 'draft') {
return redirect()->back()->with('error', '只有草稿狀態的單據可以修改');
}
$request->validate([
'reason' => 'required|string',
'remarks' => 'nullable|string',
'items' => 'required|array|min:1',
'items.*.product_id' => 'required',
'items.*.adjust_qty' => 'required|numeric',
]);
$doc->update([
'reason' => $request->reason,
'remarks' => $request->remarks,
]);
$this->adjustService->updateItems($doc, $request->items);
return redirect()->back()->with('success', '單據已更新');
}
public function show(InventoryAdjustDoc $doc)
{
$doc->load(['items.product.baseUnit', 'createdBy', 'postedBy', 'warehouse', 'countDoc']);
@@ -185,18 +219,7 @@ class AdjustDocController extends Controller
return redirect()->back()->with('error', '只能刪除草稿狀態的單據');
}
// 記錄活動
activity()
->performedOn($doc)
->causedBy(auth()->user())
->event('deleted')
->withProperties([
'snapshot' => [
'doc_no' => $doc->doc_no,
'warehouse_name' => $doc->warehouse?->name,
]
])
->log('deleted');
$doc->items()->delete();
$doc->delete();