fix(shipping): 使用资产价值快照价格确保发货与分解价格一致
修复改价后发货价格与分解价格不一致的问题: - 发货时优先使用 user_inventory.value_cents 快照价格 - 后台发货列表使用 shipping_records.price 存储的快照价格 - 确保盈亏统计时价格数据准确一致
This commit is contained in:
parent
a29669ccf6
commit
2aa7cdbd61
@ -216,11 +216,46 @@ func (h *handler) ListShippingOrders() core.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取商品信息(去重并计数)
|
// 获取商品信息(去重并计数,使用发货记录中的价格快照)
|
||||||
pidCounts := make(map[int64]int64)
|
// 按商品ID聚合价格和数量
|
||||||
for _, pid := range a.pid {
|
type productInfo struct {
|
||||||
pidCounts[pid]++
|
Name string
|
||||||
|
Image string
|
||||||
|
Price int64 // 使用发货记录中的快照价格
|
||||||
|
Count int64
|
||||||
}
|
}
|
||||||
|
productMap := make(map[int64]*productInfo)
|
||||||
|
|
||||||
|
// 查询发货记录获取每个商品的快照价格
|
||||||
|
if len(a.recordIDs) > 0 {
|
||||||
|
records, _ := h.readDB.ShippingRecords.WithContext(ctx.RequestContext()).ReadDB().
|
||||||
|
Where(h.readDB.ShippingRecords.ID.In(a.recordIDs...)).
|
||||||
|
Find()
|
||||||
|
|
||||||
|
for _, r := range records {
|
||||||
|
if r.ProductID <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info, ok := productMap[r.ProductID]; ok {
|
||||||
|
info.Count++
|
||||||
|
} else {
|
||||||
|
// 查询商品名称和图片
|
||||||
|
var prodName, prodImage string
|
||||||
|
if prod, _ := h.readDB.Products.WithContext(ctx.RequestContext()).ReadDB().
|
||||||
|
Where(h.readDB.Products.ID.Eq(r.ProductID)).First(); prod != nil {
|
||||||
|
prodName = prod.Name
|
||||||
|
prodImage = prod.ImagesJSON
|
||||||
|
}
|
||||||
|
productMap[r.ProductID] = &productInfo{
|
||||||
|
Name: prodName,
|
||||||
|
Image: prodImage,
|
||||||
|
Price: r.Price, // 使用发货记录中的快照价格
|
||||||
|
Count: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var products []struct {
|
var products []struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -228,22 +263,20 @@ func (h *handler) ListShippingOrders() core.HandlerFunc {
|
|||||||
Price int64 `json:"price"`
|
Price int64 `json:"price"`
|
||||||
Count int64 `json:"count"`
|
Count int64 `json:"count"`
|
||||||
}
|
}
|
||||||
for pid, count := range pidCounts {
|
for pid, info := range productMap {
|
||||||
if prod, _ := h.readDB.Products.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Products.ID.Eq(pid)).First(); prod != nil {
|
products = append(products, struct {
|
||||||
products = append(products, struct {
|
ID int64 `json:"id"`
|
||||||
ID int64 `json:"id"`
|
Name string `json:"name"`
|
||||||
Name string `json:"name"`
|
Image string `json:"image"`
|
||||||
Image string `json:"image"`
|
Price int64 `json:"price"`
|
||||||
Price int64 `json:"price"`
|
Count int64 `json:"count"`
|
||||||
Count int64 `json:"count"`
|
}{
|
||||||
}{
|
ID: pid,
|
||||||
ID: prod.ID,
|
Name: info.Name,
|
||||||
Name: prod.Name,
|
Image: info.Image,
|
||||||
Image: prod.ImagesJSON, // 商品图片JSON
|
Price: info.Price, // 使用快照价格
|
||||||
Price: prod.Price,
|
Count: info.Count,
|
||||||
Count: count,
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items = append(items, &ShippingOrderGroup{
|
items = append(items, &ShippingOrderGroup{
|
||||||
|
|||||||
@ -200,11 +200,19 @@ func (s *service) SubmitAddressShare(ctx context.Context, shareToken string, nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// c. 创建发货记录 (归属于 targetUserID)
|
// c. 创建发货记录 (归属于 targetUserID)
|
||||||
var price int64
|
// 使用资产价值快照,确保价格与分解时一致
|
||||||
if inv.ProductID > 0 {
|
price := inv.ValueCents
|
||||||
|
if price <= 0 && inv.ProductID > 0 {
|
||||||
|
// 如果没有快照价格,回退到商品当前价格并记录快照
|
||||||
var p model.Products
|
var p model.Products
|
||||||
if err := tx.Table("products").Where("id = ?", inv.ProductID).First(&p).Error; err == nil {
|
if err := tx.Table("products").Where("id = ?", inv.ProductID).First(&p).Error; err == nil {
|
||||||
price = p.Price
|
price = p.Price
|
||||||
|
// 回写资产价值快照
|
||||||
|
tx.Table("user_inventory").Where("id = ?", inv.ID).Updates(map[string]interface{}{
|
||||||
|
"value_cents": price,
|
||||||
|
"value_source": 2,
|
||||||
|
"value_snapshot_at": time.Now(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,10 +273,15 @@ func (s *service) RequestShippingWithBatch(ctx context.Context, userID int64, in
|
|||||||
addrID = addr.ID
|
addrID = addr.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
var price int64
|
// 使用资产价值快照,确保价格与分解时一致
|
||||||
if inv.ProductID > 0 {
|
price := inv.ValueCents
|
||||||
|
if price <= 0 && inv.ProductID > 0 {
|
||||||
|
// 如果没有快照价格,回退到商品当前价格并记录快照
|
||||||
if p, e := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(inv.ProductID)).First(); e == nil && p != nil {
|
if p, e := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(inv.ProductID)).First(); e == nil && p != nil {
|
||||||
price = p.Price
|
price = p.Price
|
||||||
|
// 回写资产价值快照
|
||||||
|
s.repo.GetDbW().Exec("UPDATE user_inventory SET value_cents=?, value_source=?, value_snapshot_at=NOW(3) WHERE id=? AND user_id=?",
|
||||||
|
price, 2, inventoryID, userID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,8 +456,26 @@ func (s *service) RequestShippings(ctx context.Context, userID int64, inventoryI
|
|||||||
return addrID, batchNo, success, skipped, failed, nil
|
return addrID, batchNo, success, skipped, failed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 批量查询products获取价格(一次查询替代N次)
|
// 7. 批量查询products获取价格(用于没有快照价格的资产)
|
||||||
productMap := make(map[int64]int64) // productID -> price
|
productMap := make(map[int64]int64) // productID -> price
|
||||||
|
// 收集需要回写快照的资产
|
||||||
|
type valueFix struct {
|
||||||
|
ID int64
|
||||||
|
ValueCents int64
|
||||||
|
ValueSource int32
|
||||||
|
}
|
||||||
|
valueFixes := make([]valueFix, 0)
|
||||||
|
|
||||||
|
// 先检查哪些资产没有快照价格
|
||||||
|
for _, inv := range validInvs {
|
||||||
|
if inv.ValueCents <= 0 && inv.ProductID > 0 {
|
||||||
|
if _, ok := productIDSet[inv.ProductID]; !ok {
|
||||||
|
productIDSet[inv.ProductID] = struct{}{}
|
||||||
|
productIDs = append(productIDs, inv.ProductID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(productIDs) > 0 {
|
if len(productIDs) > 0 {
|
||||||
prods, _ := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.In(productIDs...)).Find()
|
prods, _ := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.In(productIDs...)).Find()
|
||||||
for _, p := range prods {
|
for _, p := range prods {
|
||||||
@ -455,9 +486,22 @@ func (s *service) RequestShippings(ctx context.Context, userID int64, inventoryI
|
|||||||
// 8. 单事务批量处理
|
// 8. 单事务批量处理
|
||||||
validIDs := make([]int64, 0, len(validInvs))
|
validIDs := make([]int64, 0, len(validInvs))
|
||||||
err = s.repo.GetDbW().Transaction(func(tx *gorm.DB) error {
|
err = s.repo.GetDbW().Transaction(func(tx *gorm.DB) error {
|
||||||
// 批量插入shipping_records
|
// 批量插入shipping_records(使用资产价值快照)
|
||||||
for _, inv := range validInvs {
|
for _, inv := range validInvs {
|
||||||
price := productMap[inv.ProductID]
|
// 优先使用资产价值快照,确保与分解价格一致
|
||||||
|
price := inv.ValueCents
|
||||||
|
valueSource := inv.ValueSource
|
||||||
|
if price <= 0 && inv.ProductID > 0 {
|
||||||
|
// 如果没有快照价格,回退到商品当前价格
|
||||||
|
price = productMap[inv.ProductID]
|
||||||
|
valueSource = 2
|
||||||
|
// 记录需要回写快照的资产
|
||||||
|
valueFixes = append(valueFixes, valueFix{
|
||||||
|
ID: inv.ID,
|
||||||
|
ValueCents: price,
|
||||||
|
ValueSource: valueSource,
|
||||||
|
})
|
||||||
|
}
|
||||||
if errExec := tx.Exec(
|
if errExec := tx.Exec(
|
||||||
"INSERT INTO shipping_records (user_id, order_id, order_item_id, inventory_id, product_id, quantity, price, address_id, status, batch_no, remark) VALUES (?,?,?,?,?,?,?,?,?,?,?)",
|
"INSERT INTO shipping_records (user_id, order_id, order_item_id, inventory_id, product_id, quantity, price, address_id, status, batch_no, remark) VALUES (?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
userID, inv.OrderID, 0, inv.ID, inv.ProductID, 1, price, addrID, 1, batchNo, "batch_request_shipping",
|
userID, inv.OrderID, 0, inv.ID, inv.ProductID, 1, price, addrID, 1, batchNo, "batch_request_shipping",
|
||||||
@ -467,6 +511,16 @@ func (s *service) RequestShippings(ctx context.Context, userID int64, inventoryI
|
|||||||
validIDs = append(validIDs, inv.ID)
|
validIDs = append(validIDs, inv.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 回写资产价值快照(用于之前没有快照的资产)
|
||||||
|
for _, fix := range valueFixes {
|
||||||
|
if err := tx.Exec(
|
||||||
|
"UPDATE user_inventory SET value_cents=?, value_source=?, value_snapshot_at=NOW(3) WHERE id=? AND user_id=?",
|
||||||
|
fix.ValueCents, fix.ValueSource, fix.ID, userID,
|
||||||
|
).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 批量更新inventory状态(一次UPDATE替代N次)
|
// 批量更新inventory状态(一次UPDATE替代N次)
|
||||||
if len(validIDs) > 0 {
|
if len(validIDs) > 0 {
|
||||||
if errExec := tx.Exec(
|
if errExec := tx.Exec(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user