Merge remote-tracking branch 'origin/master'

This commit is contained in:
Administrator 2026-06-18 13:03:11 +08:00
commit a15d1d93c8

View File

@ -1477,9 +1477,15 @@ func (s *ProcessService) CreateSalesOrderWithDetail(req systemReq.SalesOrderCrea
return fmt.Errorf("批量创建销售订单明细失败: %v", err)
}
// 锁定库存
//for _, itemReq := range req.Items {
// if err := s.lockInventory(tx, invWarehouseID, itemReq.ProductID, itemReq.Quantity, now); err != nil {
// return fmt.Errorf("锁定库存失败[商品ID=%d]: %v", itemReq.ProductID, err)
// }
//}
// 锁定库存
for _, itemReq := range req.Items {
if err := s.lockInventory(tx, invWarehouseID, itemReq.ProductID, itemReq.Quantity, now); err != nil {
if err := s.lockInventoryByAppearance(tx, invWarehouseID, itemReq.ProductID, itemReq.Quantity, now); err != nil {
return fmt.Errorf("锁定库存失败[商品ID=%d]: %v", itemReq.ProductID, err)
}
}
@ -3653,6 +3659,77 @@ func (s *ProcessService) processInventoryDetailOperationForAdjustment(tx *gorm.D
return nil
}
// lockInventoryByAppearance 按品相+ISBN匹配所有商品的库存进行锁定
func (s *ProcessService) lockInventoryByAppearance(tx *gorm.DB, warehouseID, productID, quantity int64, now int64) error {
var product models.Product
if err := tx.Where("id = ? AND is_del = 0", productID).First(&product).Error; err != nil {
return fmt.Errorf("查询商品信息失败: %v", err)
}
var matchingProductIDs []int64
if err := tx.Model(&models.Product{}).
Where("barcode = ? AND appearance = ? AND is_del = 0", product.Barcode, product.Appearance).
Pluck("id", &matchingProductIDs).Error; err != nil {
return fmt.Errorf("查询同品相商品失败: %v", err)
}
if len(matchingProductIDs) == 0 {
return fmt.Errorf("无匹配的商品记录")
}
var inventories []models.Inventory
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Where("warehouse_id = ? AND product_id IN ? AND is_del = 0 AND quantity > locked_quantity",
warehouseID, matchingProductIDs).
Order("product_id ASC, expiry_date ASC, created_at ASC").
Find(&inventories).Error; err != nil {
return fmt.Errorf("查询可用库存失败: %v", err)
}
if len(inventories) == 0 {
return fmt.Errorf("商品(barcode=%s,appearance=%d)在仓库ID=%d中无可用库存", product.Barcode, product.Appearance, warehouseID)
}
remainingLock := quantity
for i := range inventories {
if remainingLock <= 0 {
break
}
availableQty := inventories[i].Quantity - inventories[i].LockedQuantity
if availableQty <= 0 {
continue
}
lockQty := availableQty
if lockQty > remainingLock {
lockQty = remainingLock
}
result := tx.Model(&inventories[i]).
Where("quantity - locked_quantity >= ?", lockQty).
UpdateColumns(map[string]interface{}{
"locked_quantity": gorm.Expr("locked_quantity + ?", lockQty),
"updated_at": now,
})
if result.Error != nil {
return fmt.Errorf("锁定库存失败: %v", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("库存已被其他事务修改,请重试")
}
remainingLock -= lockQty
}
if remainingLock > 0 {
return fmt.Errorf("可用库存不足,还需锁定:%d", remainingLock)
}
return nil
}
// 执行事务(使用指定数据库)
func executeInTransactionWithDB(db *gorm.DB, txFunc func(*gorm.DB) error) error {
tx := db.Begin()