package statcenterctl import ( "fmt" "math" "net/http" "strings" "91porn-server/common" "91porn-server/common/log" "91porn-server/common/stderr" "91porn-server/models/commod" "91porn-server/models/l/visitlogmod" "91porn-server/models/v/prdcthsomod" "91porn-server/models/v/productmod" "91porn-server/models/v/productposimod" "91porn-server/models/v/proxymod" "91porn-server/models/v/rchgordmod" "91porn-server/models/v/txnmod" "91porn-server/models/v/usermod" "github.com/gin-gonic/gin" "github.com/shopspring/decimal" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" ) // @Tags 数据通过 // @Summary 拉去数据同步信息 // @Description 返回用户收益详情 // @Accept json // @Produce json // @Param param body StatcenterSyncReq true "参数" // @Success 200 {string} string "成功" // @Success 400 {string} string "失败" // @Router /statcenter/sync [POST] func StatcenterSyncList(ctx *gin.Context) { var request StatcenterSyncReq var err error if err = ctx.ShouldBind(&request); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, err.Error()) return } var resp StatcenterSyncResp resp.Job = request.Job resp.Code = 200 // 根据记录查询数据库 switch request.Job { case string(commod.USER_ACCE): fmt.Println(request.Job) // 查询 resp.AccessList, err = UserAccessList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.USER_REG): fmt.Println(request.Job) resp.RegisterList, err = UserRegisterList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.USER_BINDING): fmt.Println(request.Job) resp.BindingList, err = UserBindingList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.USER_INVITE): fmt.Println(request.Job) resp.InviteList, err = UserInviterList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.ConsumeRecordJob): fmt.Println(request.Job) resp.ConsumeList, err = ConsumeRecordList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.USER_RECH): fmt.Println(request.Job) resp.RechargeList, err = UserRechargeList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.USER_RECH_ALL): fmt.Println(request.Job) resp.AllRechargeList, err = UserAllOrderList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.CardSellJob): fmt.Println(request.Job) resp.CardSellList, err = CardSellList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } case string(commod.AiSellJob): fmt.Println(request.Job) resp.AiSellList, err = AiSellList(request) if err != nil { resp.Code = 502 resp.Msg = err.Error() } default: resp.Code = 501 resp.Msg = "job is error" } ctx.JSON(http.StatusOK, resp) } // AiSellList AI销售流水同步 func AiSellList(req StatcenterSyncReq) (list []commod.AiSellMsg, err error) { log.Debug("AiSellList job start running") typeInts := []txnmod.TransType{txnmod.AiChangeFaceImgDebitGold, txnmod.AiImageToVideoDebitGold, txnmod.AiChangefaceDebitGold, txnmod.AiUndressDebitGold, txnmod.AiTextToImageDebitGold, txnmod.AiMateChat} startID, err := primitive.ObjectIDFromHex(req.PlatformId) if err != nil { return } filter := bson.M{"tranTypeInt": bson.M{"$in": typeInts}, "_id": bson.M{"$gt": startID}} opts := options.Find().SetLimit(req.MaxSize).SetSort(bson.D{{Key: "_id", Value: 1}}) _, logs, err := txnmod.FindTransactionLogs(filter, opts) if err != nil { return } list = make([]commod.AiSellMsg, len(logs)) if len(list) == 0 { log.Debug("AiSellList job len(list) == 0") return } for i, l := range logs { amount := l.Amount if amount < 0 { amount = -amount } msg := commod.AiSellMsg{ AppID: commod.KFK_APPID, UID: l.UID, UniqID: l.ID.Hex(), Amount: amount, SysType: l.SysType, CurrencyType: "pay", TranCreatedAt: l.CreatedAt, IsRepurchase: l.IsRepurchase, } switch txnmod.TransType(l.TranTypeInt) { case txnmod.AiChangeFaceImgDebitGold: msg.TranType = "img_faceswap" case txnmod.AiImageToVideoDebitGold: msg.TranType = "img_to_vid" case txnmod.AiChangefaceDebitGold: msg.TranType = "vid_faceswap" case txnmod.AiUndressDebitGold: msg.TranType = "strip" case txnmod.AiTextToImageDebitGold: msg.TranType = "text_to_img" case txnmod.AiMateChat: msg.TranType = "mate" aiMatePoint := l.AiMatePoint if aiMatePoint < 0 { msg.Amount = int64(math.Round(math.Abs(aiMatePoint))) } } list[i] = msg } log.Debug("AiSellList job start finished") return } // UserAccessList 日活数据同步 func UserAccessList(request StatcenterSyncReq) ([]commod.UserAccessMsg, error) { visitList, err := visitlogmod.AccessSyncById(request.PlatformId, request.MaxSize) if err != nil { log.Error("UserAccessList AccessSyncById ", log.E(err)) return nil, err } accessList := make([]commod.UserAccessMsg, len(visitList)) for i, visitInfo := range visitList { // iOS 开头的 devType(如 "iOS:25.3.0")统一规范化为 "ios" if strings.HasPrefix(strings.ToLower(visitInfo.DevType), "ios") { visitInfo.DevType = "ios" } accessList[i] = commod.UserAccessMsg{ UserId: visitInfo.UID, AppId: commod.KFK_APPID, SysType: visitInfo.SysType, DevType: visitInfo.DevType, IP: visitInfo.IP, Version: visitInfo.Ver, DevID: visitInfo.DevID, VisitAt: visitInfo.CreatedAt, PlatformId: visitInfo.ID.Hex(), IsDirect: visitInfo.IsDirect, DistrictCode: visitInfo.DistrictCode, RegisterTime: visitInfo.RegisterTime, IsDeduction: visitInfo.IsDeduction, } } return accessList, nil } // UserRegisterList 注册数据同步 func UserRegisterList(request StatcenterSyncReq) ([]commod.UserRegisterMsg, error) { userList, err := usermod.StatcenterSyncList(request.UserId, request.MaxSize) if err != nil { log.Error("UserRegisterList AccessSyncById ", log.E(err)) return nil, err } registerList := make([]commod.UserRegisterMsg, len(userList)) for i, userInfo := range userList { registerList[i] = commod.UserRegisterMsg{ UserId: userInfo.UID, AppId: commod.KFK_APPID, SysType: userInfo.SysType, DevType: userInfo.DevType, Mobile: userInfo.Mobile, Name: userInfo.Name, IP: userInfo.RegisterIP, IsDirect: userInfo.IsDirect, DistrictCode: userInfo.DistrictCode, PromSeqe: userInfo.PromSeqe, PUC: userInfo.PUC, PromCode: userInfo.PromCode, RegisterTime: userInfo.CreatedAt, PlatformId: userInfo.ID.Hex(), } } return registerList, nil } // UserRegisterList 注册数据同步 func UserInviterList(request StatcenterSyncReq) ([]commod.UserInviteBindMsg, error) { data, err := proxymod.StatCenterSyncInviteList(request.SuccessTime, request.MaxSize) if err != nil { log.Error("UserInviteList InviteSyncByInviteTime ", log.E(err)) return nil, err } res := make([]commod.UserInviteBindMsg, len(data)) for i, v := range data { res[i] = commod.UserInviteBindMsg{ UserId: v.UID, AppId: commod.KFK_APPID, ParentPromCode: v.InviteCode, InviteTime: v.InviteTime, } } return res, nil } // UserBindingList 绑定数据同步 func UserBindingList(request StatcenterSyncReq) ([]commod.UserBindingMsg, error) { userList, err := usermod.StatcenterSyncBindUserList(request.SuccessTime, request.MaxSize) if err != nil { log.Error("UserBindingList AccessSyncById ", log.E(err)) return nil, err } bindingList := make([]commod.UserBindingMsg, len(userList)) for i, userInfo := range userList { bindingList[i] = commod.UserBindingMsg{ UserId: userInfo.UID, AppId: commod.KFK_APPID, SysType: userInfo.SysType, DevType: userInfo.DevType, Mobile: userInfo.Mobile, PlatformId: userInfo.ID.Hex(), BindingTime: userInfo.MobileBindAt, } } return bindingList, nil } // ConsumeRecordList 消费流水同步 func ConsumeRecordList(request StatcenterSyncReq) ([]commod.ConsumeRecordMsg, error) { var typeInts = []txnmod.TransType{txnmod.PayVIP, txnmod.MeetingCard, txnmod.BuyVIP, txnmod.VideoFreeCard, txnmod.VideoDiscount, txnmod.Other, txnmod.LouFeng, txnmod.LouFengMianFei, txnmod.BookLoufeng, txnmod.CoinMonthCard} objId, err := primitive.ObjectIDFromHex(request.PlatformId) if err != nil { return nil, err } f := bson.M{"tranTypeInt": bson.M{"$in": typeInts}, "_id": bson.M{"$gt": objId}} opt := options.Find().SetLimit(request.MaxSize).SetSort(bson.D{{Key: "_id", Value: 1}}) _, txns, err := txnmod.FindTransactionLogs(f, opt) if err != nil { log.Error("UserBindingList AccessSyncById ", log.E(err)) return nil, err } list := make([]commod.ConsumeRecordMsg, len(txns)) for i, v := range txns { temp := commod.ConsumeRecordMsg{ AppID: commod.KFK_APPID, UID: v.UID, CurrencyType: v.CurrencyType, Amount: decimal.NewFromFloat(v.ActualAmount), Uniq: v.ID.Hex(), CreatedAt: v.CreatedAt, } switch txnmod.TransType(v.TranTypeInt) { case txnmod.PayVIP: temp.Type = commod.StatVipCard case txnmod.LouFeng, txnmod.LouFengMianFei, txnmod.BookLoufeng: temp.Type = commod.StatLouFeng case txnmod.Other, txnmod.MeetingCard: temp.Type = commod.StatValueAddSer } if v.CurrencyType == commod.CurrencyTypeCash { temp.Money = decimal.NewFromFloat(v.ActualAmount).Shift(-1) } list[i] = temp } return list, nil } // UserRechargeList 充值数据同步 func UserRechargeList(request StatcenterSyncReq) ([]commod.UserRechargeMsg, error) { rechargeOrders, err := rchgordmod.StatCenterSyncRecharge(request.SuccessTime, request.MaxSize) if err != nil { log.Error("UserRechargeList StatCenterSyncRecharge ", log.E(err)) return nil, err } data := make([]commod.UserRechargeMsg, len(rechargeOrders)) for i, v := range rechargeOrders { data[i] = commod.UserRechargeMsg{ UserId: v.UID, AppId: commod.KFK_APPID, PlatformId: v.ID.Hex(), SysType: v.DevType, DevType: v.DevType, ChannelName: v.Channel, CID: v.Channel, Type: v.RechargeType, OrderId: v.ID.Hex(), OID: v.OID, Money: v.Money, PayMoney: v.PayMoney, Status: v.Status, Rate: "12", SuccessAt: v.SuccessAt, ProductType: v.ProductType, ChanShareMod: v.ChanShareMod, } } return data, nil } // UserAllOrderList 用户订单同步 func UserAllOrderList(request StatcenterSyncReq) ([]commod.UserRechargeMsg, error) { rechargeOrders, err := rchgordmod.StatCenterSyncOrder(request.SuccessTime, request.MaxSize) if err != nil { log.Error("UserRechargeList StatCenterSyncRecharge ", log.E(err)) return nil, err } data := make([]commod.UserRechargeMsg, len(rechargeOrders)) for i, v := range rechargeOrders { data[i] = commod.UserRechargeMsg{ UserId: v.UID, AppId: commod.KFK_APPID, PlatformId: v.ID.Hex(), SysType: v.DevType, DevType: v.DevType, ChannelName: v.Channel, CID: v.Channel, Type: v.RechargeType, OrderId: v.ID.Hex(), OID: v.OID, Money: v.Money, PayMoney: v.PayMoney, Status: v.Status, Rate: "12", SuccessAt: v.CreatedAt, ProductType: v.ProductType, ChanShareMod: v.ChanShareMod, } } return data, nil } // CardSellList 会员卡特权卡销售流水同步 func CardSellList(req StatcenterSyncReq) (list []commod.CardSellMsg, err error) { log.Debug("CardSellList job start running") typeInts := []txnmod.TransType{txnmod.MeetingCard, txnmod.LouFengDiscount, txnmod.LouFengMianFei, txnmod.BuyVIP, txnmod.VideoDiscount, txnmod.VideoFreeCard, txnmod.PayVIP, txnmod.BuyAdvanceVIP, txnmod.BuyBalanceVIP, txnmod.BuyGameAdvanceVIP, txnmod.BuyWhoringCard, } startID, err := primitive.ObjectIDFromHex(req.PlatformId) if err != nil { return } filter := bson.M{"tranTypeInt": bson.M{"$in": typeInts}, "_id": bson.M{"$gt": startID}} opts := options.Find().SetLimit(req.MaxSize).SetSort(bson.D{{Key: "_id", Value: 1}}) _, logs, err := txnmod.FindTransactionLogs(filter, opts) if err != nil { return } logsLen := len(logs) productIDs := make([]primitive.ObjectID, 0, logsLen) historyIDs := make([]primitive.ObjectID, 0, logsLen) for _, l := range logs { if l.ProductID != nil && *l.ProductID != "" { productID, err := primitive.ObjectIDFromHex(*l.ProductID) if err != nil { log.Error("primitive.ObjectIDFromHex", log.Any("productID", *l.ProductID), log.E(err)) continue } productIDs = append(productIDs, productID) } else if !l.TransNo.IsZero() { historyIDs = append(historyIDs, l.TransNo) } } historyMap, err := getProductsByHistories(historyIDs) if err != nil { return } productMap, err := getProductPositions(productIDs) if err != nil { return } list = make([]commod.CardSellMsg, len(logs)) for i, l := range logs { amount := l.Amount if amount < 0 { amount = -amount } msg := commod.CardSellMsg{ AppID: commod.KFK_APPID, UID: l.UID, UniqID: l.ID.Hex(), Amount: amount, TranTypeInt: l.TranTypeInt, TranType: l.TranType, SysType: l.SysType, CurrencyType: l.CurrencyType, TranCreatedAt: l.CreatedAt, } if !l.TransNo.IsZero() { msg.Product = historyMap[l.TransNo] } else if l.ProductID != nil && *l.ProductID != "" { msg.Product = productMap[*l.ProductID] } else { msg.Product = commod.Product{ ProductType: txnmod.TranType2ProductType[txnmod.TransType(l.TranTypeInt)], Position: detectProductPosition(l), } } list[i] = msg } log.Debug("CardSellList job start finished") return } func getProductsByHistories(historyIDs []primitive.ObjectID) (products map[primitive.ObjectID]commod.Product, err error) { _, histories, err := prdcthsomod.FindProductHistorys(bson.M{"_id": bson.M{"$in": historyIDs}}, options.Find()) if err != nil { return } historyMap := make(map[primitive.ObjectID]prdcthsomod.ProductHistory) for _, history := range histories { historyMap[history.ID] = *history } productIDs := make([]primitive.ObjectID, len(histories)) for i, h := range histories { productIDs[i] = h.ProductID } productMap, err := productmod.ListByIDsMap(productIDs) if err != nil { return } posIDs := make([]primitive.ObjectID, 0, len(productMap)) for _, p := range productMap { if p.Position != "" { posID, err := primitive.ObjectIDFromHex(p.Position) if err != nil { log.Error("primitive.ObjectIDFromHex", log.Any("productID", p.ID.Hex()), log.Any("position", p.Position), log.E(err)) continue } posIDs = append(posIDs, posID) } } positions, err := productposimod.FindByIDs(posIDs) if err != nil { log.Error("productposimod.FindByIDs", log.Any("positionIDs", posIDs), log.E(err)) } positionMap := make(map[string]productposimod.ProductPosition) for _, p := range positions { positionMap[p.ID.Hex()] = p } products = make(map[primitive.ObjectID]commod.Product) for hID, h := range historyMap { product := commod.Product{Position: commod.Position{}} pro, ok := productMap[h.ProductID] if ok { product.ID = pro.ID.Hex() product.Name = pro.Name product.DiscountedPrice = pro.DiscountedPrice product.ProductType = pro.ProductType pos, ok := positionMap[pro.Position] if ok { product.Position.ID = pos.ID product.Position.Name = pos.Name } } products[hID] = product } return } func getProductPositions(productIDs []primitive.ObjectID) (products map[string]commod.Product, err error) { productList, err := productmod.ListToIDs(productIDs, "") if err != nil { return } positionIDs := make([]primitive.ObjectID, 0, len(productList)) for _, p := range productList { if p.Position != "" { positionID, err := primitive.ObjectIDFromHex(p.Position) if err != nil { log.Error("primitive.ObjectIDFromHex", log.Any("position", p.Position), log.E(err)) continue } positionIDs = append(positionIDs, positionID) } } positionList, err := productposimod.FindByIDs(positionIDs) if err != nil { return } positionMap := make(map[string]productposimod.ProductPosition) for _, p := range positionList { positionMap[p.ID.Hex()] = p } products = make(map[string]commod.Product) for _, p := range productList { pos := positionMap[p.Position] position := commod.Position{ ID: pos.ID, Name: pos.Name, } products[p.ID.Hex()] = commod.Product{ ID: p.ID.Hex(), Name: p.Name, DiscountedPrice: p.DiscountedPrice, ProductType: p.ProductType, Position: position, } } return } func detectProductPosition(txnLog *txnmod.TransactionLog) (position commod.Position) { positionMap, err := productposimod.FindAllNameMap() if err != nil { return } pos := productposimod.ProductPosition{} if txnLog != nil { switch txnLog.TranTypeInt { case int64(txnmod.BuyVIP), int64(txnmod.PayVIP): pos = positionMap["会员卡"] case int64(txnmod.MeetingCard), int64(txnmod.LouFengDiscount), int64(txnmod.LouFengMianFei), int64(txnmod.Other), int64(txnmod.VideoDiscount), int64(txnmod.VideoFreeCard): pos = positionMap["特权卡"] default: // 默认特权卡 pos = positionMap["特权卡"] } } position.ID = pos.ID position.Name = pos.Name return }