hi-server/internal/logic/public/iap/apple/singleModeHelper.go
shanshanzhong abc9864d46
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 7m31s
fix: 单订阅模式下避免重复创建订阅
1. FindSingleModeAnchorSubscribe 补充 status=4(流量耗完)到查询范围,
   避免流量耗尽的订阅被忽略导致续费时新建订阅

2. activateOrderLogic NewPurchase 路径去掉套餐ID匹配检查,
   单订阅模式下无论购买何种套餐都更新现有订阅而非新建

3. singleModeHelper fallback 查询同步补充 status=4

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-31 05:13:00 -07:00

66 lines
2.0 KiB
Go

package apple
import (
"context"
"errors"
commonLogic "github.com/perfect-panel/server/internal/logic/common"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
"gorm.io/gorm"
)
func findSingleModeMergeTarget(ctx context.Context, svcCtx *svc.ServiceContext, userId int64, subscribeId int64) (*user.Subscribe, error) {
anchorSub, err := svcCtx.UserModel.FindSingleModeAnchorSubscribe(ctx, userId)
switch {
case err == nil && anchorSub != nil && anchorSub.Id > 0:
if subscribeId > 0 && anchorSub.SubscribeId != subscribeId {
return nil, commonLogic.ErrSingleModePlanMismatch
}
return anchorSub, nil
case err != nil && !errors.Is(err, gorm.ErrRecordNotFound):
return nil, err
}
userSubs, queryErr := svcCtx.UserModel.QueryUserSubscribe(ctx, userId, 0, 1, 2, 3, 4, 5)
if queryErr != nil {
return nil, queryErr
}
var candidate *user.SubscribeDetails
for _, item := range userSubs {
if item == nil {
continue
}
if subscribeId > 0 && item.SubscribeId != subscribeId {
continue
}
if candidate == nil ||
item.ExpireTime.After(candidate.ExpireTime) ||
(item.ExpireTime.Equal(candidate.ExpireTime) && item.UpdatedAt.After(candidate.UpdatedAt)) ||
(item.ExpireTime.Equal(candidate.ExpireTime) && item.UpdatedAt.Equal(candidate.UpdatedAt) && item.Id > candidate.Id) {
candidate = item
}
}
if candidate == nil {
return nil, gorm.ErrRecordNotFound
}
return &user.Subscribe{
Id: candidate.Id,
UserId: candidate.UserId,
OrderId: candidate.OrderId,
SubscribeId: candidate.SubscribeId,
StartTime: candidate.StartTime,
ExpireTime: candidate.ExpireTime,
FinishedAt: candidate.FinishedAt,
Traffic: candidate.Traffic,
Download: candidate.Download,
Upload: candidate.Upload,
Token: candidate.Token,
UUID: candidate.UUID,
Status: candidate.Status,
Note: candidate.Note,
CreatedAt: candidate.CreatedAt,
UpdatedAt: candidate.UpdatedAt,
}, nil
}