#!/usr/bin/python # -*- coding: utf-8 -*- # @todo: 服务器LTV分析, 仅针对单 serverID 统计,不管合服后 import CommFunc import ConfigParser import CTGOKSort import mylog import logging cfg = ConfigParser.ConfigParser() cfg.read("../../InterfaceConfig.php") ServerPath = cfg.get("ServerInfo", "ServerPath") # 需要处理的流向名及顺序列表 DRNameList = ["FirstLogin", "CTGOK"] def queryServerLTVInfo(argvDict): logging.info("queryServerLTVInfo %s" % str(argvDict)) if "serverID" not in argvDict: print "not serverID" return argvDict["OnlyServerID"] = argvDict["serverID"] # 只查本服 LVTVPayOrderType = int(CommFunc.getSPConfig(argvDict, "Config", "LVTVPayOrderType", "1")) startDate = argvDict.get("startDate", "") endDate = argvDict.get("endDate", "") eventType = argvDict.get("eventType", "") ltvDayList = eval(argvDict.get("ltvDayList", "[1, 2, 3, 4, 5, 6, 7]")) # LTV 天(当日) ltvTotalDayList = eval(argvDict.get("ltvTotalDayList", "[7, 14, 15, 21, 30, 45, 60, 75, 90]")) # LTV 天(汇总) maxDay = max(max(ltvDayList), max(ltvTotalDayList)) createRoleEndDate = argvDict.get("createRoleEndDate", "") if not createRoleEndDate: createRoleEndDate = endDate if endDate else startDate argvDict["createRoleEndDate"] = createRoleEndDate # 创角结束天 endDateTime = CommFunc.getDiffDaysDate(maxDay - 1, CommFunc.strToDatetime(createRoleEndDate)) endDate = str(endDateTime)[:10] argvDict["endDate"] = endDate logging.info(" upd endDate=%s" % endDate) logging.info(" upd createRoleEndDate=%s" % createRoleEndDate) createDateAccIDInfo = {} # {"首登日期":["账号", ...], ...} ctgDateAccIDInfo = {} # {"充值日期":{"账号":orderValue, ...}, ...} # 查询中心备份的 if CommFunc.isQueryCenterbak(argvDict): queryCenterBak(startDate, endDate, LVTVPayOrderType, argvDict) return needQueryCenterbak = CommFunc.loopMainServerDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc, parseLineFunc, createDateAccIDInfo, ctgDateAccIDInfo, LVTVPayOrderType, argvDict, drNameList=DRNameList) logging.info("needQueryCenterbak %s" % needQueryCenterbak) if needQueryCenterbak: bakDataInfo = CommFunc.queryBackupCenterDR(cfg, argvDict) logging.info("queryBackupCenterDR OK") if bakDataInfo == None: return createDateAccIDInfoBak, ctgDateAccIDInfoBak = bakDataInfo # 合并数据 for bakDate, firstLoginAccIDList in createDateAccIDInfoBak.items(): if bakDate not in createDateAccIDInfo: createDateAccIDInfo[bakDate] = firstLoginAccIDList else: createDateAccIDInfo[bakDate] = list(set(firstLoginAccIDList + createDateAccIDInfo[bakDate])) for bakDate, accIDCtgInfoBak in ctgDateAccIDInfoBak.items(): if bakDate not in ctgDateAccIDInfo: ctgDateAccIDInfo[bakDate] = accIDCtgInfoBak else: accIDCtgInfo = ctgDateAccIDInfo[bakDate] for accID, orderValue in accIDCtgInfoBak.items(): accIDCtgInfo[accID] = accIDCtgInfo.get(accID, 0) + orderValue logging.info("query all data OK") dateStrList = createDateAccIDInfo.keys() dateStrList.sort() ltvDrList = [] ltvStyleInfo = {} ltvTDList = ["DateStr", "FirstLoginCount"] for ltvDay in ltvDayList: ltvTDList.append(ltvDay) ltvStyleInfo[ltvDay] = {"align":"left", "title":_(u"第%s日LTV") % ltvDay} for ltvTotalDay in ltvTotalDayList: key = "%sTotal" % ltvTotalDay ltvTDList.append(key) ltvStyleInfo[key] = {"align":"left", "title":_(u"%s日总LTV") % ltvTotalDay} # 最后总LTV LTVTotalDayTDKey = "LTVTotalDay" MaxDayCoinTotalKey = "MaxDayCoinTotal" ltvTDList.extend([LTVTotalDayTDKey, MaxDayCoinTotalKey]) ltvStyleInfo[LTVTotalDayTDKey] = {"align":"left", "title":_(u"时段总LTV(天 )")} ltvStyleInfo[MaxDayCoinTotalKey] = {"align":"left", "title":_(u"时段总充值")} coinRate = CommFunc.getPayOrderCoinRate(LVTVPayOrderType) if LVTVPayOrderType in CTGOKSort.PayByMoneyOrderTypeList: coinRate = 1.0 firstLoginAccIDCountTotal, allAccIDCoinTotal = 0, 0 curDateTime = CommFunc.getCurrentTime() for dateStr in dateStrList: dateObj = CommFunc.strToDatetime(dateStr) maxDateObj = CommFunc.getDiffDaysDate(maxDay - 1, CommFunc.strToDatetime(dateStr)) # 该创角日期最大需要统计到的充值日期 if curDateTime < maxDateObj: passDays = (curDateTime - dateObj).days + 1 else: passDays = (maxDateObj - dateObj).days + 1 firstLoginAccIDList = createDateAccIDInfo[dateStr] firstLoginCount = len(firstLoginAccIDList) firstLoginAccIDCountTotal += firstLoginCount # ltv ltvDrInfo = {"DateStr":dateStr, "FirstLoginCount":firstLoginCount} dayCtgInfo = {} # 转化为天汇总 for ltvDate, accIDCtgInfo in ctgDateAccIDInfo.items(): ltvDateObj = CommFunc.strToDatetime(ltvDate) if not ltvDateObj: continue ltvDay = (ltvDateObj - dateObj).days + 1 # 0即第一天,所以 + 1 if ltvDay > maxDay: # 超过该创角天最大需要统计的ltv天,不处理 continue ctgCoin = 0 for accID, orderValue in accIDCtgInfo.items(): if accID in firstLoginAccIDList: ctgCoin += orderValue if ctgCoin > 0: dayCtgInfo[ltvDay] = ctgCoin # ltv - 当日 for ltvDay in ltvDayList: if ltvDay not in dayCtgInfo: continue ctgCoin = dayCtgInfo[ltvDay] ltv = (ctgCoin / float(firstLoginCount) / coinRate) if firstLoginCount > 0 else 0 ltvDrInfo[ltvDay] = CommFunc.roundInt(ltv, 2) # ltv - 汇总 for ltvTotalDay in ltvTotalDayList: if ltvTotalDay > passDays: # 未到的汇总天不显示 continue ctgCoinTotal = 0 for ltvDay in range(1, ltvTotalDay + 1): ctgCoinTotal += dayCtgInfo.get(ltvDay, 0) if not ctgCoinTotal: continue ltvTotal = (ctgCoinTotal / float(firstLoginCount) / coinRate) if firstLoginCount > 0 else 0 key = "%sTotal" % ltvTotalDay ltvDrInfo[key] = CommFunc.roundInt(ltvTotal, 2) maxDayCoinTotal = sum(dayCtgInfo.values()) allAccIDCoinTotal += maxDayCoinTotal if maxDayCoinTotal > 0: maxDayLTVTotal = (maxDayCoinTotal / float(firstLoginCount) / coinRate) if firstLoginCount > 0 else 0 ltvDrInfo[LTVTotalDayTDKey] = "%s (%s%s)" % (CommFunc.roundInt(maxDayLTVTotal, 2), passDays, _(u"天")) ltvDrInfo[MaxDayCoinTotalKey] = CommFunc.roundInt(maxDayCoinTotal / coinRate, 2) if firstLoginCount: ltvDrList.append(ltvDrInfo) orderTypeName = CommFunc.getPayOrderTypeName(LVTVPayOrderType) printStr = "

