Compare commits
11 Commits
98972401c2
...
06e4698888
| Author | SHA1 | Date | |
|---|---|---|---|
| 06e4698888 | |||
| e51dbea7c7 | |||
| c8f172dc0e | |||
| 52aaaf4de5 | |||
| 877a471e24 | |||
| 40cfe46ba8 | |||
| 5733ebe40d | |||
| 0b1e6ce3c3 | |||
| 3167465865 | |||
| 8838fc51f8 | |||
| ea34718a0b |
@ -21,7 +21,7 @@ env:
|
||||
SSH_PASSWORD: ${{ github.ref_name == 'main' && vars.SSH_PASSWORD || vars.DEV_SSH_PASSWORD }}
|
||||
# TG通知
|
||||
TG_BOT_TOKEN: 8114337882:AAHkEx03HSu7RxN4IHBJJEnsK9aPPzNLIk0
|
||||
TG_CHAT_ID: "-4940243803"
|
||||
TG_CHAT_ID: "-49402438031"
|
||||
# Go构建变量
|
||||
SERVICE: vpn
|
||||
SERVICE_STYLE: vpn
|
||||
|
||||
@ -76,7 +76,7 @@ func CountScopedSubscribePurchaseOrders(
|
||||
var count int64
|
||||
query := db.WithContext(ctx).
|
||||
Model(&modelOrder.Order{}).
|
||||
Where("user_id IN ? AND subscribe_id = ? AND type = 1", scopeUserIDs, subscribeID)
|
||||
Where("user_id IN ? AND subscribe_id = ? AND type IN ? AND amount > 0", scopeUserIDs, subscribeID, []int64{1, 2})
|
||||
if len(statuses) > 0 {
|
||||
query = query.Where("status IN ?", statuses)
|
||||
}
|
||||
|
||||
@ -2,17 +2,32 @@ package order
|
||||
|
||||
import "github.com/perfect-panel/server/internal/types"
|
||||
|
||||
// getDiscount returns the discount factor for the given quantity.
|
||||
//
|
||||
// - New user: pick the tier with the lowest discount value (biggest saving).
|
||||
// - Non-new user: pick the tier with the highest discount value (least saving / closest to full price).
|
||||
func getDiscount(discounts []types.SubscribeDiscount, inputMonths int64, isNewUser bool) float64 {
|
||||
for _, discount := range discounts {
|
||||
if discount.NewUserOnly && !isNewUser {
|
||||
best := float64(-1)
|
||||
for _, d := range discounts {
|
||||
if d.Quantity != inputMonths || d.Discount <= 0 || d.Discount >= 100 {
|
||||
continue
|
||||
}
|
||||
if inputMonths == discount.Quantity && discount.Discount > 0 && discount.Discount < 100 {
|
||||
return discount.Discount / float64(100)
|
||||
if isNewUser {
|
||||
// lowest discount value = biggest saving
|
||||
if best < 0 || d.Discount < best {
|
||||
best = d.Discount
|
||||
}
|
||||
} else {
|
||||
// highest discount value = least saving (closest to original price)
|
||||
if best < 0 || d.Discount > best {
|
||||
best = d.Discount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
if best < 0 {
|
||||
return 1
|
||||
}
|
||||
return best / float64(100)
|
||||
}
|
||||
|
||||
// isNewUserOnlyForQuantity checks whether the matched discount tier has new_user_only enabled.
|
||||
|
||||
@ -82,7 +82,7 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P
|
||||
decision, routeErr := commonLogic.ResolvePurchaseRoute(
|
||||
l.ctx,
|
||||
l.svcCtx.Config.Subscribe.SingleModel,
|
||||
u.Id,
|
||||
entitlement.EffectiveUserID,
|
||||
req.SubscribeId,
|
||||
l.svcCtx.UserModel.FindSingleModeAnchorSubscribe,
|
||||
)
|
||||
|
||||
@ -81,11 +81,17 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene
|
||||
if !*sub.Sell {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "subscribe not sell")
|
||||
}
|
||||
newUserDiscount, err := resolveNewUserDiscountEligibility(l.ctx, l.svcCtx.DB, u.Id, sub.Id, req.Quantity, sub.Discount)
|
||||
if err != nil {
|
||||
l.Errorw("[Renewal] Database query error resolving new user eligibility",
|
||||
logger.Field("error", err.Error()),
|
||||
logger.Field("user_id", u.Id),
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
var discount float64 = 1
|
||||
if sub.Discount != "" {
|
||||
var dis []types.SubscribeDiscount
|
||||
_ = json.Unmarshal([]byte(sub.Discount), &dis)
|
||||
discount = getDiscount(dis, req.Quantity, false)
|
||||
if len(newUserDiscount.Discounts) > 0 {
|
||||
discount = getDiscount(newUserDiscount.Discounts, req.Quantity, newUserDiscount.EligibleForDiscount)
|
||||
}
|
||||
price := sub.UnitPrice * req.Quantity
|
||||
amount := int64(math.Round(float64(price) * discount))
|
||||
|
||||
@ -229,9 +229,14 @@ func (l *ActivateOrderLogic) NewPurchase(ctx context.Context, orderInfo *order.O
|
||||
|
||||
var userSub *user.Subscribe
|
||||
|
||||
// 单订阅模式下,优先兜底为“续费语义”:延长已购订阅,避免并发下重复创建 user_subscribe
|
||||
// 单订阅模式下,优先兜底为”续费语义”:延长已购订阅,避免并发下重复创建 user_subscribe
|
||||
if l.svc.Config.Subscribe.SingleModel {
|
||||
anchorSub, anchorErr := l.svc.UserModel.FindSingleModeAnchorSubscribe(ctx, orderInfo.UserId)
|
||||
// 家庭组场景:订阅实际属于 SubscriptionUserId(成员/主),而非付款人 UserId
|
||||
singleModeUserId := orderInfo.UserId
|
||||
if orderInfo.SubscriptionUserId > 0 {
|
||||
singleModeUserId = orderInfo.SubscriptionUserId
|
||||
}
|
||||
anchorSub, anchorErr := l.svc.UserModel.FindSingleModeAnchorSubscribe(ctx, singleModeUserId)
|
||||
switch {
|
||||
case anchorErr == nil && anchorSub != nil:
|
||||
if orderInfo.ParentId == 0 && anchorSub.OrderId > 0 && anchorSub.OrderId != orderInfo.Id {
|
||||
@ -271,7 +276,7 @@ func (l *ActivateOrderLogic) NewPurchase(ctx context.Context, orderInfo *order.O
|
||||
|
||||
// 如果没有合并已购订阅,再尝试合并赠送订阅(order_id=0)
|
||||
if userSub == nil {
|
||||
giftSub, giftErr := l.findGiftSubscription(ctx, orderInfo.UserId, orderInfo.SubscribeId)
|
||||
giftSub, giftErr := l.findGiftSubscription(ctx, singleModeUserId, orderInfo.SubscribeId)
|
||||
if giftErr == nil && giftSub != nil {
|
||||
// 在赠送订阅上延长时间,保持 token 不变
|
||||
userSub, err = l.extendGiftSubscription(ctx, giftSub, orderInfo, sub)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user