Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
a15d1d93c8
@ -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()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user