%s

" % _(u"LTV分析") if startDate: printStr += "%s: %s
" % (_(u"查询统计创角开始日期"), startDate) if createRoleEndDate: printStr += "%s: %s
" % (_(u"查询统计创角结束日期"), createRoleEndDate) printStr += "%s: %s
" % (_(u"查询总计 LTV天数列表"), ltvTotalDayList) # 表格输出 printStr += "
【LTV】 %s: %s %s: %s %s
" % (_(u"首登总人数"), firstLoginAccIDCountTotal, _(u"总充值"), str(CommFunc.roundInt(allAccIDCoinTotal / coinRate, 2)), orderTypeName) ltvStyleInfo.update({"DateStr":{"title":_(u"日期")}, "FirstLoginCount":{"title":_(u"首登人数")}, }) printStr += CommFunc.editTableHtml(ltvDrList, ltvTDList, styleInfo=ltvStyleInfo, printCount=False) printStr += "
%s" \ % (eventType, startDate, createRoleEndDate, ltvDayList, ltvTotalDayList, _(u"查看其他")) logging.info("show OK") # 只会返回最后一个print的内容 print printStr return def queryCenterBak(startDate, endDate, LVTVPayOrderType, argvDict): createDateAccIDInfoBak, ctgDateAccIDInfoBak = {}, {} if not CommFunc.loopCenterbakRarDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc, parseLineFunc, createDateAccIDInfoBak, ctgDateAccIDInfoBak, LVTVPayOrderType, argvDict, drNameList=DRNameList): return return CommFunc.queryBackupCenterOK([createDateAccIDInfoBak, ctgDateAccIDInfoBak]) def checkDrFileNeedParseFunc(drFileName, *parseArgs, **kv): ''' 检查流向是否需要处理 @param drFileName: 流向文件名 xxx_日期.txt @param *parseArgs: 自定义参数 @return: isNeed, checkNeedParseRetInfo ''' _, _, _, argvDict = parseArgs if drFileName.startswith("FirstLogin_"): dateStr = drFileName[:drFileName.rindex(".")].split("_")[1] createRoleStartDate = str(argvDict["startDate"]) createRoleEndDate = str(argvDict["createRoleEndDate"]) if dateStr < createRoleStartDate or dateStr > createRoleEndDate: return False, None return True, None def parseLineFunc(drName, dateStr, checkNeedParseRetInfo, line, *parseArgs, **kv): ''' 解析流向行内容 @param drName: 流向名 @param dateStr: 对应日期字符串 @param checkNeedParseRetInfo: checkDrFileNeedParseFunc 返回的内容 @param line: 本行内容 @param *parseArgs: 自定义参数 ''' createDateAccIDInfo, ctgDateAccIDInfo, LVTVPayOrderType, argvDict = parseArgs serverID = argvDict.get("serverID", "") sServerID = "@s%s" % serverID # 首登 if drName == "FirstLogin": if sServerID not in line: return drDict = eval(line) accID = drDict["AccID"] if not accID.endswith(sServerID): return if dateStr not in createDateAccIDInfo: createDateAccIDInfo[dateStr] = [] firstLoginAccIDList = createDateAccIDInfo[dateStr] if accID not in firstLoginAccIDList: firstLoginAccIDList.append(accID) # 统计充值 elif drName == "CTGOK": if sServerID not in line: return drDict = eval(line) accID = drDict["AccID"] if not accID.endswith(sServerID): return payOrderType = drDict.get("payOrderType", CTGOKSort.DefaultOrderType) if payOrderType != LVTVPayOrderType: return if payOrderType in CTGOKSort.PayByMoneyOrderTypeList: orderValue = drDict["orderMoneyValue"] else: if not CTGOKSort.IsRealCTG(drDict): return orderValue = drDict["orderCoin"] if dateStr not in ctgDateAccIDInfo: ctgDateAccIDInfo[dateStr] = {} accIDCtgInfo = ctgDateAccIDInfo[dateStr] accIDCtgInfo[accID] = accIDCtgInfo.get(accID, 0) + orderValue return def main(): CommFunc.setdefaultencoding() argvDict = CommFunc.parse_args() mylog.InitMyLog(argvDict.get("eventType", "")) CommFunc.gettextInstall(argvDict.get("lang", "")) queryServerLTVInfo(argvDict) return if __name__ == "__main__": try: main() except: CommFunc.printExceptionError()