庫存記錄系統修復指南
問題背景與 FIFO 修復記錄
更新日期: 2025-07-30
最新修復: FIFO 排序問題和 received_at 資料品質問題
狀態: ✅ 完全修復
原始問題分析
經過詳細檢查,發現庫存模組存在以下關鍵問題:
🚨 嚴重問題
入庫流程缺少 inventory_logs 記錄
addInventory()函數只在inventories表新增記錄- 完全沒有建立對應的
inventory_logs'in' 記錄 - 導致
current_stock計算錯誤,庫存追蹤不完整
資料不一致性
inventory_with_stock_detail視圖依賴inventory_logs計算current_stock- 缺少 'in' 記錄會導致所有入庫操作無法正確反映在庫存計算中
業務流程不完整
- 只支援「入庫」和「出庫」,缺少「調整庫存」機制
- 無法處理盤點差異、報廢、退貨等常見業務情境
邏輯缺陷
觸發器缺失
- 只有
set_updated_at_inventories觸發器更新時間戳 - 沒有自動建立
inventory_logs記錄的觸發器
- 只有
Edge Function 不完整
- 只有
allocate-inventory處理出庫(正確) - 缺少對應的入庫 Edge Function
- 只有
解決方案實施
Phase 1: 核心修復(已完成)
1. 資料庫層面修復
檔案: supabase/migrations/20250730170000_fix_inventory_logging_system.sql
- ✅ 入庫觸發器: 新增
log_inventory_creation()函數和觸發器 - ✅ 類型擴展: 擴展
inventory_logs.type支援'adjust'類型 - ✅ 調整函數: 新增
adjust_inventory_stock()函數 - ✅ 完整性檢查: 新增
check_inventory_integrity()函數 - ✅ 資料修復: 新增
repair_missing_inventory_logs()函數
2. Edge Functions 建立
入庫 Edge Function: supabase/functions/stock-in/
// 支援的請求格式
{
"product_id": "uuid",
"quantity": number,
"source": "string", // 可選
"note": "string", // 可選
"sku": "string", // 可選
"received_at": "ISO_string" // 可選
}調整 Edge Function: supabase/functions/stock-adjust/
// 支援的請求格式
{
"inventory_id": "uuid",
"adjust_quantity": number, // 正數增加,負數減少
"reason": "string",
"source": "string" // 可選
}3. 前端函數修復
檔案: admin-platform-vue/src/composables/useProduct.ts
- ✅ 修復
addInventory(): 改為呼叫stock-inEdge Function - ✅ 新增
adjustInventory(): 呼叫stock-adjustEdge Function
Phase 2: 使用指南
資料完整性檢查
-- 檢查是否有需要修復的資料
SELECT * FROM check_inventory_integrity();歷史資料修復
-- 修復缺失的 inventory_logs 記錄
SELECT repair_missing_inventory_logs();庫存操作範例
前端入庫操作:
import { addInventory } from '@/composables/useProduct'
const result = await addInventory('product-id', {
quantity: 100,
source: 'purchase_order',
note: '採購單號 PO-2025-001',
sku: 'ITEM-001',
received_at: new Date()
})前端庫存調整:
import { adjustInventory } from '@/composables/useProduct'
// 增加庫存(盤點發現多出來的)
const addResult = await adjustInventory(
'inventory-id',
5,
'盤點發現額外庫存',
'inventory_audit'
)
// 減少庫存(報廢)
const reduceResult = await adjustInventory(
'inventory-id',
-3,
'產品損壞報廢',
'damage_writeoff'
)修復驗證
驗證步驟
- 觸發器驗證
-- 新增一筆 inventory 記錄,檢查是否自動建立 inventory_logs
INSERT INTO inventories (product_id, quantity, received_at)
VALUES ('test-product-id', 10, NOW());
-- 檢查是否有對應的 'in' 記錄
SELECT * FROM inventory_logs
WHERE inventory_id = (SELECT id FROM inventories ORDER BY created_at DESC LIMIT 1)
AND type = 'in';- Edge Function 驗證
# 使用 Supabase CLI 測試 stock-in function
supabase functions serve stock-in
# 測試請求
curl -X POST http://localhost:54321/functions/v1/stock-in \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"product_id":"test-id","quantity":5,"note":"測試入庫"}'- 前端功能驗證
- 在產品管理頁面測試入庫功能
- 檢查庫存列表是否正確顯示
- 驗證
current_stock計算是否正確
預期結果
修復完成後應達到:
- ✅ 每次新增
inventories都會自動建立對應的inventory_logs'in' 記錄 - ✅
current_stock計算完全正確 - ✅ 支援庫存調整功能(增加/減少)
- ✅ 歷史資料完整性修復
- ✅ 完整的 API 覆蓋(入庫、出庫、調整)
業務價值
解決的問題
- 資料準確性: 修復庫存計算錯誤
- 操作完整性: 提供完整的庫存管理功能
- 系統可靠性: 自動化記錄,減少人為錯誤
- 業務流程: 支援更多實際業務情境
支援的使用情境
- ✅ 採購入庫: 使用
stock-inEdge Function - ✅ 手動入庫: 前端
addInventory()函數 - ✅ 訂單出庫: 原有
allocate_stock_fifo()函數(已正確) - ✅ 手動出庫: 原有
allocate-inventoryEdge Function(已正確) - ✅ 盤點調整: 新增
adjustInventory()函數 - ✅ 報廢處理: 使用調整功能減少庫存
- ✅ 退貨入庫: 使用入庫功能處理退貨
🔍 監控與維護
定期檢查
建議每週執行完整性檢查:
SELECT * FROM check_inventory_integrity();效能監控
關注以下指標:
inventory_logs表的成長速度- 庫存計算查詢的效能
- Edge Function 的回應時間
資料備份
確保定期備份:
inventories表inventory_logs表- 相關視圖和函數
相關文件
未來擴展
計劃功能
- 批量入庫 Edge Function
- 庫存預警自動化
- 庫存報表生成
- 庫存歷史追蹤優化
技術改進
- 庫存操作的事務性保證
- 更細緻的權限控制
- 庫存操作的審計日誌
FIFO 修復記錄 (2025-07-30)
問題發現
部署初始修復後,用戶回報 FIFO 庫存扣除不正確:
- 現象: 系統優先扣除較新的庫存,而非較舊的庫存
- 根本原因: 舊的庫存記錄
received_at欄位為 NULL - 影響: 違反 FIFO (先進先出) 業務邏輯
深度分析
資料品質問題:
- 歷史庫存記錄的
received_at為 NULL ORDER BY received_at ASC無法正確處理 NULL 值- NULL 值的排序行為不確定,影響 FIFO 邏輯
- 歷史庫存記錄的
函數邏輯缺陷:
allocate_stock_fifo函數缺少NULLS LAST子句- 存在重複的函數定義(舊版本和新版本)
Phase 2: FIFO 排序修復
1. 函數清理與修復
檔案: supabase/migrations/20250730231000_cleanup_and_fix_fifo.sql
修復內容:
- ✅ 清除重複函數: 移除所有現有的
allocate_stock_fifo版本 - ✅ 修復排序邏輯:
ORDER BY received_at ASC NULLS LAST, created_at ASC - ✅ 增強錯誤處理: 添加詳細的錯誤訊息和調試日誌
- ✅ 函數註釋: 添加完整的函數說明和使用指引
關鍵修復點:
-- 修復前(問題版本)
ORDER BY i.received_at ASC
-- 修復後(正確版本)
ORDER BY i.received_at ASC NULLS LAST, i.created_at ASC2. 資料品質修復
檔案: supabase/migrations/20250730232000_fix_received_at_data_quality.sql
修復策略: 採用業界最佳實踐 - received_at NOT NULL
修復內容:
- ✅ 歷史資料修復: 將所有 NULL 的
received_at設為對應的created_at - ✅ 欄位約束: 設定
received_at NOT NULL約束 - ✅ 預設值: 添加
NOW()預設值避免未來 NULL 問題 - ✅ 完整性驗證: 多重檢查確保修復完整性
修復統計:
-- 修復前檢查
SELECT COUNT(*) FROM inventories WHERE received_at IS NULL;
-- 結果: X 筆記錄需要修復
-- 修復執行
UPDATE inventories SET received_at = created_at WHERE received_at IS NULL;
-- 修復後驗證
SELECT COUNT(*) FROM inventories WHERE received_at IS NULL;
-- 結果: 0 筆記錄3. 應用層優化
檔案: admin-platform-vue/src/composables/useProduct.ts
優化內容:
- ✅ 確保 received_at: 明確處理
received_at欄位,避免 NULL 值 - ✅ 代碼可讀性: 提升前端庫存操作邏輯的清晰度
修復驗證
自動化測試腳本
快速驗證:
supabase/docs/scripts/fifo-quick-test.sql- 全自動化檢查,無需手動設定
- 驗證資料品質、約束設定、函數修復狀態
深度測試:
supabase/docs/scripts/fifo-verification-test.sql- 針對特定產品的詳細 FIFO 邏輯測試
- 模擬庫存分配情境
驗證結果
- ✅ 資料品質: 所有庫存記錄都有正確的
received_at值 - ✅ 約束設定:
received_at NOT NULL約束已生效 - ✅ FIFO 排序: 函數正確包含
NULLS LAST修復 - ✅ 業務邏輯: 庫存分配按收貨時間先進先出執行
經驗與教訓
成功要素
- 問題定位精準: 快速定位到 NULL 值和排序問題
- 業界最佳實踐: 採用
NOT NULL約束提升資料品質 - 完整的測試工具: 創建自動化驗證腳本
- 向後相容: 歷史資料平滑遷移,不影響現有功能
技術決策原理
為什麼選擇
received_at NOT NULL:- 符合業界標準實踐
- 確保 FIFO 排序邏輯可靠
- 避免未來類似問題
- 提升查詢效能
為什麼使用
created_at作為 NULL 值的替代:- 歷史記錄的最佳估計值
- 保持時間順序的合理性
- 不影響現有業務邏輯
預防措施
- 資料品質檢查: 定期檢查關鍵欄位的 NULL 值
- 約束設計: 重要業務欄位應設定 NOT NULL 約束
- 排序處理: 涉及排序的查詢都應考慮 NULL 值處理
- 測試覆蓋: 為核心業務邏輯建立完整的測試腳本
檔案組織與文檔
- 技術腳本: 移動到
supabase/docs/scripts/ - 部署指南: 移動到
supabase/docs/guides/ - 系統文檔: 新增
docs/02-development/database/inventory-system.md - 交叉引用: 建立清楚的文檔間連結關係
修復完成日期: 2025-07-30
修復影響範圍: 庫存管理模組完整功能 + FIFO 排序邏輯
測試狀態: ✅ 完整驗證通過
風險評估: 低風險,向後相容,業界最佳實踐