Files
jiu/docs/review/validation-bugs.md
T
wangjia 66e54af8c6 feat: 商品追踪页面 + 出库提交库存校验
后端:
- feat(backend): 重命名 Batches→Products 接口,新增库存状态(在售/已卖出)和买家信息
- feat(backend): 出库单创建/提交时校验仓库库存,不足则返回明确错误信息
- fix(backend): 出库创建 status 判断逻辑修复(空值默认 draft)

前端:
- feat(client): 批次追踪改为商品追踪,新增状态列(在售/已卖出)和买家/时间列
- fix(client): 无批次号时显示"无批次"而非空
- refactor(client): BatchRecord → ProductTrackingRecord,repository 接口更新

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 22:26:42 +08:00

3.7 KiB
Raw Blame History

参数校验 Bug 报告

BUG-001

严重程度:高

问题描述 POST /api/v1/partners 接口缺少对 name 字段的必填校验。传入空 name 时,handler 成功通过 ShouldBindJSON 绑定并返回 201,而不是期望的 400。

复现步骤

  1. 调用 POST /api/v1/partnersbody 为 {"type":"supplier"}(不含 name
  2. 期望返回 400,实际返回 201

失败的测试用例

func TestPartnerHandler_Create_MissingName(t *testing.T) {
    // 这个测试会失败,揭示了 partner handler 缺少 name 必填校验
    body := `{"type":"supplier"}`
    w := httptest.NewRecorder()
    req, _ := http.NewRequest("POST", "/api/v1/partners", strings.NewReader(body))
    req.Header.Set("Content-Type", "application/json")
    // 预期 400,实际得到 201
}

根因分析 backend/internal/model/partner.go 第 6 行:

Name string `gorm:"size:200;not null" json:"name"`

结构体 Name 字段只有 GORM 的 not null 约束,没有 binding:"required" 标签。 c.ShouldBindJSON 只校验 binding 标签,不校验 GORM 标签,导致空 name 可以通过校验。

SQLite in-memory 不严格强制 NOT NULL 约束(与 MySQL 行为不同),所以数据库层面也未报错。

修复建议Partner model 的 Name 字段添加 binding:"required" 标签:

Name string `gorm:"size:200;not null" json:"name" binding:"required"`

或者在 handler 中手动校验:

if req.Name == "" {
    c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"})
    return
}

BUG-002

严重程度:高

问题描述 POST /api/v1/stock-in/orders 接口缺少对 warehouse_id 字段的必填校验。传入 warehouse_id: 0(JSON 中省略该字段时默认为 0)时,handler 返回 201,而不是期望的 400。

复现步骤

  1. 调用 POST /api/v1/stock-in/ordersbody 为 {"items":[]}(不含 warehouse_id
  2. 期望返回 400,实际返回 201

失败的测试用例

func TestStockInHandler_Create_MissingWarehouse(t *testing.T) {
    body := `{"items":[]}`
    // 预期 400,实际得到 201
}

根因分析 backend/internal/model/stock.go 第 10 行:

WarehouseID uint64 `gorm:"not null" json:"warehouse_id"`

同 BUG-001,结构体只有 GORM 约束,缺少 binding:"required"。 对于 uint64 类型,JSON 省略时默认值为 0ShouldBindJSON 不会报错。

修复建议StockInOrder.WarehouseID 添加 binding:"required,min=1" 标签:

WarehouseID uint64 `gorm:"not null" json:"warehouse_id" binding:"required,min=1"`

或在 handler Create 函数中(backend/internal/handler/stock_in.go,约第 82 行)手动校验:

if req.WarehouseID == 0 {
    c.JSON(http.StatusBadRequest, gin.H{"error": "warehouse_id is required"})
    return
}

BUG-003

严重程度:高

问题描述 POST /api/v1/stock-out/orders 接口缺少对 warehouse_id 字段的必填校验,与 BUG-002 问题相同。

复现步骤

  1. 调用 POST /api/v1/stock-out/ordersbody 为 {"items":[]}(不含 warehouse_id
  2. 期望返回 400,实际返回 201

失败的测试用例

func TestStockOutHandler_Create_MissingWarehouse(t *testing.T) {
    body := `{"items":[]}`
    // 预期 400,实际得到 201
}

根因分析 同 BUG-002backend/internal/model/stock.goStockOutOrder.WarehouseID 缺少 binding 校验标签。

修复建议StockOutOrder.WarehouseID 添加 binding:"required,min=1" 标签,或在 backend/internal/handler/stock_out.goCreate 函数中手动校验。