双倍时间bug
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 8m33s
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 8m33s
This commit is contained in:
parent
4d913c1728
commit
03573d2e65
@ -241,7 +241,7 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
|||||||
|
|
||||||
if existTx != nil && existTx.Id > 0 {
|
if existTx != nil && existTx.Id > 0 {
|
||||||
if isNewPurchaseOrder {
|
if isNewPurchaseOrder {
|
||||||
if syncErr := l.syncOrderStatusAndEnqueue(orderInfo); syncErr != nil {
|
if syncErr := l.syncOrderStatusAndEnqueue(orderInfo, 0); syncErr != nil {
|
||||||
l.Errorw("事务已处理但同步订单状态失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
l.Errorw("事务已处理但同步订单状态失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", syncErr.Error()))
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "sync order status failed: %v", syncErr.Error())
|
||||||
}
|
}
|
||||||
@ -309,16 +309,10 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
|||||||
if !isNewPurchaseOrder {
|
if !isNewPurchaseOrder {
|
||||||
merged := false
|
merged := false
|
||||||
if orderLinkedSub != nil {
|
if orderLinkedSub != nil {
|
||||||
if _, e := l.extendSubscribeForIAP(orderLinkedSub, exp, subscribeId, tx); e != nil {
|
// 不在此处更新 expire_time:由激活队列统一写入,避免双重叠加天数
|
||||||
l.Errorw("更新订单关联订阅失败", logger.Field("error", e.Error()), logger.Field("userSubscribeId", orderLinkedSub.Id))
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
merged = true
|
merged = true
|
||||||
} else if singleModeAnchorSub != nil {
|
} else if singleModeAnchorSub != nil {
|
||||||
if _, e := l.extendSubscribeForIAP(singleModeAnchorSub, exp, subscribeId, tx); e != nil {
|
// 同上
|
||||||
l.Errorw("更新单订阅锚点失败", logger.Field("error", e.Error()), logger.Field("userSubscribeId", singleModeAnchorSub.Id))
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
merged = true
|
merged = true
|
||||||
}
|
}
|
||||||
if !merged {
|
if !merged {
|
||||||
@ -343,7 +337,7 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
|||||||
} else {
|
} else {
|
||||||
l.Infow("首购订单跳过 attach 阶段订阅写入", logger.Field("orderNo", orderInfo.OrderNo), logger.Field("orderType", orderInfo.Type))
|
l.Infow("首购订单跳过 attach 阶段订阅写入", logger.Field("orderNo", orderInfo.OrderNo), logger.Field("orderType", orderInfo.Type))
|
||||||
}
|
}
|
||||||
if e := l.syncOrderStatusAndEnqueue(orderInfo, tx); e != nil {
|
if e := l.syncOrderStatusAndEnqueue(orderInfo, exp.Unix(), tx); e != nil {
|
||||||
l.Errorw("同步订单状态失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", e.Error()))
|
l.Errorw("同步订单状态失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", e.Error()))
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
@ -360,7 +354,7 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *AttachTransactionLogic) syncOrderStatusAndEnqueue(orderInfo *ordermodel.Order, tx ...*gorm.DB) error {
|
func (l *AttachTransactionLogic) syncOrderStatusAndEnqueue(orderInfo *ordermodel.Order, iapExpireAt int64, tx ...*gorm.DB) error {
|
||||||
if orderInfo == nil || orderInfo.OrderNo == "" {
|
if orderInfo == nil || orderInfo.OrderNo == "" {
|
||||||
return errors.New("order info is nil")
|
return errors.New("order info is nil")
|
||||||
}
|
}
|
||||||
@ -372,7 +366,7 @@ func (l *AttachTransactionLogic) syncOrderStatusAndEnqueue(orderInfo *ordermodel
|
|||||||
l.Infow("更新订单状态成功", logger.Field("orderNo", orderInfo.OrderNo), logger.Field("status", orderStatusPaid))
|
l.Infow("更新订单状态成功", logger.Field("orderNo", orderInfo.OrderNo), logger.Field("status", orderStatusPaid))
|
||||||
}
|
}
|
||||||
// enqueue activation regardless (idempotent handler downstream)
|
// enqueue activation regardless (idempotent handler downstream)
|
||||||
payload := queueType.ForthwithActivateOrderPayload{OrderNo: orderInfo.OrderNo}
|
payload := queueType.ForthwithActivateOrderPayload{OrderNo: orderInfo.OrderNo, IAPExpireAt: iapExpireAt}
|
||||||
bytes, _ := json.Marshal(payload)
|
bytes, _ := json.Marshal(payload)
|
||||||
task := asynq.NewTask(queueType.ForthwithActivateOrder, bytes)
|
task := asynq.NewTask(queueType.ForthwithActivateOrder, bytes)
|
||||||
if _, err := l.svcCtx.Queue.EnqueueContext(l.ctx, task); err != nil {
|
if _, err := l.svcCtx.Queue.EnqueueContext(l.ctx, task); err != nil {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task)
|
|||||||
logger.Field("order_type", orderInfo.Type),
|
logger.Field("order_type", orderInfo.Type),
|
||||||
logger.Field("user_id", orderInfo.UserId))
|
logger.Field("user_id", orderInfo.UserId))
|
||||||
|
|
||||||
if err = l.processOrderByType(ctx, orderInfo); err != nil {
|
if err = l.processOrderByType(ctx, orderInfo, payload.IAPExpireAt); err != nil {
|
||||||
logger.WithContext(ctx).Error("[ActivateOrderLogic] 处理订单失败,将重试",
|
logger.WithContext(ctx).Error("[ActivateOrderLogic] 处理订单失败,将重试",
|
||||||
logger.Field("order_no", orderInfo.OrderNo),
|
logger.Field("order_no", orderInfo.OrderNo),
|
||||||
logger.Field("order_type", orderInfo.Type),
|
logger.Field("order_type", orderInfo.Type),
|
||||||
@ -169,12 +169,12 @@ func (l *ActivateOrderLogic) validateAndGetOrder(ctx context.Context, orderNo st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// processOrderByType routes order processing based on the order type
|
// processOrderByType routes order processing based on the order type
|
||||||
func (l *ActivateOrderLogic) processOrderByType(ctx context.Context, orderInfo *order.Order) error {
|
func (l *ActivateOrderLogic) processOrderByType(ctx context.Context, orderInfo *order.Order, iapExpireAt int64) error {
|
||||||
switch orderInfo.Type {
|
switch orderInfo.Type {
|
||||||
case OrderTypeSubscribe:
|
case OrderTypeSubscribe:
|
||||||
return l.NewPurchase(ctx, orderInfo)
|
return l.NewPurchase(ctx, orderInfo)
|
||||||
case OrderTypeRenewal:
|
case OrderTypeRenewal:
|
||||||
return l.Renewal(ctx, orderInfo)
|
return l.Renewal(ctx, orderInfo, iapExpireAt)
|
||||||
case OrderTypeResetTraffic:
|
case OrderTypeResetTraffic:
|
||||||
return l.ResetTraffic(ctx, orderInfo)
|
return l.ResetTraffic(ctx, orderInfo)
|
||||||
case OrderTypeRecharge:
|
case OrderTypeRecharge:
|
||||||
@ -716,7 +716,7 @@ func (l *ActivateOrderLogic) clearServerCache(ctx context.Context, sub *subscrib
|
|||||||
|
|
||||||
// Renewal handles subscription renewal including subscription extension,
|
// Renewal handles subscription renewal including subscription extension,
|
||||||
// traffic reset (if configured), commission processing, and notifications
|
// traffic reset (if configured), commission processing, and notifications
|
||||||
func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order) error {
|
func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order, iapExpireAt int64) error {
|
||||||
userInfo, err := l.getExistingUser(ctx, orderInfo.UserId)
|
userInfo, err := l.getExistingUser(ctx, orderInfo.UserId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -732,8 +732,16 @@ func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = l.updateSubscriptionForRenewal(ctx, userSub, sub, orderInfo); err != nil {
|
if iapExpireAt > 0 {
|
||||||
return err
|
// Apple IAP 续费:attachTransactionLogic 已通过 payload 传入 Apple 端计算的到期时间,
|
||||||
|
// 直接使用该时间,避免在现有 expire_time 基础上再叠加天数导致双重计算。
|
||||||
|
if err = l.updateSubscriptionWithIAPExpire(ctx, userSub, sub, iapExpireAt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = l.updateSubscriptionForRenewal(ctx, userSub, sub, orderInfo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear user subscription cache
|
// Clear user subscription cache
|
||||||
@ -768,6 +776,33 @@ func (l *ActivateOrderLogic) getUserSubscription(ctx context.Context, token stri
|
|||||||
return userSub, nil
|
return userSub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateSubscriptionWithIAPExpire 用于 Apple IAP 续费:直接将 Apple 服务端计算的
|
||||||
|
// 到期时间写入订阅,同时处理流量重置和 FinishedAt 清零,不再叠加天数。
|
||||||
|
func (l *ActivateOrderLogic) updateSubscriptionWithIAPExpire(ctx context.Context, userSub *user.Subscribe, sub *subscribe.Subscribe, iapExpireAt int64) error {
|
||||||
|
now := time.Now()
|
||||||
|
newExpire := time.Unix(iapExpireAt, 0)
|
||||||
|
today := now.Day()
|
||||||
|
resetDay := newExpire.Day()
|
||||||
|
|
||||||
|
if sub.RenewalReset != nil && *sub.RenewalReset || today == resetDay {
|
||||||
|
userSub.Download = 0
|
||||||
|
userSub.Upload = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if userSub.FinishedAt != nil {
|
||||||
|
userSub.FinishedAt = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userSub.ExpireTime = newExpire
|
||||||
|
userSub.Status = 1
|
||||||
|
|
||||||
|
if err := l.svc.UserModel.UpdateSubscribe(ctx, userSub); err != nil {
|
||||||
|
logger.WithContext(ctx).Error("Update user subscribe (IAP) failed", logger.Field("error", err.Error()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// updateSubscriptionForRenewal updates subscription details for renewal including
|
// updateSubscriptionForRenewal updates subscription details for renewal including
|
||||||
// expiration time extension and traffic reset if configured
|
// expiration time extension and traffic reset if configured
|
||||||
func (l *ActivateOrderLogic) updateSubscriptionForRenewal(ctx context.Context, userSub *user.Subscribe, sub *subscribe.Subscribe, orderInfo *order.Order) error {
|
func (l *ActivateOrderLogic) updateSubscriptionForRenewal(ctx context.Context, userSub *user.Subscribe, sub *subscribe.Subscribe, orderInfo *order.Order) error {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ type (
|
|||||||
OrderNo string `json:"order_no"`
|
OrderNo string `json:"order_no"`
|
||||||
}
|
}
|
||||||
ForthwithActivateOrderPayload struct {
|
ForthwithActivateOrderPayload struct {
|
||||||
OrderNo string `json:"order_no"`
|
OrderNo string `json:"order_no"`
|
||||||
|
IAPExpireAt int64 `json:"iap_expire_at,omitempty"` // Apple IAP 计算的到期时间(秒级 Unix),非零时队列直接使用,不再叠加天数
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user