diff --git a/internal/logic/public/order/preCreateOrderLogic.go b/internal/logic/public/order/preCreateOrderLogic.go index 65036da..f903e7c 100644 --- a/internal/logic/public/order/preCreateOrderLogic.go +++ b/internal/logic/public/order/preCreateOrderLogic.go @@ -106,6 +106,8 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r } // check new user only restriction (tier-level only) + // Only block users who registered more than 24h ago; users within 24h who already purchased + // are allowed to preview (they just won't receive the new-user discount). var newUserOnly bool if !isSingleModeRenewal && sub.Discount != "" { var dis []types.SubscribeDiscount @@ -116,20 +118,30 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r if time.Since(u.CreatedAt) > 24*time.Hour { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SubscribeNewUserOnly), "not a new user") } - var historyCount int64 - if e := l.svcCtx.DB.Model(&order.Order{}). - Where("user_id = ? AND subscribe_id = ? AND type = 1 AND status IN ?", - u.Id, targetSubscribeID, []int64{2, 5}). - Count(&historyCount).Error; e != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "check new user purchase history error: %v", e.Error()) - } - if historyCount >= 1 { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SubscribeNewUserOnly), "already purchased new user plan") - } } var discount float64 = 1 isNewUserForDiscount := time.Since(u.CreatedAt) <= 24*time.Hour + if isNewUserForDiscount && sub.Discount != "" { + // If the matched tier is new_user_only, check whether the user has already purchased this plan. + // If so, they are not eligible for the new-user discount (but the order is still allowed). + var dis []types.SubscribeDiscount + _ = json.Unmarshal([]byte(sub.Discount), &dis) + if isNewUserOnlyForQuantity(dis, req.Quantity) { + var historyCount int64 + if e := l.svcCtx.DB.Model(&order.Order{}). + Where("user_id = ? AND subscribe_id = ? AND type = 1 AND status IN ?", + u.Id, targetSubscribeID, []int64{2, 5}). + Count(&historyCount).Error; e != nil { + l.Errorw("[PreCreateOrder] Database query error checking new user discount eligibility", + logger.Field("error", e.Error()), logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "check new user discount history error: %v", e.Error()) + } + if historyCount >= 1 { + isNewUserForDiscount = false + } + } + } if sub.Discount != "" { var dis []types.SubscribeDiscount _ = json.Unmarshal([]byte(sub.Discount), &dis) diff --git a/internal/logic/public/order/purchaseLogic.go b/internal/logic/public/order/purchaseLogic.go index 1b4878b..fa11ec8 100644 --- a/internal/logic/public/order/purchaseLogic.go +++ b/internal/logic/public/order/purchaseLogic.go @@ -155,6 +155,26 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P var discount float64 = 1 isNewUserForDiscount := time.Since(u.CreatedAt) <= 24*time.Hour + if isNewUserForDiscount && sub.Discount != "" { + // If the matched tier is new_user_only, check whether the user has already purchased this plan. + // If so, they are not eligible for the new-user discount (but the order is still allowed). + var dis []types.SubscribeDiscount + _ = json.Unmarshal([]byte(sub.Discount), &dis) + if isNewUserOnlyForQuantity(dis, req.Quantity) { + var historyCount int64 + if e := l.svcCtx.DB.Model(&order.Order{}). + Where("user_id = ? AND subscribe_id = ? AND type = 1 AND status IN ?", + u.Id, targetSubscribeID, []int{2, 5}). + Count(&historyCount).Error; e != nil { + l.Errorw("[Purchase] Database query error checking new user discount eligibility", + logger.Field("error", e.Error()), logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "check new user discount history error: %v", e.Error()) + } + if historyCount >= 1 { + isNewUserForDiscount = false + } + } + } if sub.Discount != "" { var dis []types.SubscribeDiscount _ = json.Unmarshal([]byte(sub.Discount), &dis) @@ -301,6 +321,8 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P } // check new user only restriction inside transaction to prevent race condition (tier-level only) + // Only block users who registered more than 24h ago; users within 24h who already purchased + // are allowed to place another order (they just won't receive the new-user discount). if orderInfo.Type == 1 { var txNewUserOnly bool if sub.Discount != "" { @@ -312,16 +334,6 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P if time.Since(u.CreatedAt) > 24*time.Hour { return errors.Wrapf(xerr.NewErrCode(xerr.SubscribeNewUserOnly), "not a new user") } - var historyCount int64 - if e := db.Model(&order.Order{}). - Where("user_id = ? AND subscribe_id = ? AND type = 1 AND status IN ?", - u.Id, targetSubscribeID, []int{2, 5}). - Count(&historyCount).Error; e != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "check new user purchase history error: %v", e.Error()) - } - if historyCount >= 1 { - return errors.Wrapf(xerr.NewErrCode(xerr.SubscribeNewUserOnly), "already purchased new user plan") - } } } diff --git a/queue/logic/order/activateOrderLogic.go b/queue/logic/order/activateOrderLogic.go index 23032b2..1ad301b 100644 --- a/queue/logic/order/activateOrderLogic.go +++ b/queue/logic/order/activateOrderLogic.go @@ -575,10 +575,18 @@ func (l *ActivateOrderLogic) extendGiftSubscription(ctx context.Context, giftSub // This runs asynchronously to avoid blocking the main order processing flow. func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *user.User, orderInfo *order.Order) { if !l.shouldProcessCommission(userInfo, orderInfo.IsNew) { - l.grantGiftDaysToBothParties(ctx, userInfo, orderInfo.OrderNo) + // 普通用户路径(佣金比例=0):只有首单才双方赠N天 + if orderInfo.IsNew { + l.grantGiftDaysToBothParties(ctx, userInfo, orderInfo.OrderNo) + } return } + // 渠道路径(佣金比例>0):被邀请人首单赠N天 + if orderInfo.IsNew { + _ = l.grantGiftDays(ctx, userInfo, int(l.svc.Config.Invite.GiftDays), orderInfo.OrderNo, "邀请赠送") + } + referer, err := l.svc.UserModel.FindOne(ctx, userInfo.RefererId) if err != nil { logger.WithContext(ctx).Error("Find referer failed",