Skip to content

庫存記錄系統修復指南

問題背景與 FIFO 修復記錄

更新日期: 2025-07-30
最新修復: FIFO 排序問題和 received_at 資料品質問題
狀態: ✅ 完全修復

原始問題分析

經過詳細檢查,發現庫存模組存在以下關鍵問題:

🚨 嚴重問題

  1. 入庫流程缺少 inventory_logs 記錄

    • addInventory() 函數只在 inventories 表新增記錄
    • 完全沒有建立對應的 inventory_logs 'in' 記錄
    • 導致 current_stock 計算錯誤,庫存追蹤不完整
  2. 資料不一致性

    • inventory_with_stock_detail 視圖依賴 inventory_logs 計算 current_stock
    • 缺少 'in' 記錄會導致所有入庫操作無法正確反映在庫存計算中
  3. 業務流程不完整

    • 只支援「入庫」和「出庫」,缺少「調整庫存」機制
    • 無法處理盤點差異、報廢、退貨等常見業務情境

邏輯缺陷

  1. 觸發器缺失

    • 只有 set_updated_at_inventories 觸發器更新時間戳
    • 沒有自動建立 inventory_logs 記錄的觸發器
  2. 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/

typescript
// 支援的請求格式
{
  "product_id": "uuid",
  "quantity": number,
  "source": "string", // 可選
  "note": "string",   // 可選
  "sku": "string",    // 可選
  "received_at": "ISO_string" // 可選
}

調整 Edge Function: supabase/functions/stock-adjust/

typescript
// 支援的請求格式
{
  "inventory_id": "uuid",
  "adjust_quantity": number, // 正數增加,負數減少
  "reason": "string",
  "source": "string" // 可選
}

3. 前端函數修復

檔案: admin-platform-vue/src/composables/useProduct.ts

  • 修復 addInventory(): 改為呼叫 stock-in Edge Function
  • 新增 adjustInventory(): 呼叫 stock-adjust Edge Function

Phase 2: 使用指南

資料完整性檢查

sql
-- 檢查是否有需要修復的資料
SELECT * FROM check_inventory_integrity();

歷史資料修復

sql
-- 修復缺失的 inventory_logs 記錄
SELECT repair_missing_inventory_logs();

庫存操作範例

前端入庫操作:

typescript
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()
})

前端庫存調整:

typescript
import { adjustInventory } from '@/composables/useProduct'

// 增加庫存(盤點發現多出來的)
const addResult = await adjustInventory(
  'inventory-id',
  5,
  '盤點發現額外庫存',
  'inventory_audit'
)

// 減少庫存(報廢)
const reduceResult = await adjustInventory(
  'inventory-id',
  -3,
  '產品損壞報廢',
  'damage_writeoff'
)

修復驗證

驗證步驟

  1. 觸發器驗證
sql
-- 新增一筆 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';
  1. Edge Function 驗證
bash
# 使用 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":"測試入庫"}'
  1. 前端功能驗證
  • 在產品管理頁面測試入庫功能
  • 檢查庫存列表是否正確顯示
  • 驗證 current_stock 計算是否正確

預期結果

修復完成後應達到:

  • ✅ 每次新增 inventories 都會自動建立對應的 inventory_logs 'in' 記錄
  • current_stock 計算完全正確
  • ✅ 支援庫存調整功能(增加/減少)
  • ✅ 歷史資料完整性修復
  • ✅ 完整的 API 覆蓋(入庫、出庫、調整)

業務價值

解決的問題

  1. 資料準確性: 修復庫存計算錯誤
  2. 操作完整性: 提供完整的庫存管理功能
  3. 系統可靠性: 自動化記錄,減少人為錯誤
  4. 業務流程: 支援更多實際業務情境

支援的使用情境

  • 採購入庫: 使用 stock-in Edge Function
  • 手動入庫: 前端 addInventory() 函數
  • 訂單出庫: 原有 allocate_stock_fifo() 函數(已正確)
  • 手動出庫: 原有 allocate-inventory Edge Function(已正確)
  • 盤點調整: 新增 adjustInventory() 函數
  • 報廢處理: 使用調整功能減少庫存
  • 退貨入庫: 使用入庫功能處理退貨

🔍 監控與維護

定期檢查

建議每週執行完整性檢查:

sql
SELECT * FROM check_inventory_integrity();

效能監控

