fix: IAP 重复交易检测优化,防止续期误拦和孤儿订单
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 7m33s

1. 关闭孤儿订单:检测到重复交易时,立即关闭新的 pending 订单(status=3)
2. tradeNo 候选改为只用 transactionId,不再用 originalTransactionId
   - originalTransactionId 是整个订阅族共享的,续期时会误命中旧订单
   - originalTransactionId 仍用于 IAP 事务表幂等检查(FindByOriginalId)
This commit is contained in:
shanshanzhong 2026-03-09 02:32:42 -07:00
parent b303f16525
commit 57fa2b4d69

View File

@ -40,6 +40,7 @@ const (
orderTypeSubscribe uint8 = 1
orderStatusPending uint8 = 1
orderStatusPaid uint8 = 2
orderStatusClosed uint8 = 3
orderStatusFinished uint8 = 5
)
@ -101,6 +102,16 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest
if existingOrderNo != "" {
l.Errorw("Apple 交易重复绑定,返回已绑定订单", logger.Field("orderNo", req.OrderNo), logger.Field("existingOrderNo", existingOrderNo), logger.Field("tradeNoCandidates", tradeNoCandidates))
l.sendIAPAttachTraceToTelegram("REJECT_DUPLICATE_TRANSACTION", orderInfo, u.Id, orderInfo.SubscribeId, "", orderInfo.Quantity, txPayload.PurchaseDate, txPayload.TransactionId, txPayload.OriginalTransactionId, "already used by "+existingOrderNo)
// 关闭当前 pending 订单,避免产生孤儿订单
if orderInfo.Status == orderStatusPending {
if closeErr := l.svcCtx.DB.Model(&ordermodel.Order{}).
Where("order_no = ? AND status = ?", req.OrderNo, orderStatusPending).
Update("status", orderStatusClosed).Error; closeErr != nil {
l.Errorw("关闭重复订单失败", logger.Field("orderNo", req.OrderNo), logger.Field("error", closeErr.Error()))
} else {
l.Infow("已关闭重复 pending 订单", logger.Field("orderNo", req.OrderNo), logger.Field("existingOrderNo", existingOrderNo))
}
}
return &types.AttachAppleTransactionResponse{ExistingOrderNo: existingOrderNo}, nil
}
tradeNo := ""
@ -496,11 +507,8 @@ func (l *AttachTransactionLogic) getAppleTradeNoCandidates(txPayload *iapapple.T
if txPayload == nil {
return nil
}
candidates := make([]string, 0, 2)
if txPayload.OriginalTransactionId != "" {
candidates = append(candidates, txPayload.OriginalTransactionId)
}
if txPayload.TransactionId != "" && txPayload.TransactionId != txPayload.OriginalTransactionId {
candidates := make([]string, 0, 1)
if txPayload.TransactionId != "" {
candidates = append(candidates, txPayload.TransactionId)
}
return candidates