hch
2019-01-23 960e7c59624a78669b5f2e741a83466202af3131
5735 【后端】【1.5】仙玉返还
3个文件已修改
17个文件已添加
7515 ■■■■■ 已修改文件
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_AllDoubleBill.py 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QDFLDoubleBill.py 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerQuDaoDoubleBill.py 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AllDoubleBill.py 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_QDFLDoubleBill.py 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/Bill.txt 681 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/DoubleBillDB.py 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/DoubleBillTool.py 457 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/bottle.py 4403 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/lib/CommFunc.py 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/lib/DBController.py 516 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/lib/ReadConfig.py 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/lib/TimeRotatingPathFileHandler.py 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/lib/__init__.py 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/lib/mylog.py 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/main.py 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tool/WebCenter/DoubleBill/webapp.py 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_AllDoubleBill.py
New file
@@ -0,0 +1,41 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 渠道测试返利 - 缓存所有未领取数据
#
# @author: Alee
# @date 2019-1-23 下午02:06:50
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
#导入
import GMCommon
import ChConfig
import GameWorld
import GMShell
import PyGameData
#---------------------------------------------------------------------
## 执行逻辑
#  @param curPlayer 当前玩家
#  @param gmCmdDict: 命令字典
#  @return None
#  @remarks 函数详细说明.
def OnExec(orderId, gmCmdDict):
    billInfo = gmCmdDict.get('tomap', '')
    if not billInfo:
        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_ParamErr)
        return
    msgInfo = str([billInfo])
    GameWorld.DebugLog("GMT_AllDoubleBill : %s"%msgInfo)
    GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, 10010, "AllDoubleBill", msgInfo, len(msgInfo))
    GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_Success)
    return
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QDFLDoubleBill.py
New file
@@ -0,0 +1,67 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 渠道测试返利
#
# @author: Alee
# @date 2019-1-23 下午02:06:50
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
#导入
import GMCommon
import ChConfig
import GameWorld
import GMShell
import PyGameData
#---------------------------------------------------------------------
## 执行逻辑
#  @param curPlayer 当前玩家
#  @param gmCmdDict: 命令字典
#  @return None
#  @remarks 函数详细说明.
def OnExec(orderId, gmCmdDict):
    GameWorld.Log("%s"%gmCmdDict)
    accID = str(gmCmdDict.get('AccID', ''))
    if not accID:
        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_ParamErr)
        return
    gold = int(gmCmdDict.get('GoldState', 0))
    if not gold:
        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_ParamErr)
        return
    playerManager = GameWorld.GetPlayerManager()
    queryType = ChConfig.queryType_sqtPlayerByAccID
    tagPlayer = playerManager.FindPlayerByAccID(accID)
    if not tagPlayer:
        # 玩家不在线,先记录,等玩家上线后处理
        GameWorld.Log("玩家离线,暂存渠道测试返利 %s, 仙玉%s"%(accID, gold))
        GMShell.AddOfflinePlayerGMTInfo(orderId, queryType, accID, gmCmdDict)
        return
    GameWorld.Log("发放渠道测试返利 %s, 仙玉%s"%(accID, gold))
    GMCommon.GMTool_MapServer_Query(queryType, orderId, accID, gmCmdDict, 'QDFLDoubleBill', [gold], True)
    return
def OnOfflineCTGInfo(curPlayer, tagMapID, gmCmdDict):
    gold = int(gmCmdDict.get('GoldState', 0))
    cmdStr = str([gold])
    GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, curPlayer.GetPlayerID(), tagMapID, 'QDFLDoubleBill',
                                            cmdStr, len(cmdStr), curPlayer.GetRouteServerIndex())
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3322,6 +3322,8 @@
# 玩家字典key定义规则, key的长度不能超过29个字节, 注意尽量避免命名重复
# 新增参数TYPE 用于字典分类,默认0
Def_QuDao_DoubleBillGold = "qddbGold"   # 渠道返利的仙玉
Def_QuDao_DoubleBillCount = "qddbCount"   # 渠道返利的仙玉领取次数 日期+次数组合数字
Def_PDict_GeTuiSet = "GetuiSet"     # 推送提醒的设置
Def_PDict_NoGeTuiTime = "NoGetuiTime"     # 推送提醒免打扰时间,将字符串组合数字
Def_PlayerKey_TJGNPC = "TJGNPC"     # 脱机挂机NPC点
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -111,6 +111,7 @@
import PlayerGeTui
import PlayerDogz
import PlayerCoat
import PlayerQuDaoDoubleBill
import datetime
import time
@@ -741,6 +742,7 @@
    # 如果被禁言的,上线同步前端
    if curPlayer.GetGMForbidenTalk():
        curPlayer.SendPropertyRefresh(ShareDefine.CDBPlayerRefresh_ForbidenTalk, curPlayer.GetGMForbidenTalk(), False)
    return
@@ -1556,6 +1558,8 @@
    
    #EndLoadMap需放在最后
    curPlayer.EndLoadMap()
    # 渠道返利
    PlayerQuDaoDoubleBill.OnMapQDDoubleBill(curPlayer)
    return True
## 切换地图同步一次PK模式
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerQuDaoDoubleBill.py
New file
@@ -0,0 +1,142 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 渠道删档测试充值双倍返利
#
# @author: Alee
# @date 2019-1-22 下午08:22:54
# @version 1.0
#
# @note: #总共681条, 含平台['kupai', 'uc', 'gionee', 'xiaomi', 'vivo', 'lenovo', 'meizu', 'yyb', 'oppo', 'qh360']
#
#---------------------------------------------------------------------
import PyGameData
import ChConfig
import GameWorld
import ReadChConfig
import datetime
import IPY_GameWorld
import PlayerControl
import math
Def_Qudao_DoubleBill = ['kupai', 'uc', 'gionee', 'xiaomi', 'vivo', 'lenovo', 'meizu', 'yyb', 'oppo', 'qh360']
def OnMapQDDoubleBill(curPlayer):
    try:
        if GameWorld.IsCrossServer():
            return
        dbBillDict = ReadChConfig.GetEvalChConfig("DoubleBillConfig")
        if not dbBillDict["IsOpen"]:
            return
        OnFirstQDDoubleBillQuery(curPlayer)
        OnOtherQuDaoDoubleBill(curPlayer)
    except Exception, e:
        GameWorld.Log("OnMapQDDoubleBill 异常 %s-%s"%(curPlayer.GetID(), e))
    return
# 跨服不处理
# 1. 第一次为请求数据, 如果是神决宗则请求总数据
# 2. 后续切换地图,判断是否隔天领取
def OnFirstQDDoubleBillQuery(curPlayer):
    # 1 为无充值 2 为已领取 其他数值为具体返利总仙玉
    spID, accID = GetAccIDInfo(curPlayer.GetAccID())
    if spID not in Def_Qudao_DoubleBill:
        # 非渠道的
        return
    gold = curPlayer.NomalDictGetProperty(ChConfig.Def_QuDao_DoubleBillGold)
    if gold:
        # 已请求
        return
    # {spid:[accID...]}
    if PyGameData.g_Qudao_DoubleBill:
        # 有缓存但不在缓存中的
        if spID not in PyGameData.g_Qudao_DoubleBill:
            return
        if accID not in PyGameData.g_Qudao_DoubleBill[spID]:
            return
    centerUrl = "center.2460web.com"
    #centerUrl = "vm-mobilecom"
    # 先个人请求
    getUrl = "http://%s:53004/DoublieBill.php?AccID=%s"%(centerUrl, curPlayer.GetAccID())
    GameWorld.GetGameWorld().EventReport_EventReport("", "", "", "", 0, getUrl)
    if curPlayer.GetMapID() != 10010:
        return
    if not PyGameData.g_Qudao_DoubleBill:
        # 缓存请求
        getUrl = "http://%s:53004/QueryAllDoubleBill.php?ccccc=fanggongji"%centerUrl
        GameWorld.GetGameWorld().EventReport_EventReport("", "", "", "", 0, getUrl)
    return
# 后续天返回充值比例
def OnOtherQuDaoDoubleBill(curPlayer):
    # 1 为无充值 2 为已领取 其他数值为具体返利总仙玉
    spID, accID = GetAccIDInfo(curPlayer.GetAccID())
    if spID not in Def_Qudao_DoubleBill:
        # 非渠道的
        return
    gold = curPlayer.NomalDictGetProperty(ChConfig.Def_QuDao_DoubleBillGold)
    if gold <= 2:
        #无可领取的
        return
    CalcDoubleBillByDay(curPlayer)
    return
##获取平台账号 和 spid
def GetAccIDInfo(gameAccID):
    infoList = gameAccID.split('@')
    return infoList[1], infoList[0]
# 每日领取返利
def CalcDoubleBillByDay(curPlayer):
    gold = curPlayer.NomalDictGetProperty(ChConfig.Def_QuDao_DoubleBillGold)
    if gold <= 2:
        return
    dbBillDict = ReadChConfig.GetEvalChConfig("DoubleBillConfig")
    billDayRate = dbBillDict["BillDayRate"]
    # 记录返利次数: 时间+次数
    #count = curDay.year*100000 + curDay.month*1000 + curDay.day*10 + 0
    count = curPlayer.NomalDictGetProperty(ChConfig.Def_QuDao_DoubleBillCount)
    realCnt = count%10  # 已领取次数
    if realCnt >= len(billDayRate):
        return
    dateStr = "%d-%02d-%02d"%(count/100000, count%100000/1000, count%1000/10)
    startDate = GameWorld.GetDateTimeByStr(dateStr, ChConfig.TYPE_Time_Format_Day)
    curDay = datetime.datetime.today()
    theDay = curDay - startDate
    if theDay.days < realCnt:
        return
    giveGold = int(math.ceil(billDayRate[realCnt]/100.0*gold))
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_QuDao_DoubleBillCount, count+1)
    title = "系统邮件".decode("gbk").encode("utf8")
    content = "亲爱的道友:</r><Space=2>欢迎归来,感谢您在付费删档测试期间对我们的大力支持,给您奉上今日份回归大礼。您在付费删档测试期间的充值按照1元=20仙玉的比例共计返还7天,具体每日返还比例请您查看登录公告-删档回归有礼。请您留意每日返利邮件,祝您游戏愉快!".decode("gbk").encode("utf8")
    mailItemInfoList = []
    if realCnt == 0:
        mailItemInfoList = [[57, 1, 1]]
    # 发邮件
    PlayerControl.SendMail(title, content, 30, [curPlayer.GetPlayerID()], mailItemInfoList, gold=giveGold)
    GameWorld.Log("领取渠道返利 第%s次 仙玉=%s"%(realCnt+1, giveGold))
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AllDoubleBill.py
New file
@@ -0,0 +1,56 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 渠道返利发放 - 缓存所有未领取数据
#
# @author: Alee
# @date 2019-1-23 下午02:38:15
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
#导入
import GameWorld
import ChConfig
import PyGameData
import json
#---------------------------------------------------------------------
#全局变量
#---------------------------------------------------------------------
#---------------------------------------------------------------------
#逻辑实现
## 请求逻辑
#  @param query_Type 请求类型
#  @param query_ID 玩家ID
#  @param packCMDList 发包命令
#  @param tick 当前时间
#  @return "True" or "False" or ""
#  @remarks 函数详细说明.
def DoLogic(query_Type, query_ID, packCMDList, tick):
    PyGameData.g_Qudao_DoubleBill = json.loads(packCMDList[0])
    return
