feat(backend): 商品价格历史接口(从入库单价派生)

GET /products/:id/price-history:从已审核入库单明细 unit_price 按 order_date
倒序派生进价变更点,去相邻重复价,守多租户 shop_id(零额外表)。
新增测试 PriceHistory(含草稿排除 + 倒序断言)。go build/vet/test 全过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
This commit is contained in:
wangjia
2026-06-25 16:06:56 +08:00
parent 38e2ea1c6c
commit deb5e503f6
4 changed files with 74 additions and 0 deletions
+33
View File
@@ -233,6 +233,39 @@ func (h *ProductHandler) Detail(c *gin.Context) {
util.RespondSuccess(c, product)
}
// PriceHistory GET /api/v1/products/:id/price-history
// 进价变更历史:从已审核入库单的明细单价按时间派生(零额外表)。
// 返回按日期倒序的 {date, price} 点;前端据相邻点算涨跌。
func (h *ProductHandler) PriceHistory(c *gin.Context) {
shopID := middleware.GetShopID(c)
id := c.Param("id")
type pricePoint struct {
Date string `json:"date"`
Price float64 `json:"price"`
}
points := make([]pricePoint, 0)
// 守多租户:order 的 shop_id 必须等于当前店;只取已审核单的正单价。
h.db.Raw(`
SELECT o.order_date AS date, sii.unit_price AS price
FROM stock_in_items sii
JOIN stock_in_orders o ON o.id = sii.order_id
WHERE sii.product_id = ? AND o.shop_id = ? AND o.status = 'approved'
AND sii.unit_price > 0
ORDER BY o.order_date DESC, sii.id DESC
LIMIT 20`, id, shopID).Scan(&points)
// 去掉相邻重复价(只保留价格发生变化的点)
deduped := make([]pricePoint, 0, len(points))
for i, p := range points {
if i > 0 && points[i-1].Price == p.Price {
continue
}
deduped = append(deduped, p)
}
util.RespondSuccess(c, deduped)
}
// QRCode GET /api/v1/products/:id/qrcode
func (h *ProductHandler) QRCode(c *gin.Context) {
shopID := middleware.GetShopID(c)