feat(backend): 库存三态落库(stock/on_sale/sold)——挂售可控 + 卖光留痕

- inventories 加 status 枚举列(默认 stock,AutoMigrate 存量即全部「库存」)+ 索引
- 出库审核扣光置 sold 不再软删(留痕台账);退单恢复行置回 stock;盘亏仍软删
- 新接口 PUT /inventory/:id/status(仅收 stock/on_sale,已售行拒改,租户校验)
- List 默认排除已售(显式 status=sold 才显示)+ status 多值筛选
- Summary:SKU/货值/数量排除已售,新增 sold_count
- 公开店铺页/API 只列 on_sale——酒单从全量裸奔改为人工精选
- 测试:卖光置售/部分不改/退单回库/接口边界/跨租户/汇总口径 8 用例
- 设计方案 docs/design/inventory-sale-status.html + db-schema/CLAUDE.md 同步

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
wangjia
2026-07-07 13:35:03 +08:00
parent b0b38db39f
commit 73955a139c
15 changed files with 386 additions and 9 deletions
+2 -2
View File
@@ -87,10 +87,10 @@ func (h *PublicHandler) loadPublicProduct(publicID string) (*publicProductData,
// queryShopProducts 店铺公开商品列表查询——ListShopProductsJSON API)与 ShopPageSSR)共用。
// keyword 为空时不过滤(API 现状);非空时按 名称/编号/全拼/首字母 模糊匹配(SSR 搜索框)。
func (h *PublicHandler) queryShopProducts(shopID uint64, page, pageSize int, keyword string) ([]publicProductResp, int64, error) {
// 仅列「有库存」的商品JOIN 库存按 product 聚合(数量>0)的子查询
// 仅列「在售且有库存」的商品2026-07-07 三态:公开酒单只挂 status=on_sale
stockSub := h.db.Model(&model.Inventory{}).
Select("product_id, SUM(quantity) AS qty").
Where("shop_id = ? AND deleted_at IS NULL AND quantity > 0", shopID).
Where("shop_id = ? AND deleted_at IS NULL AND quantity > 0 AND status = 'on_sale'", shopID).
Group("product_id")
query := h.db.Model(&model.Product{}).