#---------------------------------------------------------------------
#执行结果
## 执行结果
#  @param curPlayer 发出请求的玩家
#  @param callFunName 功能名称
#  @param funResult 查询的结果
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def DoResult(curPlayer, callFunName, funResult, tick):
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_QDFLDoubleBill.py
New file
@@ -0,0 +1,74 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 渠道返利发放
#
# @author: Alee
# @date 2019-1-23 下午02:38:15
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
#导入
import PlayerControl
import GameWorld
import ChConfig
import datetime
import PlayerQuDaoDoubleBill
#---------------------------------------------------------------------
#全局变量
#---------------------------------------------------------------------
#---------------------------------------------------------------------
#逻辑实现
## 请求逻辑
#  @param query_Type 请求类型
#  @param query_ID 玩家ID
#  @param packCMDList 发包命令
#  @param tick 当前时间
#  @return "True" or "False" or ""
#  @remarks 函数详细说明.
def DoLogic(query_Type, query_ID, packCMDList, tick):
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(query_ID)
    if not curPlayer or curPlayer.IsEmpty():
        GameWorld.Log("渠道返利无法找到玩家:%s"%query_ID)
        return
    gold = packCMDList[0]
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_QuDao_DoubleBillGold, gold)
    if gold <= 2:
        return
    #第一天返利
    # 记录返利次数: 时间+次数
    curDay = datetime.datetime.today()
    count = curDay.year*100000 + curDay.month*1000 + curDay.day*10 + 0
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_QuDao_DoubleBillCount, count)
    GameWorld.Log("渠道返利发放 %s状态%s-%s"%(curPlayer.GetAccID(), count, gold))
    PlayerQuDaoDoubleBill.CalcDoubleBillByDay(curPlayer)
    return
