Files
jiu/docs/review/stock-order-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

73 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 入库/出库单 Bug 报告
## BUG-001
**严重程度**:中
**问题描述**
创建入库单(`POST /api/v1/stock-in/orders`)和出库单(`POST /api/v1/stock-out/orders`)时,缺少对 `warehouse_id``binding:"required"` 验证。当客户端不传 `warehouse_id` 或传入 `0`,后端会静默接受并创建一条 `warehouse_id=0` 的无效单据,而不是返回 400 Bad Request。
**复现步骤**
1. 调用 `POST /api/v1/stock-in/orders`,请求体中省略 `warehouse_id` 字段
2. 期望返回 400,实际返回 201,并创建了一条 `warehouse_id=0` 的单据
等效对出库单同样适用。
**失败的测试用例**
```go
func TestStockInHandler_Create_MissingWarehouse(t *testing.T) {
// 缺少 warehouse_id,应该返回 400
w := makeRequest(r, "POST", "/api/v1/stock-in/orders", token, map[string]interface{}{
"order_date": time.Now().Format(time.RFC3339),
"items": []map[string]interface{}{},
})
assert.Equal(t, http.StatusBadRequest, w.Code) // 实际返回 201
}
```
**根因分析**
- `backend/internal/model/stock.go``StockInOrder``StockOutOrder` 结构体中,`WarehouseID` 字段缺少 `binding:"required"` 标签
- 当前定义:`WarehouseID uint64 \`gorm:"not null" json:"warehouse_id"\``
- 缺少:`binding:"required"`
**修复建议**
`StockInOrder``StockOutOrder``WarehouseID` 字段上添加 `binding:"required"` 标签:
```go
WarehouseID uint64 `gorm:"not null" json:"warehouse_id" binding:"required"`
```
注意:Go 的 `binding:"required"``uint64` 类型的判断是零值(即 0)视为未填写,因此可正确拦截缺失或为 0 的情况。
---
## BUG-002
**严重程度**:低
**问题描述**
`WarehouseHandler.Delete` 在资源不存在时返回 200 而不是 404。当用户删除一个不存在的仓库 ID 时,业务逻辑没有检查 `RowsAffected`,始终返回 200 OK。
**复现步骤**
1. 调用 `DELETE /api/v1/warehouses/99999`(不存在的 ID
2. 期望返回 404,实际返回 200
**根因分析**
`backend/internal/handler/warehouse.go``Delete` 方法未检查 `result.RowsAffected`,与 `ProductHandler.Delete` 的实现不一致。
**修复建议**
参考 `ProductHandler.Delete` 的实现,添加 `RowsAffected == 0` 检查:
```go
func (h *WarehouseHandler) Delete(c *gin.Context) {
shopID := middleware.GetShopID(c)
now := timeNow()
result := h.db.Model(&model.Warehouse{}).
Where("id = ? AND shop_id = ? AND deleted_at IS NULL", c.Param("id"), shopID).
Update("deleted_at", now)
if result.RowsAffected == 0 {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "deleted"})
}
```