package user import ( "context" "errors" "fmt" "time" "bindbox-game/internal/repository/mysql/model" "gorm.io/gorm" ) // TransferCoupon 转赠优惠券给另一个用户 // fromUserID: 发送方用户ID // toUserID: 接收方用户ID // userCouponID: 用户持有的优惠券记录ID func (s *service) TransferCoupon(ctx context.Context, fromUserID, toUserID, userCouponID int64) error { if fromUserID <= 0 || toUserID <= 0 || userCouponID <= 0 { return fmt.Errorf("invalid_params") } if fromUserID == toUserID { return fmt.Errorf("cannot_transfer_to_self") } // 1. 校验发送方持有该优惠券 uc, err := s.readDB.UserCoupons.WithContext(ctx). Where(s.readDB.UserCoupons.ID.Eq(userCouponID)). Where(s.readDB.UserCoupons.UserID.Eq(fromUserID)). First() if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("coupon_not_found") } return err } // 2. 校验优惠券状态为可用 if uc.Status != 1 { return fmt.Errorf("coupon_not_available") } // 3. 校验接收方用户存在 _, err = s.readDB.Users.WithContext(ctx).Where(s.readDB.Users.ID.Eq(toUserID)).First() if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("receiver_not_found") } return err } // 4. 执行转赠:更新 user_id db := s.repo.GetDbW() err = db.Transaction(func(tx *gorm.DB) error { // 更新优惠券归属 if err := tx.Model(&model.UserCoupons{}). Where("id = ? AND user_id = ? AND status = 1", userCouponID, fromUserID). Update("user_id", toUserID).Error; err != nil { return err } // 记录转出日志 transferOutLog := &model.UserCouponLedger{ UserID: fromUserID, UserCouponID: userCouponID, ChangeAmount: 0, // 转赠不涉及金额变动 BalanceAfter: uc.BalanceAmount, OrderID: 0, Action: "transfer_out", CreatedAt: time.Now(), } if err := tx.Create(transferOutLog).Error; err != nil { return err } // 记录转入日志 transferInLog := &model.UserCouponLedger{ UserID: toUserID, UserCouponID: userCouponID, ChangeAmount: 0, BalanceAfter: uc.BalanceAmount, OrderID: 0, Action: "transfer_in", CreatedAt: time.Now(), } if err := tx.Create(transferInLog).Error; err != nil { return err } return nil }) if err != nil { return err } fmt.Printf("[优惠券转赠] 成功: coupon_id=%d from=%d to=%d\n", userCouponID, fromUserID, toUserID) return nil }