#---------------------------------------------------------------------
#执行结果
## 执行结果
#  @param curPlayer 发出请求的玩家
#  @param callFunName 功能名称
#  @param funResult 查询的结果
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def DoResult(curPlayer, callFunName, funResult, tick):
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -91,3 +91,5 @@
g_ZhuXianBossPlayerHurtDict = {} #诛仙BOSS玩家伤害排行信息
g_zhuXianSkillAddPerDict = {} # 诛仙装备对技能增强缓存 {playerID:{技能TypeID:数值, ...}, ...}
g_zhuXianSkillReducePerDict = {} # 诛仙装备对技能减伤缓存 {playerID:{技能TypeID:数值, ...}, ...}
g_Qudao_DoubleBill = {} # 渠道删档充值返利
Tool/WebCenter/DoubleBill/Bill.txt
New file
@@ -0,0 +1,681 @@
vivo    82f3c8552db41cdf    200
oppo    152757925    2560
vivo    901b6ff023a7e85f    1000
uc    8478aeb43a0fd895ead516fce6ae5fc9_ali    200
xiaomi    2018122805304069    1600
vivo    f448a71e25919d70    17520
vivo    6abf2c86b779afdf    560
oppo    385315489    10000
yyb    o17pv02u-j2s3qw5tzidlhlaqznw    2760
yyb    7f4104d04495d84f4f0fa0cad6e6c50d    200
vivo    88b3782e503ac490    200
yyb    8d2bc948c3f9c3f05325c0e7bf148341    200
xiaomi    164521958    1000
oppo    233182438    200
uc    ee09ed16337641c446398cfb86ca571f_ali    200
vivo    7965450c5048a7d7    560
vivo    6b26eaf4049c55d1    33200
xiaomi    1088670742    1600
oppo    269564243    200
yyb    6664de5453447fb426126bb22d80ffd1    17280
vivo    e68d085b7e423f4b    5480
meizu    121807453    15960
oppo    215951423    16800
qh360    1394604735    200
oppo    201868216    200
oppo    352797806    200
oppo    101114083    200
vivo    5b6fac2c24679a41    200
oppo    262198164    4880
uc    8083a292c060cc3460bae6eceedebdf6_ali    200
oppo    383472023    200
xiaomi    2018122906312482    200
vivo    2f861d83776cda6b    200
oppo    259507706    200
vivo    7dc157390f54ad57    200
uc    ef4b94b30fb449c90a27a29a77ef82e0_ali    200
oppo    342957751    4520
vivo    66cdf6014fa3ee36    200
oppo    324231784    200
yyb    dc017ca1da4e7711f67bdecaa4b604db    200
vivo    3e0448c023347425    200
vivo    4f77b51d4c724ad9    200
vivo    07644a06017edf17    200
uc    eb3c49e72f9c126cec0b6574fe90f455_ali    200
vivo    79d96402ffe53254    200
oppo    76985310    200
uc    970105c9e401e48f833ec4c0ba9f239d_ali    200
vivo    7059030e984e5912    200
vivo    ac2b7e288e7f3534    1200
oppo    204838825    200
oppo    368200330    2120
qh360    2566131193    200
oppo    255242979    200
vivo    ad4abd123f99700e    560
oppo    306446247    200
qh360    278173472    200
uc    9f043b1cbb339816e05a37a9b255f347_ali    200
oppo    337754507    200
xiaomi    1021445156    1360
oppo    353606775    1200
oppo    122393461    2560
uc    ff6cf5061c5764582ab448f8366d701a_ali    3720
gionee    1eba5ec5d7df4d2296a970a034b7328f    200
uc    e0f7b9b141c24e67f37e6e7ed62d9c9b_ali    8400
oppo    368830565    200
oppo    298784489    2560
uc    67088abd72a594d4cb079e943c4c2a03_ali    200
qh360    679581332    200
uc    f91d2368493ea3d1b2cd19dbf2b9d847_ali    2200
oppo    277620850    200
vivo    06d64003ee7e3f27    7040
oppo    247462964    200
xiaomi    2018112706993619    4000
vivo    3ffa2d2ac585d4e2    1160
oppo    237195046    1200
yyb    o17pv04dpzkksjx6_cbvparvxo50    200
oppo    421049782    200
uc    3b4004a1e4ebd8d7296e966ea5895861_ali    200
oppo    271029371    7480
yyb    o17pv05heotfv_a__rhzs0lkw3mm    560
oppo    352591631    200
uc    52c2099bf1931bfc55aef218651ad2e3_ali    200
gionee    361e9c1b270442488154e081129d1181    200
oppo    289653761    200
oppo    147088965    1400
xiaomi    169491961    200
oppo    153459286    5480
vivo    3318439f39aaa145    13560
oppo    424197444    200
oppo    311257217    600
oppo    410517582    560
xiaomi    31158624    200
oppo    157807373    1000
xiaomi    2018122805045079    200
oppo    269780646    200
oppo    422495211    200
oppo    242212251    200
oppo    256050937    2920
xiaomi    1025597802    1000
yyb    o17pv07x2wubeze9gztzzqfieady    360
kupai    101095640    200
vivo    00bcc22a3d6da501    200
oppo    301773370    27320
yyb    o17pv0-oh8dy1omlrjftnht27xr8    200
xiaomi    1140040845    200
yyb    o17pv07rdxx2axyy5tlmdvkvtbwu    4160
uc    bde23ea768a06320d6a6d20ccd272912_ali    200
yyb    o17pv0_gmabxyt-svf9ou-kbg-qc    200
uc    f44fe6520af8bba522ea463f36b8a1cb_ali    200
oppo    387199301    200
oppo    390352287    200
oppo    121393085    200
oppo    238380022    200
oppo    200151032    800
uc    e496a67891ff78c88bf93df1be849bc3_ali    200
oppo    223083314    200
uc    91034274498011a33d9876767523692c_ali    200
vivo    54baf0c4e0b5848f    200
yyb    o17pv04zgixvunfljxqaxepfqplw    200
oppo    283800180    4720
uc    68d37cd7d8dc47af73474613225fbb0d_ali    560
oppo    299750392    200
oppo    68792513    20760
oppo    143653381    1000
uc    356e349241bcd17d233b4a582d55b894_ali    200
uc    c6ceda1c6685cb7330f738d065425b47_ali    8600
oppo    27720822    200
uc    11216515c38ca4e7ea35c2c00421d955_ali    200
vivo    48a420424411af19    200
oppo    147796532    400
oppo    125869425    200
uc    9a38fec523e3218fdb8020d8babe8fd6_ali    8000
vivo    ce8aaeb1c805e250    200
vivo    bec0a887fc77fea6    200
uc    2e6d627c9c58ba6adf1c0ff3dfc05ddc_ali    200
oppo    272379683    560
xiaomi    2018122805077325    200
oppo    232077665    200
oppo    313628435    200
oppo    284489272    200
uc    50a6789ca65896369bb0e7ab4d31a7cf_ali    200
oppo    399689077    1000
yyb    o17pv07idcmuh9_nlpuvjo8d5nw4    200
vivo    1a4fffb68c33024d    200
yyb    o17pv00hftagkedjvc69pqr4d60y    200
vivo    bf78f8e03ea96c42    200
uc    1ab709b8c2e6f662260fd5348c76d2b8_ali    200
uc    7ccf46ecbb63122b301580d9b2dcf060_ali    200
uc    09d9dbc96e4bc1b0c1152c2565648a7c_ali    200
xiaomi    2018122604409646    200
oppo    355943975    200
vivo    1359836bcf7b743a    1160
oppo    129122287    200
vivo    6a0d5e946919c7bf    200
vivo    755781bb21f7154c    1160
vivo    65bc25aeeb006c71    200
oppo    377117456    1000
uc    4c8382c787a720d14d1f110d1f5e42b8_ali    200
oppo    252265005    200
oppo    278352380    760
xiaomi    89110137    400
oppo    278577188    200
uc    bacff785c48717c9dda4f20c1af65df2_ali    200
vivo    c94ca73dc926d89b    2120
oppo    395777068    200
oppo    302666356    200
xiaomi    1283160716    1720
oppo    371783012    200
oppo    265343653    400
oppo    205359207    2760
oppo    252688395    400
xiaomi    2018122805041068    200
uc    835c2d80940491af0ebc8689d28bd634_ali    2000
uc    e344828773556b46ff4cf2cd3ef26e67_ali    200
uc    17649a91c21a23fd0d73af32d7445beb_ali    200
oppo    250425998    21040
yyb    o17pv0-dsiacpeldxyxst6d_wuki    200
yyb    bf8be35e45353d5fe8985e4ac776aa11    200
oppo    132591008    200
oppo    328593376    200
qh360    24811316    200
oppo    209803204    200
uc    7acacd61234cb8acd373051e83617170_ali    4120
vivo    d097c8e1cb6e9013    2800
oppo    424306720    200
vivo    f5af934dd04aeafc    2000
vivo    9a8ecea2eff3a9b5    200
uc    0eea4a35fad4211815efed7dc540375d_ali    43320
vivo    e28581402492b419    1400
uc    bd4bbda4a4bd3f06f842f41229d64431_ali    200
xiaomi    2018122906066879    1000
xiaomi    2018122704676451    200
qh360    2946645067    200
oppo    88734337    200
oppo    412584094    360
uc    5ec471186df83e4016a3015f3e725e39_ali    200
qh360    825858114    200
gionee    847e84f0e9014e46af2dd5085f95fb23    200
oppo    376928499    200
oppo    290512804    400
oppo    40929689    1000
qh360    380862319    200
oppo    123522434    4680
oppo    238997465    200
oppo    215672006    200
oppo    288020097    200
vivo    c031c32bd18258e7    11640
xiaomi    41313962    200
meizu    153309418    200
vivo    3f88a155d3e9d7e1    20360
uc    552d96b4ca5a4e026ccf53bd25911817_ali    1360
uc    6ba23ac773471a8caf235d7572595881_ali    200
uc    e4ec1cf7a140ce33c92aa46590a07187_ali    200
yyb    c9a8d2474018386bc08cb05c190b6719    200
oppo    204047699    7200
oppo    271140297    200
qh360    3039662638    200
oppo    406253936    200
oppo    382197009    200
vivo    d293ac07df6baa99    200
oppo    315181044    200
xiaomi    1136238005    4320
uc    7cd7a91108352326df6789edafa46d7c_ali    4880
oppo    210575226    200
oppo    130827046    200
uc    880c3d6646d492714d6e0006c0826ae7_ali    200
oppo    302961513    1160
oppo    249136462    200
oppo    224051513    200
oppo    210801681    200
uc    d7000487317d03b921e840dbaa975bf0_ali    200
xiaomi    1137339007    200
oppo    308123618    560
uc    117eac4fa731744736e7bb5cbf10a844_ali    200
oppo    264724657    200
oppo    216305250    200
meizu    19662006    200
uc    5ee5f28a3efa57bec3e413711636a61d_ali    560
uc    e39c0c310d601d21b9ac92aa0e0afc06_ali    200
oppo    297913707    800
uc    7e4ea43c033370df4cab0eab208ae7b2_ali    200
oppo    95894423    200
vivo    c07d26a033a0b341    200
gionee    1c5f1e0332424db3986cbd8e8751cf78    200
oppo    353941326    200
vivo    1db8027efa603427    200
oppo    155723526    200
oppo    237226552    200
oppo    320653836    200
uc    6dfca86c77cf31ca9726cea887b996cf_ali    200
vivo    d92c0a100c80a6f8    2720
yyb    o17pv06qxn7usfxyw8jp7toruojk    360
oppo    382110852    1000
yyb    o17pv05wrwpyp7dzzrlsz86gcumy    12200
vivo    91b35270051b7ffb    3560
oppo    39921681    200
uc    79e404f6d9b5d03b3db47a149f78eed9_ali    200
oppo    405986640    7840
oppo    247011825    200
oppo    311546293    200
vivo    92810d623e6754fc    200
oppo    141482197    560
oppo    336722288    200
oppo    390790962    1120
uc    d00368441137cb46d3f9e313cc00ce52_ali    2560
oppo    337088025    2760
oppo    352260205    1000
uc    9a18ffa893d1f4e5d1ce636c8f362a40_ali    6240
uc    5c07ec726a95db5cfe686b3155f61051_ali    1160
uc    c3b0be984b9b98b1baba4ac8dd796ce4_ali    200
oppo    231114389    200
uc    d5ca6808d754433ab55446e62a63b094_ali    200
uc    2fc866d2afce71953525afcb5db1d4af_ali    7240
uc    af65d2ec937dbf64fb4874b7bd067127_ali    1360
oppo    364107878    10760
oppo    339950423    200
oppo    g251809013099056411    200
oppo    21242152    200
oppo    202074663    200
vivo    9872706a903e168a    1000
oppo    309331847    200
oppo    130268810    200
oppo    120721221    200
uc    e56e4a15e85e63aee76b2c2be80643dd_ali    1000
vivo    8c5fab1e421efdb6    200
uc    a18ab4b623861283cbf947e868114955_ali    200
oppo    120464069    200
vivo    e0fbffd171c6d60e    200
qh360    2815384078    200
oppo    229036022    200
uc    b7b52246f318467c52525284ce2367d0_ali    200
uc    bc94dd481ba8089c63e3767de77591c5_ali    200
uc    3e43d868a78dd54e5ce2072831b736e2_ali    6880
oppo    316702827    2360
oppo    120930066    200
oppo    229781711    200
yyb    0747ad7ac9d2df7763199d11f9833c4c    200
uc    2daae5d057ef49674baca6b020d9bdfb_ali    1160
oppo    205063029    200
uc    0d9c8fdb22aedfd2a4a18c98af0ceea9_ali    2160
uc    037c588306aef1ba882e38ebdb46166b_ali    200
uc    679da6dbed489b97dc2ba8517ffed256_ali    3720
gionee    4c15bcd4c42f4730a9d3b1ddc17d74a0    200
xiaomi    63569047    400
vivo    8a2330ed17bbb3f4    1160
oppo    376626045    200
xiaomi    1131966296    200
uc    58f4f4228b62f6f69ce88eefb46ad3b4_ali    200
oppo    215614201    200
vivo    72fc51e202b6995d    200
qh360    130454715    200
uc    88024214331b58ffaaabf2aba8c69391_ali    4320
oppo    263406896    200
uc    27358a4969deafa8a45d7a97c14d297e_ali    200
oppo    308260086    10040
oppo    377739486    200
gionee    7043592a6f3647f58f0c2a98c02096bc    200
vivo    67aa714cef3b7a93    200
vivo    e85054243135050c    200
oppo    231372879    200
uc    c2e9575c409a581c1aa66813cb2b1cfa_ali    200
oppo    283771428    200
qh360    3104791211    1160
vivo    ccd98d30a47e84c0    200
oppo    47545084    800
oppo    385937122    800
gionee    e574dec776a04ce9b9ae50f1588328f0    2960
oppo    360346913    1000
xiaomi    133068086    200
oppo    59435983    600
vivo    d3efa55478df5da3    3560
xiaomi    176814433    200
meizu    147573331    2760
vivo    98b2805dc2d15d56    2720
oppo    109039959    1160
uc    dc4d65cab19a8bc41c45af16ffacb422_ali    200
vivo    0a45b35472bf39ea    560
oppo    360183897    3160
oppo    227039780    3920
oppo    207023781    25720
oppo    157597203    200
xiaomi    2018122905977745    560
oppo    416621295    200
uc    dce51d5642c293a1c800d483ce2c9787_ali    44920
uc    111be28d4e2914c5533cc9977e1cd97d_ali    200
uc    5036a358b5ca64ec5fc5f0659f6bca1d_ali    200
uc    24149f294a205fd24f5ab26f7811a8d8_ali    200
oppo    356398218    200
xiaomi    1012326175    1760
oppo    297034994    200
qh360    19945587    4520
uc    d86962171353c14514c602c155e1d825_ali    200
xiaomi    65553669    200
vivo    c15711a66fbf7d9d    200
yyb    o17pv08ewtvefflefropb2u9rc60    200
uc    feab3fce1ddf3710239f1e0f139aabcb_ali    360
oppo    106051020    200
oppo    259025772    200
oppo    146917783    200
qh360    635599801    2760
oppo    413322528    6040
vivo    4ee9454fcee2324b    600
yyb    o17pv055pmmp_jmgdnwjxluovgpi    200
vivo    57570cc9b4873259    24160
oppo    82103626    6720
yyb    o17pv0wx5kkz5awdyzqgo2iprojw    200
qh360    2993812756    200
oppo    295618964    560
gionee    917fbe758848449298c83aa283a2c329    200
oppo    42404837    200
oppo    364830466    200
yyb    672400e8343dbdd22f057ded0a455de3    44000
oppo    212115480    1160
uc    ab37354f3d629cc33c84b21e9e012423_ali    200
vivo    740933f3cf9c8af6    600
xiaomi    48816775    200
yyb    o17pv0-dakzdfhu9aipv8le6evb8    21560
vivo    2a0474385188c369    200
xiaomi    2018122805277795    200
oppo    390227594    200
vivo    bb3a1fcc77c4a621    200
xiaomi    97882714    6640
uc    fcfb555c0df5ba967a0584d68d69378a_ali    1160
xiaomi    142357422    200
oppo    62793498    2160
oppo    63527031    200
oppo    273084300    200
vivo    ef27eb5708c0ee2e    200
oppo    156757168    200
oppo    203702472    200
uc    abae09bd4dc2947037dba3bbb39f653a_ali    800
xiaomi    71831495    200
oppo    314778495    200
uc    042e3e0b159d70708313d86d87c91f81_ali    200
oppo    230545944    3360
uc    a955f7743371dcf51e4d87cff8310b7f_ali    200
oppo    247924712    200
uc    c1e51083160f23138001f1b0cdf0f430_ali    200
vivo    0945c1821925b0b9    200
uc    7b25e102846cba5ae4fa4b6d94b00da1_ali    200
xiaomi    2018122704956901    200
oppo    102105723    200
uc    3a10d50e110e8a7649b12e3c08d2f0fe_ali    6520
oppo    346806770    200
oppo    374205568    200
vivo    89971ba63000ff6f    200
vivo    cdd27a7159bdbfc1    1160
oppo    216711417    6040
uc    782a1edec92bdb7a2c4207b12437648f_ali    1000
oppo    140011394    200
vivo    84a56c8d9d4351eb    4520
vivo    56389ddd8f9ac854    2320
yyb    a412504e2a32bece362f3840ffd18d26    1400
uc    01e5707733b63729b41ec9b334909936_ali    4920
oppo    374836678    4320
oppo    248291697    2560
vivo    ef545a90bf2f7342    8040
vivo    77e464a85f459714    200
oppo    79077961    200
uc    41399f4bc8fdcc9ffc737282f8f08b77_ali    2160
oppo    362346452    8800
oppo    268996224    4280
oppo    137826947    200
oppo    240815153    2960
oppo    326118066    200
oppo    31032838    200
qh360    366904668    200
oppo    128951275    200
vivo    003f70fa2bb0ebd4    2560
oppo    406604500    200
yyb    o17pv08eno5fnria4y_xlkvrormg    200
uc    f9e1ec6ef76f743cf416c64164e51555_ali    1000
yyb    o17pv09fudw12dfwtzi68mhqnzlk    200
oppo    125078260    200
yyb    o17pv0_m69hgfrckfaactgzagkoa    6840
vivo    ff78057a4fea1649    200
oppo    159418910    200
oppo    401482477    800
xiaomi    98477450    200
oppo    244384729    200
oppo    229992458    1160
oppo    358821834    2160
oppo    224671375    200
oppo    68178327    960
oppo    232536326    200
yyb    o17pv04pel53btzkf5grx-6igwiy    200
yyb    9ad3021502676fd519591fa9345b2ad2    200
uc    b21d5c1f8e656fbdd464fd76cbd39534_ali    200
uc    a9be827fcd91c31cfeab18409b138956_ali    7160
oppo    396051888    7240
oppo    402065291    21960
vivo    b6f9ecbf2a30d20b    20120
uc    3cdd90b4e15e622d1c49534e5261b584_ali    200
oppo    304571639    9320
oppo    278470659    360
oppo    256595603    200
yyb    o17pv00iuvmk5-uog97qptpg2j-m    10160
uc    ccf6bc72fdd23cebc4eae87b39e60444_ali    600
vivo    1ec67d4b7793791a    1000
xiaomi    1130042911    200
uc    69624290d46dd718cc2f9e2f24e4bc7f_ali    200
oppo    369420484    1320
xiaomi    258717    200
oppo    261622394    560
yyb    o17pv04ygr-bf2uhteqgqn5p58qw    2560
uc    1f2a8901ce41aaa7df309e7284b728b8_ali    1160
vivo    780041c02376ef8e    760
oppo    360602356    200
meizu    147201109    200
oppo    358126871    4360
vivo    d4e82a32234f2ee6    360
yyb    o17pv0978bb1_qv3miap74nckqye    400
oppo    132459730    1000
vivo    4f74d6ed74437579    200
vivo    77931b89e09a975b    200
oppo    30684126    3280
oppo    28511315    200
vivo    0e4377f03e84a103    200
uc    a544f0029a6defe8358cfb4d72d22d4c_ali    200
xiaomi    2018122704593835    200
oppo    320705464    200
oppo    157729500    800
oppo    219160323    10200
oppo    279464953    2160
oppo    167301532    200
oppo    46294593    1160
vivo    8b116d7e0bf2af95    200
uc    e52aa50989f07bf169a6cceefbefde80_ali    2400
uc    86f6c6a1280c3519c657ea314b1a15f0_ali    200
oppo    253812822    200
lenovo    10134826973    200
oppo    421876249    5840
oppo    336330244    200
yyb    o17pv086vcrezjd5seqfbgrvnr6k    200
oppo    266845715    200
uc    37190d122f726522415204529536dc0a_ali    200
oppo    117223374    4720
yyb    o17pv0w31yot7m_z6nbuwuvf6aua    200
yyb    o17pv08gombsjkp6akybicqk4k_k    17160
oppo    364525962    200
oppo    212429318    200
oppo    388209982    2920
oppo    201108752    2360
vivo    a08b3f3d6243fcce    200
lenovo    10134409050    200
xiaomi    1131095509    2160
xiaomi    93979584    1000
uc    db8724f34ce8af171f4ef86ad4e53985_ali    200
oppo    149057284    200
qh360    3043505919    200
uc    556bef15ee922ca26b20ea965ad8311e_ali    9400
xiaomi    66948764    200
xiaomi    6878019    200
uc    c9aca2c70a222db5283584c1db013ce6_ali    5480
oppo    242271147    200
oppo    210652692    6880
vivo    d2df5b9b7b1a7f59    200
oppo    82798699    200
uc    84441ddff236aeec519edc57bf0df0f3_ali    20320
yyb    o17pv05gjpuxfg4ncc22udladxao    200
oppo    147694212    1560
oppo    157975820    560
oppo    399246639    600
uc    0475a7d172af0626638da2ef0490ea21_ali    200
vivo    c04becbc83823adc    200
oppo    415525735    200
uc    329f12bfea0b75b0f86d3036b07c9f68_ali    4160
yyb    o17pv03hkdftct_xhcyezm-d6yni    200
qh360    543535500    800
xiaomi    1049901775    200
xiaomi    140253855    2520
oppo    282307700    360
uc    3c718aef876a52f3dffd5223716851c6_ali    200
xiaomi    162239035    200
oppo    406073690    200
oppo    302888081    960
oppo    425227108    200
oppo    323485732    200
uc    1c9768fa84def80b9662e7af94ad5fc8_ali    200
meizu    162038018    200
vivo    cae9d41e94a4db0b    200
oppo    331130471    200
vivo    cc71bf226be738a3    760
oppo    336108133    1720
oppo    365369216    2160
xiaomi    1109575422    200
oppo    65412945    200
oppo    303306435    200
yyb    o17pv016-xbntfnto8dmnujr73l8    9160
oppo    217895166    200
oppo    391869516    12360
oppo    341528078    200
vivo    d9f7992ef8c0f11c    200
oppo    275666431    200
lenovo    10134474718    200
oppo    150069409    200
uc    efec018b2f5a84fa406573616d1da7eb_ali    800
oppo    303030396    400
yyb    6ab7a4b6759bae392c30c7620730da0c    200
uc    db24e1c9a4bee5c3d4e325ec0462399e_ali    200
oppo    378612954    560
oppo    156878963    200
vivo    1f528e22e8433aef    200
oppo    48225126    200
xiaomi    14035931    200
oppo    326266516    200
uc    94d3395c3df6efc6d5044cb95f3416d5_ali    200
vivo    d6132fdc476f223a    200
yyb    o17pv0xvt-kduk4ezkogx_y5mzhs    200
oppo    226895056    200
xiaomi    72705931    200
oppo    273624232    800
oppo    277873367    200
uc    2e9d8b5d9f979dff0ceaef9ce74129d4_ali    200
yyb    adb828e92716e338ac44dc08b9ea1483    200
vivo    1690760fe3257af0    7440
oppo    146865973    67920
xiaomi    127562084    1200
xiaomi    78126528    200
yyb    o17pv07snqkcmbkhp8aclisujfvk    200
xiaomi    1039857212    1360
yyb    o17pv0wt9vcjvdnk1jaenxvpwzpk    200
vivo    82dc39e0c671993b    200
oppo    279042369    200
vivo    8734fb0770881000    200
oppo    205007669    61880
xiaomi    75701888    1160
meizu    119626606    200
uc    5dc0b3b52c9ae75f343698e03032cd98_ali    200
oppo    378369013    200
vivo    692695aa3545fb5e    200
oppo    311363738    1160
yyb    o17pv0-x2dsuc-jz4ht-kij0qqk4    200
uc    e69d4f85dbfb45999c6abb43911d6aad_ali    200
vivo    7545aa944a768c3e    2960
vivo    979413bc418b5188    200
vivo    4bf70d50dbeb733c    200
oppo    157556500    1000
oppo    318639885    1360
vivo    c9b33a7c46a4237a    200
oppo    409456093    1160
vivo    c95636c643441606    200
xiaomi    1125426384    5040
yyb    o17pv08k5cphm8wpe_g5oryz4r60    200
oppo    408755028    14120
vivo    ccac2b0bcc7f4bf5    200
yyb    o17pv09hcor5doyzxrw8iua6cmxu    200
vivo    c4ff8fec48ffbbc4    73680
oppo    332769083    920
uc    f2a59dd63891ebf485f68d14b35b75c0_ali    200
oppo    129360630    200
xiaomi    105171138    1000
oppo    292125878    200
qh360    396814834    200
oppo    139064637    1160
uc    8673e952fd8a5647dbbad3d986d19ed4_ali    1360
oppo    411383567    144200
uc    54a9ddc19da32a87118bf2a41a686bf8_ali    200
oppo    284237868    200
uc    0c02faf559e63f78293bc87c458c383a_ali    9040
oppo    362447552    200
oppo    235469516    200
oppo    232635618    200
oppo    118702614    44960
oppo    157103866    2560
oppo    154828437    560
vivo    56018b58393a3ff7    4120
vivo    27418491e561e881    200
uc    a07681488f70c9ca60c5424ec80fdd36_ali    200
oppo    111193819    800
meizu    17097398    4080
oppo    327117491    2760
vivo    9c09420af8300727    200
uc    c3b69e197837c8e260ab429c0b11f0ff_ali    200
uc    800e24a59f529bb53cecbae82dd43b75_ali    7280
uc    4b2e1171944e5bacd2856a4abff1dea3_ali    200
yyb    o17pv06ygejzfv9-hsvlo0fsq8ey    800
vivo    c726b1caa009878b    2760
uc    5e81fecb4ac9762587705df1543255dd_ali    200
oppo    245522252    200
yyb    o17pv09uths5umpykvwd47wasfwg    200
xiaomi    1051049514    200
oppo    424009396    200
yyb    o17pv0-d9hx3ymwagycvy1kaoutw    200
oppo    387588449    200
vivo    7e9e81990fc2e7d5    200
meizu    145311380    200
oppo    253381574    200
oppo    251115270    200
gionee    cd7e9fe4cfc44ec19ce4bc17afcea973    5160
oppo    76574434    200
vivo    e5c963e639cbe4fe    1160
yyb    o17pv03j8kgr-qcddftkri6hilqo    200
oppo    28511331    200
uc    1f128dad77d929d14b0deab2324146b2_ali    200
uc    98aeabce757a38e5aa774525f4d2fc8a_ali    200
vivo    c08ed942738c05e2    200
oppo    341853907    200
oppo    307629707    200
oppo    415411792    15360
oppo    286603484    200
oppo    294092776    200
oppo    266170227    600
vivo    b2a2d652b82cbcec    2560
vivo    e8cd15a99e1dfb24    1000
uc    3f69d43bec189b1f5dfe2873d70ad1bb_ali    200
vivo    d018afc4d853d493    1960
qh360    13458383    6280
vivo    a4e4d305cf2c9594    1360
oppo    290685531    4920
uc    685148381997c887f5dc997124f0621c_ali    200
oppo    301890935    10560
oppo    271345808    200
vivo    97b3adcdf8b3671b    200
vivo    f072c062e1ab0ef6    200
oppo    128264104    200
oppo    323026143    200
uc    89de4d67ccfbdca0578c25fe72f66350_ali    200
meizu    140734701    200
oppo    44631391    200
xiaomi    929140    200
Tool/WebCenter/DoubleBill/DoubleBillDB.py
New file
@@ -0,0 +1,49 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 数据库-录入传统渠道删档玩家的充值返利  1元=20仙玉
#
# @author: Alee
# @date 2019-1-22 下午03:13:42
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
from lib import DBController
from lib import mylog
g_dbController = None
def InitDB():
    global g_dbController
    if not g_dbController:
        IP = "127.0.0.1"
        Port = 27017
        User = "sa"
        Pwd = "sa"
        DBName = "DoubleBillDB"
        g_dbController = DBController.DBController(IP, Port, DBName, User, Pwd, None)
        mylog.debug('获取新的数据库链接')
    if not g_dbController.connected:
        mylog.debug('无法链接数据库')
        return False
    return True
