package coinser import ( "context" "strings" "time" "videoweb/app/service/rechargeser/jiahua" "videoweb/pub/common/log" "videoweb/pub/common/srvdef" "videoweb/pub/models/rechargepackagemod" "videoweb/pub/models/usermod" "videoweb/pub/models/vipordermod" "videoweb/pub/mongos" "videoweb/pub/pubdef" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) // BuyCoinResp 购买金币下单响应 type BuyCoinResp struct { TradeNo string `json:"tradeNo"` PayUrl string `json:"payUrl"` PayUrlMode string `json:"payUrlMode"` IsOpenNewBrowser bool `json:"isOpenNewBrowser"` } // GetUserInfo 获取用户信息 func GetUserInfo(ctx context.Context, userId int64) (*usermod.User, *srvdef.SrvErr) { return usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: userId}) } // CreateCoinOrder 创建金币购买订单(统一写入 vip_order 表,OrderType=2)。 // 防重复:15 秒内同一用户+同一套餐的 pending 订单直接返回原支付链接。 func CreateCoinOrder(ctx context.Context, userId int64, userName string, packageId int64, payMode string, sysType string, devType string, ip string, districtCode string, ) (*BuyCoinResp, *srvdef.SrvErr) { pkg, serr := rechargepackagemod.FindOneRechargePackage(ctx, bson.M{ rechargepackagemod.FN.RechargePackage.Id: packageId, rechargepackagemod.FN.RechargePackage.PackageType: rechargepackagemod.PackageTypeCoin, rechargepackagemod.FN.RechargePackage.Status: rechargepackagemod.StatusEnabled, }) if serr != nil || pkg == nil { return nil, srvdef.New(srvdef.ErrNoData, "金币套餐不存在或已下架", "") } coinAmount := pkg.BaseCoin + pkg.GiftCoin if coinAmount <= 0 { return nil, srvdef.New(srvdef.ErrParamError, "金币套餐到账数量无效", "") } now := time.Now() dupFilter := bson.M{ vipordermod.FN.VipOrder.UserId: userId, vipordermod.FN.VipOrder.CoinCfgId: packageId, vipordermod.FN.VipOrder.OrderType: vipordermod.OrderTypeCoin, vipordermod.FN.VipOrder.PayMode: payMode, vipordermod.FN.VipOrder.Status: pubdef.VipOrderPending, vipordermod.FN.VipOrder.CreatedAt: bson.M{"$gte": now.Add(-15 * time.Second)}, } existing, _ := vipordermod.FindOneVipOrder(ctx, dupFilter) if existing != nil && existing.PayUrl != "" { return &BuyCoinResp{ TradeNo: existing.TradeNo, PayUrl: existing.PayUrl, PayUrlMode: existing.PayUrlMode, IsOpenNewBrowser: true, }, nil } tradeNo := pubdef.GetTrandNoWithUUID() payInfo, serr := jiahua.SubmitOrder(ctx, userId, userName, tradeNo, pkg.Price, payMode, sysType, devType, ip) if serr != nil { return nil, serr } order := &vipordermod.VipOrder{ Id: mongos.Lid.VipOrder.Get(), OrderType: vipordermod.OrderTypeCoin, UserId: userId, CoinCfgId: packageId, // 兼容历史字段,存购买套餐ID Coin: coinAmount, BaseCoin: pkg.BaseCoin, GiftCoin: pkg.GiftCoin, Amount: pkg.Price, PayMode: payMode, TradeNo: tradeNo, Oid: payInfo.Oid, Status: pubdef.VipOrderPending, PayUrl: payInfo.PayUrl, PayUrlMode: payInfo.PayUrlMode, PayChannel: payInfo.PayChannel, PayRate: payInfo.PayRate, IPAddr: ip, SysType: sysType, DistrictCode: strings.TrimSpace(districtCode), CreatedAt: now, UpdatedAt: now, } if serr = vipordermod.InsertOneVipOrder(ctx, order); serr != nil { log.Error("coinser:CreateCoinOrder InsertOneVipOrder failed", log.Any("tradeNo", tradeNo), log.E(serr)) return nil, serr } return &BuyCoinResp{ TradeNo: tradeNo, PayUrl: payInfo.PayUrl, PayUrlMode: payInfo.PayUrlMode, IsOpenNewBrowser: true, }, nil } // GetCoinOrderHistory 查询用户金币购买记录 func GetCoinOrderHistory(ctx context.Context, userId int64, page, pageSize int64) (vipordermod.VipOrderList, int64, *srvdef.SrvErr) { filter := bson.M{ vipordermod.FN.VipOrder.UserId: userId, vipordermod.FN.VipOrder.OrderType: vipordermod.OrderTypeCoin, } total, serr := vipordermod.CountVipOrder(ctx, filter) if serr != nil { return nil, 0, serr } skip := (page - 1) * pageSize opts := options.Find(). SetSort(bson.M{vipordermod.FN.VipOrder.CreatedAt: -1}). SetSkip(skip). SetLimit(pageSize) list, serr := vipordermod.FindManyVipOrder(ctx, filter, opts) return list, total, serr }