同步历史版本代码

This commit is contained in:
2026-03-03 09:32:22 -08:00
parent 7d46b31866
commit 4d8516b2e1
140 changed files with 8399 additions and 489 deletions
+164 -7
View File
@@ -5,6 +5,7 @@ package orderLogic
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
@@ -68,14 +69,32 @@ func NewActivateOrderLogic(svc *svc.ServiceContext) *ActivateOrderLogic {
// It handles the complete workflow of activating a paid order including validation,
// processing based on order type, and finalization.
func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) error {
logger.WithContext(ctx).Info("[ActivateOrderLogic] 开始处理订单激活任务",
logger.Field("payload", string(task.Payload())))
payload, err := l.parsePayload(ctx, task.Payload())
if err != nil {
return err // Return error to trigger retry
logger.WithContext(ctx).Error("[ActivateOrderLogic] 解析 payload 失败,跳过任务",
logger.Field("error", err.Error()))
return nil // payload 解析失败不重试,因为重试也会失败
}
logger.WithContext(ctx).Info("[ActivateOrderLogic] 正在验证订单",
logger.Field("order_no", payload.OrderNo))
orderInfo, err := l.validateAndGetOrder(ctx, payload.OrderNo)
if err != nil {
return err // Return error to trigger retry
// 如果订单不存在或状态不对,不重试
if errors.Is(err, ErrInvalidOrderStatus) {
logger.WithContext(ctx).Info("[ActivateOrderLogic] 订单状态不是已支付,跳过",
logger.Field("order_no", payload.OrderNo))
return nil
}
// 数据库查询失败,应该重试
logger.WithContext(ctx).Error("[ActivateOrderLogic] 查询订单失败,将重试",
logger.Field("order_no", payload.OrderNo),
logger.Field("error", err.Error()))
return err
}
// Idempotency: if order is already finished, skip processing
@@ -83,12 +102,25 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task)
return nil
}
logger.WithContext(ctx).Info("[ActivateOrderLogic] 订单验证通过,开始处理",
logger.Field("order_no", orderInfo.OrderNo),
logger.Field("order_type", orderInfo.Type),
logger.Field("user_id", orderInfo.UserId))
if err = l.processOrderByType(ctx, orderInfo); err != nil {
logger.WithContext(ctx).Error("[ActivateOrderLogic] Process task failed", logger.Field("error", err.Error()))
return err // Return error to trigger retry
logger.WithContext(ctx).Error("[ActivateOrderLogic] 处理订单失败,将重试",
logger.Field("order_no", orderInfo.OrderNo),
logger.Field("order_type", orderInfo.Type),
logger.Field("error", err.Error()))
return err // 返回 err 允许 asynq 重试
}
l.finalizeCouponAndOrder(ctx, orderInfo)
logger.WithContext(ctx).Info("[ActivateOrderLogic] 订单激活成功",
logger.Field("order_no", orderInfo.OrderNo),
logger.Field("order_type", orderInfo.Type),
logger.Field("user_id", orderInfo.UserId))
return nil
}
@@ -191,9 +223,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
@@ -385,10 +439,61 @@ 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) {
// 直接查询数据库,查找 order_id=0(赠送)且同套餐的订阅,不限制过期状态
var giftSub user.Subscribe
err := l.svc.DB.Model(&user.Subscribe{}).
Where("user_id = ? AND order_id = 0 AND subscribe_id = ?", userId, subscribeId).
Order("created_at DESC").
First(&giftSub).Error
if err != nil {
return nil, err
}
return &giftSub, 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) {
if !l.shouldProcessCommission(userInfo, orderInfo.IsNew) {
l.grantGiftDaysToBothParties(ctx, userInfo, orderInfo.OrderNo)
return
}
@@ -456,6 +561,58 @@ func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *use
}
}
func (l *ActivateOrderLogic) grantGiftDaysToBothParties(ctx context.Context, referee *user.User, orderNo string) {
giftDays := l.svc.Config.Invite.GiftDays
if giftDays <= 0 || referee == nil || referee.Id == 0 {
return
}
_ = l.grantGiftDays(ctx, referee, int(giftDays), orderNo, "邀请赠送")
if referee.RefererId == 0 {
return
}
referer, err := l.svc.UserModel.FindOne(ctx, referee.RefererId)
if err != nil || referer == nil {
return
}
_ = l.grantGiftDays(ctx, referer, int(giftDays), orderNo, "邀请赠送")
}
func (l *ActivateOrderLogic) grantGiftDays(ctx context.Context, u *user.User, days int, orderNo string, remark string) error {
if u == nil || days <= 0 {
return nil
}
activeSubscribe, err := l.svc.UserModel.FindActiveSubscribe(ctx, u.Id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
activeSubscribe.ExpireTime = activeSubscribe.ExpireTime.Add(time.Duration(days) * 24 * time.Hour)
err = l.svc.UserModel.UpdateSubscribe(ctx, activeSubscribe)
if err != nil {
return err
}
// Insert system log
giftLog := &log.Gift{
Type: log.GiftTypeIncrease,
OrderNo: orderNo,
SubscribeId: activeSubscribe.Id,
Amount: int64(days),
Balance: u.Balance,
Remark: remark,
Timestamp: time.Now().UnixMilli(),
}
content, _ := giftLog.Marshal()
return l.svc.LogModel.Insert(ctx, &log.SystemLog{
Type: log.TypeGift.Uint8(),
Date: time.Now().Format("2006-01-02"),
ObjectID: u.Id,
Content: string(content),
})
}
// shouldProcessCommission determines if commission should be processed based on
// referrer existence, commission settings, and order type
func (l *ActivateOrderLogic) shouldProcessCommission(userInfo *user.User, isFirstPurchase bool) bool {