feat: 单订阅模式下赠送订阅自动合并,保持token不变
Build docker and publish / build (20.15.1) (push) Failing after 7m38s

- purchaseLogic: 允许只有赠送订阅(order_id=0)的用户在SingleModel下新购
- activateOrderLogic: NewPurchase激活时检测赠送订阅,在原有订阅上延长到期时间而非创建新记录
This commit is contained in:
2026-02-24 21:01:36 -08:00
parent a81f28f304
commit 9638cc11fa
3 changed files with 133 additions and 5 deletions
+82 -3
View File
@@ -206,9 +206,31 @@ func (l *ActivateOrderLogic) NewPurchase(ctx context.Context, orderInfo *order.O
return err
}
userSub, err := l.createUserSubscription(ctx, orderInfo, sub)
if err != nil {
return err
var userSub *user.Subscribe
// 单订阅模式下,检查用户是否已有赠送订阅(order_id=0)
if l.svc.Config.Subscribe.SingleModel {
giftSub, err := l.findGiftSubscription(ctx, orderInfo.UserId, orderInfo.SubscribeId)
if err == nil && giftSub != nil {
// 在赠送订阅上延长时间,保持 token 不变
userSub, err = l.extendGiftSubscription(ctx, giftSub, orderInfo, sub)
if err != nil {
logger.WithContext(ctx).Error("Extend gift subscription failed",
logger.Field("error", err.Error()),
logger.Field("gift_subscribe_id", giftSub.Id),
)
// 合并失败时回退到创建新订阅
userSub = nil
}
}
}
// 如果没有合并赠送订阅,则正常创建新订阅
if userSub == nil {
userSub, err = l.createUserSubscription(ctx, orderInfo, sub)
if err != nil {
return err
}
}
// Handle commission in separate goroutine to avoid blocking
@@ -382,6 +404,63 @@ func (l *ActivateOrderLogic) createUserSubscription(ctx context.Context, orderIn
return userSub, nil
}
// findGiftSubscription 查找用户指定套餐的赠送订阅(order_id=0 且状态活跃)
// 返回找到的赠送订阅记录,如果没有则返回 nil
func (l *ActivateOrderLogic) findGiftSubscription(ctx context.Context, userId int64, subscribeId int64) (*user.Subscribe, error) {
// 查询用户所有活跃订阅
subs, err := l.svc.UserModel.QueryUserSubscribe(ctx, userId, 0, 1)
if err != nil {
return nil, err
}
// 查找 order_id=0(赠送)且同套餐的订阅
for _, s := range subs {
if s.OrderId == 0 && s.SubscribeId == subscribeId {
// 通过 ID 获取完整的 Subscribe 记录
sub, err := l.svc.UserModel.FindOneSubscribe(ctx, s.Id)
if err != nil {
return nil, err
}
return sub, nil
}
}
return nil, nil
}
// extendGiftSubscription 在现有赠送订阅上延长到期时间,保持 token 不变
// 将购买的天数叠加到赠送订阅的到期时间上,并更新 order_id 为新订单 ID
func (l *ActivateOrderLogic) extendGiftSubscription(ctx context.Context, giftSub *user.Subscribe, orderInfo *order.Order, sub *subscribe.Subscribe) (*user.Subscribe, error) {
now := time.Now()
// 计算基准时间:取赠送订阅到期时间和当前时间的较大值
baseTime := giftSub.ExpireTime
if baseTime.Before(now) {
baseTime = now
}
// 在基准时间上增加购买的天数
newExpireTime := tool.AddTime(sub.UnitTime, orderInfo.Quantity, baseTime)
// 更新赠送订阅的信息
giftSub.OrderId = orderInfo.Id
giftSub.ExpireTime = newExpireTime
giftSub.Status = 1
if err := l.svc.UserModel.UpdateSubscribe(ctx, giftSub); err != nil {
logger.WithContext(ctx).Error("Update gift subscription failed",
logger.Field("error", err.Error()),
logger.Field("subscribe_id", giftSub.Id),
)
return nil, err
}
logger.WithContext(ctx).Info("Extended gift subscription successfully",
logger.Field("subscribe_id", giftSub.Id),
logger.Field("old_expire_time", baseTime),
logger.Field("new_expire_time", newExpireTime),
logger.Field("order_id", orderInfo.Id),
)
return giftSub, nil
}
// handleCommission processes referral commission for the referrer if applicable.
// This runs asynchronously to avoid blocking the main order processing flow.
func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *user.User, orderInfo *order.Order) {