From 5d7ca4b9bdc2e51f60a2e4fc8e30a8c141c6ae38 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Wed, 17 Dec 2025 18:48:57 -0800 Subject: [PATCH] =?UTF-8?q?feat(iap/apple):=20=E4=BB=8EApple=E5=95=86?= =?UTF-8?q?=E5=93=81ID=E8=A7=A3=E6=9E=90=E8=B4=AD=E4=B9=B0=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E5=B9=B6=E5=8C=B9=E9=85=8D=E8=AE=A2=E9=98=85=E6=8A=98?= =?UTF-8?q?=E6=89=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加从Apple商品ID中解析购买数量(天数)的逻辑,并基于订阅列表的折扣配置进行匹配。当商品ID包含"day"时,提取后续数字作为购买数量,然后查找对应数量的订阅折扣配置。 --- .../iap/apple/attachTransactionLogic.go | 70 ++++++++++++++++--- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/internal/logic/public/iap/apple/attachTransactionLogic.go b/internal/logic/public/iap/apple/attachTransactionLogic.go index 57edc8a..fa43c3b 100644 --- a/internal/logic/public/iap/apple/attachTransactionLogic.go +++ b/internal/logic/public/iap/apple/attachTransactionLogic.go @@ -6,11 +6,14 @@ import ( "encoding/hex" "encoding/json" "fmt" + "strconv" + "strings" "time" "github.com/google/uuid" "github.com/hibiken/asynq" iapmodel "github.com/perfect-panel/server/internal/model/iap/apple" + "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -54,18 +57,67 @@ func (l *AttachTransactionLogic) Attach(req *types.AttachAppleTransactionRequest var existTx *iapmodel.Transaction existTx, _ = iapmodel.NewModel(l.svcCtx.DB, l.svcCtx.Redis).FindByOriginalId(l.ctx, txPayload.OriginalTransactionId) l.Infow("幂等等检查", logger.Field("originalTransactionId", txPayload.OriginalTransactionId), logger.Field("exists", existTx != nil && existTx.Id > 0)) - pm, _ := iapapple.ParseProductMap(l.svcCtx.Config.Site.CustomData) - m, ok := pm.Items[txPayload.ProductId] - l.Infow("商品映射解析", logger.Field("items_count", len(pm.Items)), logger.Field("命中映射", ok)) + + // 从 Apple 商品ID中解析购买数量(天数),形如 com.hifastvpn.plan.day7 -> 7 + var parsedQuantity int64 + if idx := strings.Index(strings.ToLower(txPayload.ProductId), "day"); idx >= 0 { + sub := txPayload.ProductId[idx+3:] + for i := 0; i < len(sub); i++ { + if sub[i] < '0' || sub[i] > '9' { + sub = sub[:i] + break + } + } + if q, e := strconv.ParseInt(sub, 10, 64); e == nil && q > 0 { + parsedQuantity = q + } + } + l.Infow("商品映射解析", logger.Field("productId", txPayload.ProductId), logger.Field("解析数量", parsedQuantity)) + + // 基于订阅列表的折扣配置做匹配:UnitTime=Day 且 Discount.quantity == parsedQuantity var duration int64 var tier string var subscribeId int64 - if ok { - duration = m.DurationDays - tier = m.Tier - subscribeId = m.SubscribeId - l.Infow("命中商品映射", logger.Field("productId", txPayload.ProductId), logger.Field("durationDays", duration), logger.Field("tier", tier), logger.Field("subscribeId", subscribeId)) - } else { + if parsedQuantity > 0 { + _, subs, e := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{ + Page: 1, + Size: 9999, + Show: true, + Sell: true, + DefaultLanguage: true, + }) + if e == nil && len(subs) > 0 { + for _, item := range subs { + if !strings.EqualFold(item.UnitTime, "Day") { + continue + } + var discounts []types.SubscribeDiscount + if item.Discount != "" { + _ = json.Unmarshal([]byte(item.Discount), &discounts) + } + for _, d := range discounts { + if int64(d.Quantity) == parsedQuantity { + duration = parsedQuantity + subscribeId = item.Id + tier = item.Name + l.Infow("订阅映射命中", logger.Field("subscribeId", subscribeId), logger.Field("name", tier), logger.Field("durationDays", duration)) + break + } + } + if subscribeId > 0 { + break + } + } + } else { + l.Infow("订阅列表为空或查询失败", logger.Field("error", func() string { + if e != nil { + return e.Error() + } + return "" + }())) + } + } + if subscribeId == 0 { // fallback from order_no if provided if req.OrderNo != "" { if ord, e := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo); e == nil && ord != nil && ord.Id != 0 {