關注以下指標:

  • inventory_logs 表的成長速度
  • 庫存計算查詢的效能
  • Edge Function 的回應時間

資料備份

確保定期備份:

  • inventories
  • inventory_logs
  • 相關視圖和函數

相關文件

未來擴展

計劃功能

  • 批量入庫 Edge Function
  • 庫存預警自動化
  • 庫存報表生成
  • 庫存歷史追蹤優化

技術改進

  • 庫存操作的事務性保證
  • 更細緻的權限控制
  • 庫存操作的審計日誌

FIFO 修復記錄 (2025-07-30)

問題發現

部署初始修復後,用戶回報 FIFO 庫存扣除不正確:

  • 現象: 系統優先扣除較新的庫存,而非較舊的庫存
  • 根本原因: 舊的庫存記錄 received_at 欄位為 NULL
  • 影響: 違反 FIFO (先進先出) 業務邏輯

深度分析

  1. 資料品質問題:

    • 歷史庫存記錄的 received_at 為 NULL
    • ORDER BY received_at ASC 無法正確處理 NULL 值
    • NULL 值的排序行為不確定,影響 FIFO 邏輯
  2. 函數邏輯缺陷:

    • 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
  • 增強錯誤處理: 添加詳細的錯誤訊息和調試日誌
  • 函數註釋: 添加完整的函數說明和使用指引

關鍵修復點:

sql
-- 修復前(問題版本)
ORDER BY i.received_at ASC

-- 修復後(正確版本)
ORDER BY i.received_at ASC NULLS LAST, i.created_at ASC

2. 資料品質修復

檔案: supabase/migrations/20250730232000_fix_received_at_data_quality.sql

修復策略: 採用業界最佳實踐 - received_at NOT NULL

修復內容:

  • 歷史資料修復: 將所有 NULL 的 received_at 設為對應的 created_at
  • 欄位約束: 設定 received_at NOT NULL 約束
  • 預設值: 添加 NOW() 預設值避免未來 NULL 問題
  • 完整性驗證: 多重檢查確保修復完整性

修復統計:

sql
-- 修復前檢查
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 值
  • 代碼可讀性: 提升前端庫存操作邏輯的清晰度

修復驗證

自動化測試腳本

  1. 快速驗證: supabase/docs/scripts/fifo-quick-test.sql

    • 全自動化檢查,無需手動設定
    • 驗證資料品質、約束設定、函數修復狀態
  2. 深度測試: supabase/docs/scripts/fifo-verification-test.sql

    • 針對特定產品的詳細 FIFO 邏輯測試
    • 模擬庫存分配情境

驗證結果

  • 資料品質: 所有庫存記錄都有正確的 received_at
  • 約束設定: received_at NOT NULL 約束已生效
  • FIFO 排序: 函數正確包含 NULLS LAST 修復
  • 業務邏輯: 庫存分配按收貨時間先進先出執行

經驗與教訓

成功要素

  1. 問題定位精準: 快速定位到 NULL 值和排序問題
  2. 業界最佳實踐: 採用 NOT NULL 約束提升資料品質
  3. 完整的測試工具: 創建自動化驗證腳本
  4. 向後相容: 歷史資料平滑遷移,不影響現有功能

技術決策原理

  1. 為什麼選擇 received_at NOT NULL:

    • 符合業界標準實踐
    • 確保 FIFO 排序邏輯可靠
    • 避免未來類似問題
    • 提升查詢效能
  2. 為什麼使用 created_at 作為 NULL 值的替代:

    • 歷史記錄的最佳估計值
    • 保持時間順序的合理性
    • 不影響現有業務邏輯

預防措施

  1. 資料品質檢查: 定期檢查關鍵欄位的 NULL 值
  2. 約束設計: 重要業務欄位應設定 NOT NULL 約束
  3. 排序處理: 涉及排序的查詢都應考慮 NULL 值處理
  4. 測試覆蓋: 為核心業務邏輯建立完整的測試腳本

檔案組織與文檔

  • 技術腳本: 移動到 supabase/docs/scripts/
  • 部署指南: 移動到 supabase/docs/guides/
  • 系統文檔: 新增 docs/02-development/database/inventory-system.md
  • 交叉引用: 建立清楚的文檔間連結關係

修復完成日期: 2025-07-30
修復影響範圍: 庫存管理模組完整功能 + FIFO 排序邏輯
測試狀態: ✅ 完整驗證通過
風險評估: 低風險,向後相容,業界最佳實踐