def GetDBEventCon():
    global g_dbController
    if not InitDB():
        return None
    return g_dbController
Tool/WebCenter/DoubleBill/DoubleBillTool.py
New file
@@ -0,0 +1,457 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 录入返利 # 数据库字段 渠道spid 账号accid 仙玉gold 兑换所在服serverid
#
# @author: Alee
# @date 2019-1-22 下午03:23:30
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
import pymongo
from pymongo.son_manipulator import SONManipulator
import base64
from functools import wraps
from time import (sleep)
from lib import CommFunc
class ObjectIdRemover(SONManipulator):
    def transform_outgoing(self, son, collection):
        if '_id' in son:
            del son['_id']
        return son
class EncodeStringManipulator(SONManipulator):
    def __init__(self, encoding):
        self.encoding = encoding
    def transform_incoming(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                result, value = CommFunc.EncodingToUnicode(self.encoding, value)
                return value
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
    def transform_outgoing(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                result, value =CommFunc.UnicodeToEncoding(self.encoding, value)
                return value
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
class Base64StringManipulator(SONManipulator):
    def transform_incoming(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                return base64.b64encode(value)
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
    def transform_outgoing(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                return base64.b64decode(value)
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
#用于修饰DBController的数据库操作函数
#断线自动重试
def reconnect_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwds):
        MAX_RECONNECT = 10
        RECONNECT_INTERVAL = 0.1
        failCnt = 0
        while True:
            try:
                #去掉self
                return func(*args, **kwds)
            except pymongo.errors.AutoReconnect, e:
                failCnt += 1
                sleep(RECONNECT_INTERVAL)
                if failCnt > MAX_RECONNECT:
                    raise e
    return wrapper
class DBController:
    def __init__(self, host, port, dbName, user, pwd, encoding):
        self.host = host
        self.port = port
        self.dbName = dbName
        self.user = user
        self.pwd = pwd
        self.connected = False
        self.con = None
        self.db = None
        self.lastError = None
        self.translator = None
        #===========================================================================================
        # if encoding == 'base64':
        #    self.translator = Base64StringManipulator()
        # else:
        #    self.translator = EncodeStringManipulator(encoding)
        #===========================================================================================
        self.initialize()
    def initialize(self):
        if not self.connected:
            if not self.doConnect(self.host, self.port):
                return False
            authResult = self.doAuthentication(self.dbName, self.user, self.pwd)
            if self.db:
                self.db.add_son_manipulator(ObjectIdRemover())
            return authResult
        return True
    def doConnect(self, ip, port):
        try:
            self.con = pymongo.Connection(ip, port)
        except TypeError, typeError:
            raise
        except pymongo.errors.ConnectionFailure, failure:
            self.lastError = failure
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        self.connected = True
        return True
    def doAuthentication(self, dbName, user, pwd):
        if not self.connected or not self.con:
            self.lastError = 'Not connected yet!'
            return False
        self.db = self.con[dbName]
        authDB = self.con['admin']
        try:
            return authDB.authenticate(user, pwd)
#            return self.db.authenticate(user, pwd)
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
    def find_one(self, colName, spec, filter = None):
        result, recList = self.find(colName, spec, filter, 1)
        if not result:
            return False, None
        for rec in recList:
            return True, rec
        return True, None
    @reconnect_decorator
    def find(self, colName, spec = None, filter = None, maxCnt = 0, sortBy = None):
        if not self.connected:
            if not self.initialize():
                return False, []
        result = False
        resultDictList = []
        col = self.db[colName]
        if self.translator:
            spec = self.translator.transform_incoming(spec, None)
        try:
            resultCollection = col.find(spec, filter, limit = maxCnt, sort = sortBy)
            if self.translator:
                resultDictList = self.translator.transform_outgoing(list(resultCollection), None)
            else:
                resultDictList = list(resultCollection)
            return True, resultDictList
        except TypeError, typeError:
            self.lastError = typeError
            return result, resultDictList
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return result, resultDictList
        except Exception, e:
            self.lastError = e
            return result, resultDictList
        except:
            self.lastError = 'Unknown exception occur!'
            return result, resultDictList
    @reconnect_decorator
    def insert(self, colName, doc_or_docs, isSafe = True):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        if self.translator:
            doc_or_docs = self.translator.transform_incoming(doc_or_docs, None)
        try:
            col.insert(doc_or_docs, safe = isSafe)
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def update(self, colName, spec, doc, isUpsert = False, isSafe = True, isMulti = False):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        #需要先对doc进行处理,但由不能开启collection.update的manipulate,因为那会应用所有处理
        if self.translator:
            spec = self.translator.transform_incoming(spec, None)
            doc = self.translator.transform_incoming(doc, None)
        try:
            col.update(spec, doc, upsert = isUpsert, safe = isSafe, multi = isMulti)
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def save(self, colName, doc, isSafe = True):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        if self.translator:
            doc = self.translator.transform_incoming(doc, None)
        try:
            col.save(doc, safe = isSafe)
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def remove(self, colName, spec = None, isSafe = True):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        if self.translator:
            spec = self.translator.transform_incoming(spec, None)
        try:
            col.remove(spec, safe = isSafe)
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def drop(self, colName):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        try:
            col.drop()
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def count(self, colName):
        if not self.connected:
            if not self.initialize():
                return False, 0
        col = self.db[colName]
        try:
            cnt = col.count()
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False, 0
        except Exception, e:
            self.lastError = e
            return False, 0
        except:
            self.lastError = 'Unknown exception occur!'
            return False, 0
        return True, cnt
def test_DBController():
    fileIO = open("Bill.txt")
    # spid accid gold
    testColName = 'tagDoubleBill'
    dbController = DBController('localhost', 27017, "DoubleBillDB", 'sa', 'sa', None)
    print "开始录入数据"
    cnt = 0
    spidDict= {}
    #渠道SpID 账号AccID 仙玉Gold 兑换所在服ServerID
    for line in fileIO.readlines():
        try:
            spID, accID, gold = line.strip().split()
        except:
            print "Error:", line
            continue
        result, recs = dbController.find(testColName, {"SpID":spID, "AccID":accID})
        if recs:
            print "重复插入", spID, accID, gold
            continue
        doc = {"SpID":spID, "AccID":accID, "Gold":gold, "ServerID":""}
        result = dbController.insert(testColName, doc)
        if not result:
            print "插入失败", spID, accID, gold
            continue
        spidDict[spID] = 0
        cnt += 1
    print "录入渠道返利结束,总共%s条, 含平台%s"%(cnt, spidDict.keys())
#开始录入数据
#录入渠道返利结束,总共681条, 含平台['kupai', 'uc', 'gionee', 'xiaomi', 'vivo', 'lenovo', 'meizu', 'yyb', 'oppo', 'qh360']
def test():
    test_DBController()
    print 'test ok!'
if __name__ == '__main__':
    test()
    import os
    os.system("pause")
Tool/WebCenter/DoubleBill/bottle.py
New file
Diff too large
Tool/WebCenter/DoubleBill/lib/CommFunc.py
New file
@@ -0,0 +1,371 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo:
#
# @author: Alee
# @date 2018-7-18 上午11:22:43
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
import struct
import string
import datetime
import os
import binascii
import socket
import sys
#python的读取/写入库
#要进行反转高低位的话,可使用!符号,如struct.unpack_from('!B', buf, pos)
#------------------------读取
def ReadBYTE(buf, pos):
    curValue = struct.unpack_from('b', buf, pos)
    pos += 1
    return curValue[0], pos
def ReadWORD(buf, pos):
    curValue = struct.unpack_from('H', buf, pos)
    pos += 2
    return curValue[0], pos
def ReadDWORD(buf, pos):
    curValue = struct.unpack_from('i', buf, pos)
    pos += 4
    return curValue[0], pos
def ReadFloat(buf, pos):
    curValue = struct.unpack_from('f', buf, pos)
    pos += 4
    return curValue[0], pos
def ReadDouble(buf, pos):
    curValue = struct.unpack_from('d', buf, pos)
    pos += 8
    return curValue[0], pos
def ReadString(buf, pos, _len):
    curValue = struct.unpack_from('%ds'%_len, buf, pos)
    pos += _len
    return curValue[0], pos
#----------------------写入
def WriteBYTE(buf, value):
    buf += struct.pack('b', value)
    return buf
def WriteWORD(buf, value):
    buf += struct.pack('H', value)
    return buf
def WriteDWORD(buf, value):
    buf += struct.pack('i', value)
    return buf
def WriteFloat(buf, value):
    buf += struct.pack('f', value)
    return buf
def WriteDouble(buf, value):
    buf += struct.pack('d', value)
    return buf
def WriteString(buf, len, value):
    buf += struct.pack('%ds'%len, value)
    return buf
#获得当前系统时间
def GetCurrentDataTimeStr():
    curTime = datetime.datetime.today()
    curTimeStr = str(curTime)
    curTimeStr = curTimeStr.split(".")[0]
    return curTimeStr
#获得系统时间(参数 -> 时间列表)
def GetDateTimeByStr(timeStr):
    timeStr = timeStr.split(".")[0]
    return  datetime.datetime.strptime(timeStr, "%Y-%m-%d %H:%M:%S")
#字符串转换为整型, 如果不能转换, 返回默认值
def ToIntDef(input, defValue = 0):
    try:
        result = int(input)
        return result
    except ValueError:
        return defValue
#字符串转换为整型, 如果不能转换, 返回False,原值
def StrToInt(input):
    try:
        result = int(input)
        return True,result
    except ValueError:
        return False,input
#16进制颜色转换
#"#FFFFFF"--"255,255,255"
def HcToSc(h):
    h="0x"+h[1:7]
    red=string.atoi(h[:2]+h[2:4], base=16)
    green=string.atoi(h[:2]+h[4:6], base=16)
    blue=string.atoi(h[:2]+h[6:8], base=16)
    cStr=str(red)+","+str(green)+","+str(blue)
    return cStr
#"255,255,255"--"#FFFFFF"
def ScToHc(s):
    red=hex(string.atoi(s.split(",")[0]))[2:]
    green=hex(string.atoi(s.split(",")[1]))[2:]
    blue=hex(string.atoi(s.split(",")[2]))[2:]
    hStr="#"+str(red+green+blue)
    return hStr
#16进制转换
#"0xFFFFFF"--"255,255,255"
def HdToSd(h):
    red=string.atoi(h[0:2]+h[2:4], base=16)
    green=string.atoi(h[0:2]+h[4:6], base=16)
    blue=string.atoi(h[0:2]+h[6:8], base=16)
    cStr=str(red)+","+str(green)+","+str(blue)
    return cStr
#"255,255,255"--"0xFFFFFF"
def SdToHd(s):
    red=hex(string.atoi(s.split(",")[0]))[2:]
    green=hex(string.atoi(s.split(",")[1]))[2:]
    blue=hex(string.atoi(s.split(",")[2]))[2:]
    hStr="0x"+str(red+green+blue)
    return hStr
def GetPercent(value1, value2):
    if value2 == 0:
        return 0
    return int(float(value1) / float(value2) * 100)
def OpenFileForWrite(fileName):
    dirName = os.path.dirname(fileName)
    if not os.path.isdir(dirName):
        os.makedirs(dirName)
    if os.path.isfile(fileName):
        return open(fileName, 'w')
    return  open(fileName, 'a')
#函数调用
def ParseNameGetObj(curCallObj, callName):
    callList = callName.split(".")
    if len(callList) <= 1:
        return None
    for curCallName in callList:
        if hasattr(curCallObj, curCallName) != True:
            #无此属性
            return None
        curCallObj = getattr(curCallObj, curCallName)
    return curCallObj
#获得执行函数
def GetExecFunc(curCallObj, callName):
    curCallObj = ParseNameGetObj(curCallObj, callName)
    if curCallObj == None:
        return None
    if callable(curCallObj) != True:
        #不可调用
        return None
    return curCallObj
#字符串异或处理
def str_xor(astring, xornum=150):
    a=[]
    for x in astring:
        a.append(chr(ord(x)^xornum))
    return ''.join(a)
#解析封包
def ParseBuff(buff):
    result=''
    for i in  range(len(buff)):
        if i%2==0 and i!=0:
            result=result + ' ' + buff[i]
        else:
            result = result + buff[i]
    return result
def b2a_hex(data):
    return ParseBuff(binascii.b2a_hex(data))
def GetHostName():
    return socket.gethostname()
def GetHostIP():
    return socket.gethostbyname(GetHostName())
def compact_traceback():
    t, v, tb = sys.exc_info()
    tbinfo = []
    if not tb: # Must have a traceback
        raise AssertionError("traceback does not exist")
    while tb:
        tbinfo.append((
            tb.tb_frame.f_code.co_filename,
            tb.tb_frame.f_code.co_name,
            str(tb.tb_lineno)
            ))
        tb = tb.tb_next
    # just to be safe
    del tb
    info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
    return t, v, info
import base64
import urllib
import urllib2
#---------------------------------------------------------------------
## 加密算法需要的定义
Def_NumEncodeCnt = 3  # 加密的次数
Def_NumXorKey = 151  # 异或的key
## 公司内部解密算法
def GetDecodePwd(strPwd):
    strResult = strPwd
    for index in xrange(Def_NumEncodeCnt):
        strResult = base64.b64decode(strResult)
    tempResult = ""
    for index in xrange(len(strResult)):
        tempResult += chr(ord(strResult[index])^Def_NumXorKey)
    return tempResult
## 公司内部加密算法
def GetEncodePwd(strPwd):
    strResult = ""
    for index in xrange(len(strPwd)):
        strResult += chr(ord(strPwd[index])^Def_NumXorKey)
    for index in xrange(Def_NumEncodeCnt):
        strResult = base64.b64encode(strResult)
    return strResult
#---------------------------------------------------------------------
## UTF-8 <==> GBK
def gbk2utf8(content):
    if type( content ) is not str:
        content = str(content)
    try:
        return content.decode('gbk').encode('utf-8')
    except:
        return content
def utf82gbk(content):
    if type( content ) is not str:
        content = str(content)
    try:
        return content.decode('utf-8').encode('gbk')
    except:
        return content
## GET请求
def DoGet(url, data=None, headers={}):
    if data:
        request = urllib2.Request(url + "?" + urllib.urlencode(data), None, headers)
    else:
        request = urllib2.Request(url, None, headers)
    response = urllib2.urlopen(request, timeout=5)
    content = response.read()
    response.close()
    return content
## POST请求
def DoPost(url, data, headers={}):
    try:
        data = urllib.urlencode(data)
    except:
        pass
    request = urllib2.Request(url, data, headers)
    try:
        response = urllib2.urlopen(request, timeout=30)
        content = response.read()
        response.close()
    except:
        content = "error timeout"
    return content
FileTypeDict = {
'.txt':'text/html',
'.html':'text/html',
'.htm':'text/html',
'.bmp':'application/x-bmp',
'.ico':'image/x-icon',
'.jpe':'image/jpeg',
'.jpeg':'image/jpeg',
'.jpg':'application/x-jpg',
'.png':'application/x-png',
'.gif':'image/gif',
'.bin':'application/octet-stream',
'.*':'application/octet-stream'
}
def GetHttpContentType(strType):
    return FileTypeDict[strType]
## 编码
#  @param srcEncoding 编码格式
#  @param input 字符串
#  @return None
def EncodingToUnicode(srcEncoding, msg):
    try:
        result = unicode(msg, srcEncoding)    #translate to utf-8
    except:
        return "EncodingToUnicode error"
    return result
## 编码
#  @param srcEncoding 编码格式
#  @param input 字符串
#  @return None
def UnicodeToEncoding(dstEncoding, msg):
    try:
        result = msg.encode(dstEncoding)
    except:
        return "UnicodeToEncoding error"
    return result
Tool/WebCenter/DoubleBill/lib/DBController.py
New file
@@ -0,0 +1,516 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------
#
import pymongo
from pymongo.son_manipulator import SONManipulator
import base64
from functools import wraps
from time import (sleep)
import CommFunc
#模拟SQL的IDENT
def seq(db, collectionName, fieldName, feed, increment):
    try:
        result = 0
        collection = db['%s_seq'%collectionName]
        resultObj = collection.find_and_modify(query={'_id':fieldName}, update={'$inc':{'seq':increment}}, new=True)
        if resultObj:
            result = resultObj['seq']
        else:
            resultObj = collection.find_and_modify(query={'_id':fieldName}, update={'$set':{'seq':feed}}, new=True,
                                                   upsert=True)
            if resultObj:
                result = resultObj['seq']
            else:
                return False, None
    except Exception, e:
        return False, None
    return True, result
class ObjectIdRemover(SONManipulator):
    def transform_outgoing(self, son, collection):
        if '_id' in son:
            del son['_id']
        return son
class EncodeStringManipulator(SONManipulator):
    def __init__(self, encoding):
        self.encoding = encoding
    def transform_incoming(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                result, value = CommFunc.EncodingToUnicode(self.encoding, value)
                return value
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
    def transform_outgoing(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                result, value =CommFunc.UnicodeToEncoding(self.encoding, value)
                return value
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
class Base64StringManipulator(SONManipulator):
    def transform_incoming(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                return base64.b64encode(value)
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
    def transform_outgoing(self, son, collection):
        def transform_value(value):
            if isinstance(value, dict):
                return transform_dict(value)
            elif isinstance(value, list):
                return [transform_value(v) for v in value]
            elif isinstance(value, basestring):
                return base64.b64decode(value)
            return value
        def transform_dict(object):
            for (key, value) in object.items():
                object[key] = transform_value(value)
            return object
        def transform_list(container):
            for item in container:
                transform_dict(item)
            return container
        if isinstance(son, dict):
            return transform_dict(son)
        elif isinstance(son, list):
            return transform_list(son)
        return son
#用于修饰DBController的数据库操作函数
#断线自动重试
def reconnect_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwds):
        MAX_RECONNECT = 10
        RECONNECT_INTERVAL = 0.1
        failCnt = 0
        while True:
            try:
                #去掉self
                return func(*args, **kwds)
            except pymongo.errors.AutoReconnect, e:
                failCnt += 1
                sleep(RECONNECT_INTERVAL)
                if failCnt > MAX_RECONNECT:
                    raise e
    return wrapper
class DBController:
    def __init__(self, host, port, dbName, user, pwd, encoding):
        self.host = host
        self.port = port
        self.dbName = dbName
        self.user = user
        self.pwd = pwd
        self.connected = False
        self.con = None
        self.db = None
        self.lastError = None
        self.translator = None
        #===========================================================================================
        # if encoding == 'base64':
        #    self.translator = Base64StringManipulator()
        # else:
        #    self.translator = EncodeStringManipulator(encoding)
        #===========================================================================================
        self.initialize()
    def initialize(self):
        if not self.connected:
            if not self.doConnect(self.host, self.port):
                return False
            authResult = self.doAuthentication(self.dbName, self.user, self.pwd)
            if self.db:
                self.db.add_son_manipulator(ObjectIdRemover())
            return authResult
        return True
    def doConnect(self, ip, port):
        try:
            self.con = pymongo.Connection(ip, port)
        except TypeError, typeError:
            raise
        except pymongo.errors.ConnectionFailure, failure:
            self.lastError = failure
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        self.connected = True
        return True
    def doAuthentication(self, dbName, user, pwd):
        if not self.connected or not self.con:
            self.lastError = 'Not connected yet!'
            return False
        self.db = self.con[dbName]
        authDB = self.con['admin']
        try:
            return authDB.authenticate(user, pwd)
#            return self.db.authenticate(user, pwd)
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
    def find_one(self, colName, spec, filter = None):
        result, recList = self.find(colName, spec, filter, 1)
        if not result:
            return False, None
        for rec in recList:
            return True, rec
        return True, None
    @reconnect_decorator
    def find(self, colName, spec = None, filter = None, maxCnt = 0, sortBy = None):
        if not self.connected:
            if not self.initialize():
                return False, []
        result = False
        resultDictList = []
        col = self.db[colName]
        if self.translator:
            spec = self.translator.transform_incoming(spec, None)
        try:
            resultCollection = col.find(spec, filter, limit = maxCnt, sort = sortBy)
            if self.translator:
                resultDictList = self.translator.transform_outgoing(list(resultCollection), None)
            else:
                resultDictList = list(resultCollection)
            return True, resultDictList
        except TypeError, typeError:
            self.lastError = typeError
            return result, resultDictList
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return result, resultDictList
        except Exception, e:
            self.lastError = e
            return result, resultDictList
        except:
            self.lastError = 'Unknown exception occur!'
            return result, resultDictList
    @reconnect_decorator
    def insert(self, colName, doc_or_docs, isSafe = True):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        if self.translator:
            doc_or_docs = self.translator.transform_incoming(doc_or_docs, None)
        try:
            col.insert(doc_or_docs, safe = isSafe)
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def update(self, colName, spec, doc, isUpsert = False, isSafe = True, isMulti = False):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        #需要先对doc进行处理,但由不能开启collection.update的manipulate,因为那会应用所有处理
        if self.translator:
            spec = self.translator.transform_incoming(spec, None)
            doc = self.translator.transform_incoming(doc, None)
        try:
            col.update(spec, doc, upsert = isUpsert, safe = isSafe, multi = isMulti)
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def save(self, colName, doc, isSafe = True):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        if self.translator:
            doc = self.translator.transform_incoming(doc, None)
        try:
            col.save(doc, safe = isSafe)
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def remove(self, colName, spec = None, isSafe = True):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        if self.translator:
            spec = self.translator.transform_incoming(spec, None)
        try:
            col.remove(spec, safe = isSafe)
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def drop(self, colName):
        if not self.connected:
            if not self.initialize():
                return False
        col = self.db[colName]
        try:
            col.drop()
        except TypeError, typeError:
            self.lastError = typeError
            return False
        except Exception, e:
            self.lastError = e
            return False
        except:
            self.lastError = 'Unknown exception occur!'
            return False
        return True
    @reconnect_decorator
    def count(self, colName):
        if not self.connected:
            if not self.initialize():
                return False, 0
        col = self.db[colName]
        try:
            cnt = col.count()
        except pymongo.errors.OperationFailure, err:
            self.lastError = err
            return False, 0
        except Exception, e:
            self.lastError = e
            return False, 0
        except:
            self.lastError = 'Unknown exception occur!'
            return False, 0
        return True, cnt
def test_seq():
    con = pymongo.Connection()
    db = con.admin
    if not db.authenticate('sa', 'sa'):
        print 'auth failed!'
        return
    colName = 'tagSeqTest'
    fieldName = 'ID'
    db = con['test']
    db.drop_collection(colName)
    db.drop_collection('%s_seq'%colName)
    result, ID = seq(db, colName, fieldName, 1, 1)
    assert (result and ID == 1)
    result, ID = seq(db, colName, fieldName, 1, 1)
    assert (result and ID == 2)
def test_StringManipulator():
    translator = Base64StringManipulator()
    son = []
    result = translator.transform_incoming(son, None)
    assert (son == result)
    result = translator.transform_outgoing(son, None)
    assert (son == result)
    son = [{'a':1}]
    result = translator.transform_incoming(son, None)
    assert (son == result)
    result = translator.transform_outgoing(son, None)
    assert (son == result)
    son = [{'a':'a'}]
    result = translator.transform_incoming(son, None)
    assert (result and result == [{'a':base64.b64encode('a')}])
    result = translator.transform_outgoing(result, None)
    assert (result and result == son)
    son = [{'a':[{'b':'b'}, {'c':'c'}]}]
    result = translator.transform_incoming(son, None)
    assert (result and result == [{'a':[{'b':base64.b64encode('b')}, {'c':base64.b64encode('c')}]}])
    result = translator.transform_outgoing(result, None)
    assert (result and result == son)
def test_DBController():
    testColName = 'tagTestController'
    dbController = DBController('localhost', 27017, 'test', 'test', '1')
    result = dbController.drop(testColName)
    assert result
    result, cnt = dbController.count(testColName)
    assert (result and cnt == 0)
    doc = {'a':1}
    result = dbController.insert(testColName, doc)
    assert result
    result, recs = dbController.find(testColName)
    assert (result and len(recs) == 1)
    rec = recs[0]
#    del rec['_id']
#    print 'rec = %s\r\ndoc = %s'%(rec, doc)
    assert (rec == doc)
    spec = {'a':1}
    updateDoc = {'a':2}
    updateDocWithModifier = {'$set':updateDoc}
    result = dbController.update(testColName, spec, updateDocWithModifier)
    assert result
    result, recs = dbController.find(testColName)
    assert (result and len(recs) == 1)
    rec = recs[0]
    del rec['_id']
#    print 'rec = %s\r\nupdateDoc = %s'%(rec, updateDoc)
    assert (rec == updateDoc)
    result = dbController.remove(testColName)
    assert result
    result, recs = dbController.find(testColName)
    assert (result and recs == [])
    saveDoc = {'b':3}
    result = dbController.save(testColName, saveDoc)
    assert result
    result, recs = dbController.find(testColName)
    assert (result and len(recs) == 1)
    rec = recs[0]
#    del rec['_id']
    assert (rec == saveDoc)
def test():
    test_seq()
    test_StringManipulator()
    test_DBController()
    print 'test ok!'
if __name__ == '__main__':
    test()
Tool/WebCenter/DoubleBill/lib/ReadConfig.py
New file
@@ -0,0 +1,74 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo:
#
# @author: Alee
# @date 2018-6-5 下午08:20:53
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
import ConfigParser
class ReadConfig():
    def __init__(self, filePath):
        self.__config = ConfigParser.ConfigParser()
        self.__config.read(filePath)
    def GetValue(self, section, option, default=None, isThrowException=False):
        try:
            return self.__config.get(section, option);
        except Exception, err:
            if not isThrowException:
                return default;
            raise Exception, "Error:配置问题,%s"%err;
    get = GetValue;
    def GetInt(self, section, option, default = 0, isThrowException=False):
        try:
            return self.__config.getint(section, option);
        except Exception, err:
            if not isThrowException:
                return default;
            raise Exception, "Error:配置问题,%s"%err;
    getint = GetInt;
    def GetBoolean(self, section, option, default = False):
        try:
            return self.__config.getboolean(section, option);
        except ValueError:
            default = str(default).lower();
            if default not in self.__config._boolean_states:
                return False;
            else:
                return self.__config._boolean_states[default];
    getboolean = GetBoolean;
    def HasSection(self, section):
        return self.__config.has_section(section)
    def HasOption(self, section, option):
        return self.__config.has_option(section, option)
#===============================================================================
# ## 读取Eval的值
# def GetEvalConfig(path):
#    with open(path, "r") as file:
#        content = file.read()
#        try:
#            value = eval(content)
#        except:
#            value = None
#
#    return value
#===============================================================================
Tool/WebCenter/DoubleBill/lib/TimeRotatingPathFileHandler.py
New file
@@ -0,0 +1,155 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo:
#
# @author: Alee
# @date 2018-7-18 上午11:40:53
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
#根据时间切换目录和文件的文件处理器
from logging.handlers import *
class TimeRotatingPathFileHandler(TimedRotatingFileHandler):
    def __init__(self, root, filename, when = 'h', interval = 1, backupCount = 0, encoding = None, delay = False, utc = False):
        #创建输出目录数
        t = int(time.time())
        if utc:
            timeTup = time.gmtime(t)
        else:
            timeTup = time.localtime(t)
        year = timeTup[0]
        month = timeTup[1]
        day = timeTup[2]
        self.root = root
        self.filename = filename
        self.baseFilename = self.getBaseFileName(self.root, year, month, day, self.filename)
        #print 'baseFileName = %s'%self.baseFilename
        filepath = os.path.dirname(self.baseFilename)
        self.ensurePath(filepath)
        #改变当前工作目录
        #if not (os.getcwd() == filepath):
        #    os.chdir(filepath)
        TimedRotatingFileHandler.__init__(self, self.baseFilename, when, interval, backupCount, encoding, delay, utc)
        #self.suffix = ''#不指定后缀
    def getBaseFileName(self, root, year, month, day, filename):
        filenameWithoutExt = filename.split('.')[0]
        return os.path.join(root, '%04d-%02d\\%s\\%02d\\%s'%(year, month, filenameWithoutExt, day, filename))
    def ensurePath(self, filepath):
        if not os.path.exists(filepath):
            os.makedirs(filepath)
    def doRollover(self):
        lastRolloverTime = self.rolloverAt
        #TimedRotatingFileHandler.doRollover(self)
        if self.stream:
            self.stream.close()
            self.stream = None
        #获取上一次切换的时间
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
        filenameTuple = self.filename.split('.')
        filename = ''
        if len(filenameTuple) == 1:
            filename = '%s-%s'%(filenameTuple[0], time.strftime(self.suffix, timeTuple))
        else:
            filename = '%s-%s.%s'%(filenameTuple[0], time.strftime(self.suffix, timeTuple), filenameTuple[len(filenameTuple) - 1])
        dfn = os.path.join(self.root, '%04d-%02d\\%s\\%02d\\%s'%(timeTuple[0], timeTuple[1], filenameTuple[0], timeTuple[2], filename))
        #dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
        if os.path.exists(dfn):
            os.remove(dfn)
#        print 'dfn = %s baseFilename = %s'%(dfn, self.baseFilename)
        #可能由于改系统时间或其他人为原因造成文件找不到
        if os.path.exists(self.baseFilename):
            os.rename(self.baseFilename, dfn)
        if self.backupCount > 0:
            # find the oldest log file and delete it
            #s = glob.glob(self.baseFilename + ".20*")
            #if len(s) > self.backupCount:
            #    s.sort()
            #    os.remove(s[0])
            for s in self.getFilesToDelete():
                os.remove(s)
        currentTime = int(time.time())
        newRolloverAt = self.computeRollover(currentTime)
        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval
        #If DST changes and midnight or weekly rollover, adjust for this.
        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
            dstNow = time.localtime(currentTime)[-1]
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
                    newRolloverAt = newRolloverAt - 3600
                else:           # DST bows out before next rollover, so we need to add an hour
                    newRolloverAt = newRolloverAt + 3600
        self.rolloverAt = newRolloverAt
        #判断是否需要切换文件夹
        nextRolloverTime = self.rolloverAt
        if self.utc:
            lastRolloverTimeTup = time.gmtime(lastRolloverTime)
            nextRolloverTimeTup = time.gmtime(nextRolloverTime)
        else:
            lastRolloverTimeTup = time.localtime(lastRolloverTime)
            nextRolloverTimeTup = time.localtime(nextRolloverTime)
        lastRolloverYear = lastRolloverTimeTup[0]
        lastRolloverMonth = lastRolloverTimeTup[1]
        lastRolloverDay = lastRolloverTimeTup[2]
        nextRolloverYear = nextRolloverTimeTup[0]
        nextRolloverMonth = nextRolloverTimeTup[1]
        nextRolloverDay = nextRolloverTimeTup[2]
        if lastRolloverYear != nextRolloverYear or lastRolloverMonth != nextRolloverMonth or lastRolloverDay != nextRolloverDay:
            #年或月改变,更换文件夹
            self.baseFilename = self.getBaseFileName(self.root, nextRolloverYear, nextRolloverMonth, nextRolloverDay, self.filename)
#            print 'need to rollove path:%s-%s -> %s-%s'%(lastRolloverYear, lastRolloverMonth,
#                                                         nextRolloverYear, nextRolloverMonth)
            filepath = os.path.dirname(self.baseFilename)
            self.ensurePath(filepath)
        else:
            pass
        self.mode = 'w'
        self.stream = self._open()
def test():
    import logging
    mylogger = logging.getLogger('test')
    mylogger.setLevel(logging.DEBUG)
    hdlr = TimeRotatingPathFileHandler('d:\\ServerLog\\', 'AD.txt')
    fs = '%(asctime)s\t%(levelname)-8s\t%(message)s'
    dfs = '%Y-%m-%dT%H:%M:%S'
    fmt = logging.Formatter(fs, dfs)
    hdlr.setLevel(logging.DEBUG)
    hdlr.setFormatter(fmt)
    mylogger.addHandler(hdlr)
#    mylogger.info('test')
#    os.system('pause')
    exit = False
    cnt = 0
    lastTime = time.time()
    while not exit:
        curTime = time.time()
        if curTime - lastTime >= 60:
            lastTime = curTime
            mylogger.info('test')
if __name__ == "__main__":
    test()
Tool/WebCenter/DoubleBill/lib/__init__.py
Tool/WebCenter/DoubleBill/lib/mylog.py
New file
@@ -0,0 +1,158 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo:
#
# @author: Alee
# @date 2018-7-18 上午11:40:23
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------\
import logging
from time import localtime
import TimeRotatingPathFileHandler
import CommFunc
__gLogger = None
def InitLog( LogPath, LogName, printToConsole = True, isDebug = True, mode = 'H' ):
    global __gLogger
    logLevel = logging.INFO
    if isDebug:
        logLevel = logging.DEBUG
    #设置日志的过滤等级
    __gLogger = logging.getLogger(LogName)
    __gLogger.setLevel(logLevel)
    hdlr = TimeRotatingPathFileHandler.TimeRotatingPathFileHandler(LogPath, LogName, mode)
    fs = '%(asctime)s\t%(levelname)-8s\t%(message)s'
    dfs = '%Y-%m-%dT%H:%M:%S'
    fmt = logging.Formatter(fs, dfs)
    hdlr.suffix = "%Y-%m-%d_%H-%M-%S"
    hdlr.setLevel(logLevel)
    hdlr.setFormatter(fmt)
    __gLogger.addHandler(hdlr)
    if printToConsole:
        console = logging.StreamHandler()
        console.setFormatter(fmt)
        __gLogger.addHandler(console)
        console.setLevel(logLevel)
__WARN_COUNT = 0
__ERR_COUNT = 0
__FATAL_COUNT = 0
__LastWarnInfo = ""
__LastWarnTime = ""
__LastErrInfo = ""
__LastErrTime = ""
__LastFatalInfo = ""
__LastFatalTime = ""
def GetLastWarnInfo():
    global __LastWarnInfo
    return __LastWarnInfo
def GetLastWarnTime():
    global __LastWarnTime
    return __LastWarnTime
def GetLastErrInfo():
    global __LastErrInfo
    return __LastErrInfo
def GetLastErrTime():
    global __LastErrTime
    return __LastErrTime
def GetLastFatalInfo():
    global __LastFatalInfo
    return __LastFatalInfo
def GetLastFatalTime():
    global __LastFatalTime
    return __LastFatalTime
def Get_Warn_Count():
    global __WARN_COUNT
    return __WARN_COUNT
def Get_Err_Count():
    global __ERR_COUNT
    return __ERR_COUNT
def Get_Fatal_Count():
    global __FATAL_COUNT
    return __FATAL_COUNT
def debug(msg):
    global __gLogger
    __gLogger.debug(msg)
def info(msg):
    global __gLogger
    __gLogger.info(msg)
def warn(msg):
    global __WARN_COUNT
    global __LastWarnInfo
    global __LastWarnTime
    global __gLogger
    __WARN_COUNT += 1
    __LastWarnInfo = msg
    __LastWarnTime = CommFunc.GetCurrentDataTimeStr()
    __gLogger.warning(msg)
__ErrInfoList = []
__OnErr = None
def OnErr(onErr):
    global __OnErr
    __OnErr = onErr
def error(msg):
    global __ERR_COUNT
    global __LastErrInfo
    global __LastErrTime
    global __gLogger
    global __ErrInfoList
    global __OnErr
    __ERR_COUNT += 1
    __LastErrInfo = msg
    __LastErrTime = CommFunc.GetCurrentDataTimeStr()
    if msg not in __ErrInfoList:
        __ErrInfoList.append(msg)
        if __OnErr:
            errInfo = ""
            for info in __ErrInfoList:
                errInfo += "%s\r\n"%info
            __OnErr(errInfo[:-2])
    __gLogger.error(msg)
def fatal(msg):
    global __FATAL_COUNT
    global __LastFatalInfo
    global __LastFatalTime
    global __gLogger
    __FATAL_COUNT += 1
    __LastFatalInfo = msg
    __LastFatalTime = CommFunc.GetCurrentDataTimeStr()
    __gLogger.critical(msg)
def test():
    import os
    InitLog(os.getcwd(), "AD")
    info('test')
if __name__ == '__main__':
    test()
Tool/WebCenter/DoubleBill/main.py
New file
@@ -0,0 +1,48 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo: 渠道删档测试的充值返利
#
# @author: Alee
# @date 2019-1-22 上午11:40:21
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
#需要安装第三方库
#waitress-1.1.0.tar.gz
#requests-2.18.4.tar.gz
#---------------------------------------------------------------------
import webapp
from bottle import run
from lib import mylog
import time
import os
import datetime
Def_Debug = True
# 测试步骤 1. 双击DoubleBillTool.py 导入数据Bill.txt, 可配测试账号
# 2. PHP增加普通GM命令 ,GMT_AllDoubleBill,GMT_QDFLDoubleBill
# 2. 登录有充值的账号,即可获得第一天返利,
# 3. 后续天,在线切换地图或者登录即可获得返利邮件
#
#
#
#center.secondworld.net.cn
def main():
    time.sleep(1)
    os.system("title DoubleBill-%s"%datetime.datetime.today())
    mylog.InitLog(r".\ServerLog", "DoubleBill.txt", False, Def_Debug)
    CenterPort = 53004  # 端口原头条SDK使用已废弃
    run(host='0.0.0.0', port=CenterPort, app=webapp.myapp, server='waitress')
    return
if __name__ == '__main__':
    main()
Tool/WebCenter/DoubleBill/webapp.py
New file
@@ -0,0 +1,215 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
##@package
#
# @todo:
#
# @author: Alee
# @date 2019-1-22 上午11:50:11
# @version 1.0
#
# @note:
#
#---------------------------------------------------------------------
from bottle import Bottle, request
import md5
import urllib2
import urllib
import json
from lib import mylog
import DoubleBillDB
myapp = Bottle()
DoubleBillColName = 'tagDoubleBill'
GMPort = 80
@myapp.route('/DoublieBill.php')
def OnDoubleBill():
    # 玩家登录从服务器请求兑换返利,必须记录兑换结果,用于复查;通过访问IP,查找GM通道返回结果30001
    # 参数:玩家账号,查询是否有充值返利
    # 返回1:无充值,2:已兑换(只能一个服),其他额度为仙玉
    # 数据库字段 渠道SpID 账号AccID 仙玉Gold 兑换所在服ServerID
    dataDict = request.GET
    gameAccID = dataDict.get("AccID", "")     # 运营提供的APPID,即渠道
    if not gameAccID:
        print "accID Error", gameAccID
        return
    try:
        accID, spID, sid = gameAccID.split("@")
    except:
        print "accID Error", gameAccID
        return
    if not sid:
        return
    dbController = DoubleBillDB.GetDBEventCon()
    if not dbController:
        # 无法获取数据库
        mylog.debug("no dbController")
        return
    result, data = dbController.find(DoubleBillColName, {"SpID":spID, "AccID":accID})
    if not data:
        # 无记录不能领取,GM返回1, 减少反复查询
        SendGm(gameAccID, 1)
        return
    rec = data[0]
    if not rec["Gold"]:
        # 无仙玉
        return
    if rec["ServerID"]:
        # 已领取,GM返回2, 减少反复查询
        SendGm(gameAccID, 2)
        return
    updateDoc = {"SpID":spID, "AccID":accID, "Gold":rec["Gold"], "ServerID":sid}
    dbController.update(DoubleBillColName, {"SpID":spID, "AccID":accID}, updateDoc)
    mylog.info("OnDoubleBill:%s-%s"%(gameAccID, updateDoc))
    SendGm(gameAccID, rec["Gold"])
    return
def SendGm(gameAccID, dbState):
    try:
        serverIP = request.environ.get("REMOTE_ADDR", "0.0.0.0")
        # GM推送地址
        #GMToolPage = http://s1.yhlz.09ge.com:30001/Server/Tool.php
        gmurl = "http://%s:%s/Server/Tool.php"%(serverIP, GMPort)
        gmkey = "Y25GVFoyOVFjbWtyTDJJckt5OU1OQ3RtUFQxPV"
        if not gmkey or not gmurl:
            return
        pack_data = {}
        pack_data["AccID"] = gameAccID
        # 返回1:无充值,2:已兑换(只能一个服),其他额度为仙玉
        pack_data["GoldState"] = str(dbState)
        pack_data["pack_type"] = "GMT_QDFLDoubleBill"
        pack_data["key"] = gmkey;
        pack_data['coding'] = "utf8"
        #使用key加密
        pack_data_dict = json.dumps(pack_data)
        mylog.debug("OnDoubleBill SendGm:%s-%s"%(gmurl, pack_data_dict))
        sign = md5.md5(pack_data_dict+gmkey).hexdigest()
        post = {}
        post['pack'] = pack_data_dict;
        post['sign'] = sign;
        result = urllib2.urlopen(gmurl, urllib.urlencode(post), 10)
        content = result.read()
        result.close()
        mylog.info("推送结果 GMT_QDFLDoubleBill:%s"%(content))
        return content
    except Exception, e:
        mylog.debug("gm error %s"%e)
    return
# 查询所有的数据,只在第一张地图处理,缓存避免请求过于频繁
@myapp.route('/QueryAllDoubleBill.php')
def QueryAllDoubleBill():
    dataDict = request.GET
    checkInfo = dataDict.get("ccccc", "")
    if not checkInfo:
        return
    if checkInfo != "fanggongji":
        return
    dbController = DoubleBillDB.GetDBEventCon()
    if not dbController:
        # 无法获取数据库
        mylog.debug("no dbController")
        return
    # 返回未领取的
    result, data = dbController.find(DoubleBillColName, {"ServerID":""})
    if not data:
        return
    recDict = {}
    for rec in data:
        spID = rec["SpID"]
        if spID not in recDict:
            recDict[spID] = [rec["AccID"]]
        else:
            recDict[spID].append(rec["AccID"])
    if not recDict:
        return
    try:
        serverIP = request.environ.get("REMOTE_ADDR", "0.0.0.0")
        # GM推送地址
        #GMToolPage = http://s1.yhlz.09ge.com:30001/Server/Tool.php
        gmurl = "http://%s:%s/Server/Tool.php"%(serverIP, GMPort)
        gmkey = "Y25GVFoyOVFjbWtyTDJJckt5OU1OQ3RtUFQxPV"
        if not gmkey or not gmurl:
            return
        mylog.debug("SendGm:%s"%gmurl)
        pack_data = {}
        pack_data["tomap"] = json.dumps(recDict)
        pack_data["pack_type"] = "GMT_AllDoubleBill"
        pack_data["key"] = gmkey;
        pack_data['coding'] = "utf8"
        #使用key加密
        pack_data_dict = json.dumps(pack_data)
        mylog.debug("QueryAllDoubleBill SendGm:%s-%s"%(gmurl, pack_data_dict))
        sign = md5.md5(pack_data_dict+gmkey).hexdigest()
        post = {}
        post['pack'] = pack_data_dict;
        post['sign'] = sign;
        result = urllib2.urlopen(gmurl, urllib.urlencode(post), 10)
        result.close()
    except Exception, e:
        mylog.debug("gm error %s"%e)
# 1.查询
@myapp.route('/QueryDoubleBill.php')
def QueryDoubleBill():
    # 玩家登录从服务器请求兑换返利,必须记录兑换结果,用于复查;通过访问IP,查找GM通道返回结果30001
    # 参数:玩家账号,查询是否有充值返利
    # 返回1:无充值,2:已兑换(只能一个服),其他额度为仙玉
    # 数据库字段 渠道SpID 账号AccID 仙玉Gold 兑换所在服ServerID
    dataDict = request.GET
    gameAccID = dataDict.get("AccID", "")     # 运营提供的APPID,即渠道
    if not gameAccID:
        print "accID Error", gameAccID
        return
    try:
        accID, spID, sid = gameAccID.split("@")
    except:
        print "accID Error", gameAccID
        return
    if not sid:
        return
    dbController = DoubleBillDB.GetDBEventCon()
    if not dbController:
        # 无法获取数据库
        mylog.debug("no dbController")
        return
    result, data = dbController.find(DoubleBillColName, {"SpID":spID, "AccID":accID})
    if not data:
        # 无记录不能领取,GM返回1, 减少反复查询
        return
    return data[0]