diff --git a/internal/service/douyin/scheduler.go b/internal/service/douyin/scheduler.go index 153123d..eda1525 100755 --- a/internal/service/douyin/scheduler.go +++ b/internal/service/douyin/scheduler.go @@ -1,6 +1,7 @@ package douyin import ( + "encoding/json" "errors" "bindbox-game/internal/pkg/logger" @@ -419,6 +420,113 @@ func (s *service) reclaimLivestreamAssets(ctx context.Context, log *model.Livest // 3. 恢复奖品库存 db.Exec("UPDATE livestream_prizes SET remaining = remaining + 1 WHERE id = ? AND remaining >= 0", log.PrizeID) s.logger.Info("[资产回收] 恢复奖品库存", zap.Int64("prize_id", log.PrizeID)) + + // 4. 回收翻牌游戏资格(如果奖品配置了翻牌游戏) + s.reclaimFlipCardTicket(ctx, log) +} + +// reclaimFlipCardTicket 回收翻牌游戏资格 +// 逻辑:如果订单对应的商品配置了翻牌游戏奖励,需要回收用户的翻牌次数 +func (s *service) reclaimFlipCardTicket(ctx context.Context, log *model.LivestreamDrawLogs) { + db := s.repo.GetDbW().WithContext(ctx) + + // 1. 查找对应的抖店订单,获取商品ID + var order model.DouyinOrders + if err := s.repo.GetDbR().Where("shop_order_id = ?", log.ShopOrderID).First(&order).Error; err != nil { + s.logger.Warn("[翻牌回收] 查询订单失败", zap.String("shop_order_id", log.ShopOrderID), zap.Error(err)) + return + } + + if order.DouyinProductID == "" { + return // 订单没有商品ID + } + + // 2. 查询该商品是否配置了翻牌游戏奖励 + var rewards []model.DouyinProductRewards + if err := s.repo.GetDbR().Where("product_id = ? AND status = 1", order.DouyinProductID).Find(&rewards).Error; err != nil { + s.logger.Warn("[翻牌回收] 查询奖励配置失败", zap.String("product_id", order.DouyinProductID), zap.Error(err)) + return + } + + // 3. 检查是否有翻牌游戏奖励 + hasFlipCard := false + for _, reward := range rewards { + if reward.RewardType == "game_ticket" && reward.RewardPayload != "" { + var payload struct { + GameCode string `json:"game_code"` + } + _ = json.Unmarshal([]byte(reward.RewardPayload), &payload) + if payload.GameCode == "flip_card" { + hasFlipCard = true + break + } + } + } + + if !hasFlipCard { + return // 没有配置翻牌游戏奖励 + } + + // 4. 回收翻牌游戏资格 + // 查找用户的翻牌游戏资格记录 + var ticket model.UserGameTickets + err := s.repo.GetDbR().Where("user_id = ? AND game_code = ?", log.LocalUserID, "flip_card").First(&ticket).Error + if err != nil { + s.logger.Warn("[翻牌回收] 用户没有翻牌资格记录", + zap.Int64("user_id", log.LocalUserID), + zap.String("shop_order_id", log.ShopOrderID)) + return + } + + // 检查是否有可用次数 + if ticket.Available <= 0 { + s.logger.Info("[翻牌回收] 用户翻牌次数已为0,无需回收", + zap.Int64("user_id", log.LocalUserID), + zap.Int32("available", ticket.Available)) + return + } + + // 扣减翻牌次数 + result := db.Model(&model.UserGameTickets{}). + Where("user_id = ? AND game_code = ? AND available > 0", log.LocalUserID, "flip_card"). + Updates(map[string]interface{}{ + "available": gorm.Expr("available - 1"), + "total_earned": gorm.Expr("total_earned - 1"), + "updated_at": time.Now(), + }) + + if result.Error != nil { + s.logger.Error("[翻牌回收] 扣减翻牌次数失败", + zap.Error(result.Error), + zap.Int64("user_id", log.LocalUserID)) + return + } + + if result.RowsAffected == 0 { + s.logger.Warn("[翻牌回收] 扣减翻牌次数失败,可能次数不足", + zap.Int64("user_id", log.LocalUserID)) + return + } + + // 记录日志 + logEntry := &model.GameTicketLogs{ + UserID: log.LocalUserID, + GameCode: "flip_card", + ChangeType: 3, // 3=扣除/回收 + Amount: -1, + Balance: ticket.Available - 1, + Source: "refund_reclaim", + SourceID: log.ID, + Remark: fmt.Sprintf("订单退款回收翻牌资格 (订单: %s)", log.ShopOrderID), + } + if err := db.Create(logEntry).Error; err != nil { + s.logger.Error("[翻牌回收] 记录日志失败", zap.Error(err)) + } + + s.logger.Info("[翻牌回收] 成功回收翻牌资格", + zap.Int64("user_id", log.LocalUserID), + zap.String("shop_order_id", log.ShopOrderID), + zap.Int32("remaining", ticket.Available-1)) } type activityAttribution struct {