fix(activity): 对对碰发奖跳过奖项库存扣减

仅对对碰调用订单发奖时跳过 activity_reward_settings.quantity 校验和扣减,其他发奖场景仍保留原有库存保护。
This commit is contained in:
Zuncle 2026-05-22 15:25:40 +08:00
parent 566641a2e7
commit c849d2cc4f
2 changed files with 35 additions and 31 deletions

View File

@ -40,12 +40,12 @@ func matchingRewardDisplayName(name string, isDoubled bool) string {
}
type matchingSettlementPlan struct {
reward *model.ActivityRewardSettings
quantity int
productName string
rewardName string
cardToVoid int64
drawLogID int64
reward *model.ActivityRewardSettings
quantity int
productName string
rewardName string
cardToVoid int64
drawLogID int64
}
// grantRewardHelper 发放奖励辅助函数
@ -59,12 +59,13 @@ func (h *handler) grantRewardHelper(ctx context.Context, userID, orderID int64,
rid := r.ID
_, err := h.user.GrantRewardToOrder(ctx, userID, usersvc.GrantRewardToOrderRequest{
OrderID: orderID,
ProductID: r.ProductID,
Quantity: quantity,
ActivityID: &actID,
RewardID: &rid,
Remark: remark,
OrderID: orderID,
ProductID: r.ProductID,
Quantity: quantity,
ActivityID: &actID,
RewardID: &rid,
Remark: remark,
SkipRewardInventory: true,
})
if err != nil {
h.logger.Error("Failed to grant reward to order", zap.Int64("order_id", orderID), zap.Error(err))

View File

@ -280,12 +280,13 @@ func generateOrderNo() string {
// GrantRewardToOrderRequest 在现有订单上发放奖励的请求参数
type GrantRewardToOrderRequest struct {
OrderID int64 `json:"order_id" binding:"required"` // 现有订单ID
ProductID int64 `json:"product_id" binding:"required"` // 商品ID
Quantity int `json:"quantity" binding:"min=1"` // 发放数量
ActivityID *int64 `json:"activity_id,omitempty"` // 活动ID可选
RewardID *int64 `json:"reward_id,omitempty"` // 奖励配置ID可选
Remark string `json:"remark,omitempty"` // 备注
OrderID int64 `json:"order_id" binding:"required"` // 现有订单ID
ProductID int64 `json:"product_id" binding:"required"` // 商品ID
Quantity int `json:"quantity" binding:"min=1"` // 发放数量
ActivityID *int64 `json:"activity_id,omitempty"` // 活动ID可选
RewardID *int64 `json:"reward_id,omitempty"` // 奖励配置ID可选
Remark string `json:"remark,omitempty"` // 备注
SkipRewardInventory bool `json:"-"` // 跳过活动奖项库存扣减
}
// GrantRewardToOrderResponse 在现有订单上发放奖励的响应
@ -330,18 +331,21 @@ func (s *service) GrantRewardToOrder(ctx context.Context, userID int64, req Gran
if req.RewardID != nil {
logger.Info("检查奖励配置", zap.Int64("reward_id", *req.RewardID))
// 【使用乐观锁扣减库存】直接用 Quantity > 0 作为更新条件,避免竞态
result, err := tx.ActivityRewardSettings.WithContext(ctx).Where(
tx.ActivityRewardSettings.ID.Eq(*req.RewardID),
tx.ActivityRewardSettings.Quantity.Gt(0), // 乐观锁:只有库存>0才能扣减
).UpdateSimple(tx.ActivityRewardSettings.Quantity.Add(-int64(req.Quantity)))
if err != nil {
logger.Error("扣减奖励库存失败", zap.Error(err))
return fmt.Errorf("扣减奖励库存失败: %w", err)
}
if result.RowsAffected == 0 {
logger.Error("奖励库存不足或不存在")
return fmt.Errorf("奖励库存不足或不存在")
if !req.SkipRewardInventory {
// 【使用乐观锁扣减库存】直接用 Quantity > 0 作为更新条件,避免竞态
result, err := tx.ActivityRewardSettings.WithContext(ctx).Where(
tx.ActivityRewardSettings.ID.Eq(*req.RewardID),
tx.ActivityRewardSettings.Quantity.Gt(0), // 乐观锁:只有库存>0才能扣减
).UpdateSimple(tx.ActivityRewardSettings.Quantity.Add(-int64(req.Quantity)))
if err != nil {
logger.Error("扣减奖励库存失败", zap.Error(err))
return fmt.Errorf("扣减奖励库存失败: %w", err)
}
if result.RowsAffected == 0 {
logger.Error("奖励库存不足或不存在")
return fmt.Errorf("奖励库存不足或不存在")
}
logger.Info("奖励库存扣减成功(乐观锁)")
}
rewardSetting, err = tx.ActivityRewardSettings.WithContext(ctx).Where(
tx.ActivityRewardSettings.ID.Eq(*req.RewardID),
@ -350,7 +354,6 @@ func (s *service) GrantRewardToOrder(ctx context.Context, userID int64, req Gran
logger.Error("查询奖励配置失败", zap.Error(err))
return fmt.Errorf("查询奖励配置失败: %w", err)
}
logger.Info("奖励库存扣减成功(乐观锁)")
}
// 3. 查询商品信息快照