# coding=utf-8 import time import logging import xmltodict from django.http import HttpResponse from typing import TYPE_CHECKING from apps.web.user.models import MoniUser from apps.web.utils import concat_user_center_entry_url, concat_user_login_entry_url if TYPE_CHECKING: from apps.web.dealer.models import Dealer from apps.web.agent.models import MoniApp logger = logging.getLogger(__name__) class UserConsumeFilter(object): """ 用户端的消费信息显示过滤器 用于过滤掉某些 用户的敏感信息 """ _DEFAULT_DATA = [ 'deviceStatTime', 'reason', 'deviceFinishedTime', 'elec', 'power', 'orderStatus', 'consumeType', 'coins', 'amount', 'spendMoney', 'refundedMoney', 'cardOrderNo', 'vCardOrderNo', 'cardNo', 'errorDesc', 'feeType', 'cardDeduct', 'vCardDeduct', 'billTime', 'batteryType', 'voltage', 'oldBatteryImei', 'newBatteryImei', 'pw', ] def __init__(self, dealer, consumeDict): # type:(Dealer, dict) -> None self._supportFields = dealer.supportedConsumptionShow or UserConsumeFilter._DEFAULT_DATA self._consumeDict = consumeDict.copy() @classmethod def default_filter(cls): return cls._DEFAULT_DATA def filter(self): """ 重新赋值 并过滤掉显示为空的部分 """ # 默认不显示 self._consumeDict["needTime"] = self.needTime self._consumeDict["usedTime"] = self.usedTime self._consumeDict["leftTime"] = self.leftTime self._consumeDict["needElec"] = self.needElec self._consumeDict["elec"] = self.usedElec self._consumeDict["leftElec"] = self.leftElec # 默认需要显示 self._consumeDict['deviceStatTime'] = self.deviceStatTime self._consumeDict['reason'] = self.reason self._consumeDict['deviceFinishedTime'] = self.deviceFinishedTime self._consumeDict['elec'] = self.elec self._consumeDict['orderStatus'] = self.orderStatus self._consumeDict['consumeType'] = self.consumeType self._consumeDict['coins'] = self.coins self._consumeDict['amount'] = self.amount self._consumeDict['spendMoney'] = self.spendMoney self._consumeDict['refundedMoney'] = self.refundedMoney self._consumeDict['cardOrderNo'] = self.cardOrderNo self._consumeDict['vCardOrderNo'] = self.vCardOrderNo self._consumeDict['cardNo'] = self.cardNo self._consumeDict['errorDesc'] = self.errorDesc self._consumeDict['feeType'] = self.feeType self._consumeDict['cardDeduct'] = self.cardDeduct self._consumeDict['vCardDeduct'] = self.vCardDeduct self._consumeDict['billTime'] = self.billTime self._consumeDict['batteryType'] = self.batteryType self._consumeDict['voltage'] = self.voltage self._consumeDict['oldBatteryImei'] = self.oldBatteryImei self._consumeDict['newBatteryImei'] = self.newBatteryImei self._consumeDict['pw'] = self.pw consumeDict = dict() for _k, _v in self._consumeDict.items(): if _v is None: continue consumeDict[_k] = _v return consumeDict @property def needTime(self): if "needTime" in self._supportFields and "needTime" in self._consumeDict: return self._consumeDict["needTime"] @property def usedTime(self): if "usedTime" in self._consumeDict: usedTime = self._consumeDict["usedTime"] elif "duration" in self._consumeDict: usedTime = self._consumeDict["duration"] else: usedTime = None if "usedTime" in self._supportFields: return usedTime @property def leftTime(self): if "leftTime" in self._supportFields and "leftTime" in self._consumeDict: return self._consumeDict["leftTime"] @property def needElec(self): if "needElec" in self._supportFields and "needElec" in self._consumeDict: return self._consumeDict["needElec"] @property def usedElec(self): if "usedElec" in self._consumeDict: usedElec = self._consumeDict["usedElec"] elif "elec" in self._consumeDict: usedElec = self._consumeDict["elec"] else: usedElec = None if "usedElec" in self._supportFields: return usedElec @property def leftElec(self): if "leftElec" in self._supportFields and "leftElec" in self._consumeDict: return self._consumeDict["leftElec"] @property def deviceStatTime(self): if 'deviceStatTime' in self._supportFields and 'deviceStatTime' in self._consumeDict: return self._consumeDict['deviceStatTime'] @property def reason(self): if 'reason' in self._supportFields and 'reason' in self._consumeDict: return self._consumeDict['reason'] @property def deviceFinishedTime(self): if 'deviceFinishedTime' in self._supportFields and 'deviceFinishedTime' in self._consumeDict: return self._consumeDict['deviceFinishedTime'] @property def elec(self): if 'elec' in self._supportFields and 'elec' in self._consumeDict: return self._consumeDict['elec'] @property def orderStatus(self): """ 订单状态必须返回, 不在判断模板 :return: """ if 'orderStatus' in self._consumeDict: return self._consumeDict['orderStatus'] @property def consumeType(self): if 'consumeType' in self._supportFields and 'consumeType' in self._consumeDict: return self._consumeDict['consumeType'] @property def coins(self): if 'coins' in self._supportFields and 'coins' in self._consumeDict: return self._consumeDict['coins'] @property def amount(self): if 'amount' in self._supportFields and 'amount' in self._consumeDict: return self._consumeDict['amount'] @property def spendMoney(self): if 'spendMoney' in self._supportFields and 'spendMoney' in self._consumeDict: return self._consumeDict['spendMoney'] @property def refundedMoney(self): if 'refundedMoney' in self._supportFields and 'refundedMoney' in self._consumeDict: return self._consumeDict['refundedMoney'] @property def cardOrderNo(self): if 'cardOrderNo' in self._supportFields and 'cardOrderNo' in self._consumeDict: return self._consumeDict['cardOrderNo'] @property def vCardOrderNo(self): if 'vCardOrderNo' in self._supportFields and 'vCardOrderNo' in self._consumeDict: return self._consumeDict['vCardOrderNo'] @property def cardNo(self): if 'cardNo' in self._supportFields and 'cardNo' in self._consumeDict: return self._consumeDict['cardNo'] @property def errorDesc(self): if 'errorDesc' in self._supportFields and 'errorDesc' in self._consumeDict: return self._consumeDict['errorDesc'] @property def feeType(self): if 'feeType' in self._supportFields and 'feeType' in self._consumeDict: return self._consumeDict['feeType'] @property def cardDeduct(self): if 'cardDeduct' in self._supportFields and 'cardDeduct' in self._consumeDict: return self._consumeDict['cardDeduct'] @property def vCardDeduct(self): if 'vCardDeduct' in self._supportFields and 'vCardDeduct' in self._consumeDict: return self._consumeDict['vCardDeduct'] @property def billTime(self): if 'billTime' in self._supportFields and 'billTime' in self._consumeDict: return self._consumeDict['billTime'] @property def batteryType(self): if 'batteryType' in self._supportFields and 'batteryType' in self._consumeDict: return self._consumeDict['batteryType'] @property def voltage(self): if 'voltage' in self._supportFields and 'voltage' in self._consumeDict: return self._consumeDict['voltage'] @property def oldBatteryImei(self): if 'oldBatteryImei' in self._supportFields and 'oldBatteryImei' in self._consumeDict: return self._consumeDict['oldBatteryImei'] @property def newBatteryImei(self): if 'newBatteryImei' in self._supportFields and 'newBatteryImei' in self._consumeDict: return self._consumeDict['newBatteryImei'] @property def pw(self): if 'pw' in self._supportFields and 'pw' in self._consumeDict: return self._consumeDict['pw'] @property def power(self): if 'power' in self._supportFields and 'power' in self._consumeDict: return self._consumeDict['power'] class WechatMessage(object): """ 微信消息总成 """ def __init__(self, source): self._source = source self._data = self.parse_xml(xmlData=source) self._successor = None def __str__(self): return self._data.__str__() @property def isEvent(self): return self._data["MsgType"] == "event" @property def isSubscribeEvent(self): return self._data["Event"] == "subscribe" @property def isUnSubscribeEvent(self): return self._data["Event"] == "unsubscribe" @property def isMenuEvent(self): return self._data["Event"] == "VIEW" @property def isScanEvent(self): return self._data["Event"] == "SCAN" @property def isText(self): return self._data["MsgType"] == "text" @property def eventKey(self): if self.isEvent and self._data["EventKey"]: return self._data["EventKey"].replace("qrscene_", "") return "" @staticmethod def parse_xml(xmlData): payload = xmltodict.parse(xmlData)['xml'] return payload @staticmethod def un_parse_xml(xmlDict): return xmltodict.unparse(xmlDict) @property def fromUser(self): return self._data["FromUserName"] @property def toUser(self): return self._data["ToUserName"] @property def receiveTime(self): return self._data["CreateTime"] def get_text_response(self, context): xmlDict = { "xml" : { "ToUserName": self.fromUser, "FromUserName": self.toUser, "CreateTime": int(time.time()), "MsgType": "text", "Content": context } } return HttpResponse(self.un_parse_xml(xmlDict)) class MessageHandler(object): def __init__(self, message, app): # type:(WechatMessage, MoniApp) -> None self._message = message self._app = app @classmethod def defaultResponse(cls): return HttpResponse() def handle(self): return self.defaultResponse() def get_text_response(self, content): xmlDict = { "xml" : { "ToUserName": self._message.fromUser, "FromUserName": self._message.toUser, "CreateTime": int(time.time()), "MsgType": "text", "Content": content } } return HttpResponse(self._message.un_parse_xml(xmlDict)) def get_news_response(self, linkUrl, imageUrl, content=None, title=None): content = content or u"🔋🔋🔋点击开始使用" title = title or u"点击使用" xmlDict = { "xml" : { "ToUserName": self._message.fromUser, "FromUserName": self._message.toUser, "CreateTime": int(time.time()), "MsgType": "news", "ArticleCount": 1, "Articles": { "item": { "Title": title, "Description": content, "PicUrl": imageUrl, "Url": linkUrl } } } } return HttpResponse(self._message.un_parse_xml(xmlDict)) class WechatText(MessageHandler): """ 文本类消息 # TODO 智能机器人待添加 """ def handle(self): logger.info("{} handle event, event = {}".format(self.__class__.__name__, self._message)) return self.defaultResponse() class WechatMenu(MessageHandler): pass class WechatSubscribe(MessageHandler): """ 微信关注事件 """ def handle(self): """ 微信关注一共分为两种 第一种 是扫描带参数二维码的 第二种是不带参数二维码的 """ eventKey = self._message.eventKey if not eventKey or not isinstance(eventKey, (str, unicode)): content = "您好,欢迎关注{}".format(self._app.appName) openId, logicalCode, productAgentId, chargeIndex = "", "", "", "" response = self.get_text_response(content) else: productAgentId, openId, logicalCode, chargeIndex = eventKey.split(":") title = "您好,欢迎关注 {}".format(self._app.appName) if logicalCode: url = concat_user_login_entry_url(l=logicalCode, chargeIndex=chargeIndex) else: url = concat_user_center_entry_url(productAgentId) response = self.get_news_response(linkUrl=url, imageUrl="", title=title) # 创建一条关联记录 MoniUser.get_or_create( moniOpenId=self._message.fromUser, moniAppId=self._app.appid, openId=openId, subLogicalCode=logicalCode, subAgentId=productAgentId, isSubscribe=True ) self._app.__class__.subscribe(self._app) return response class WechatUnSubscribe(MessageHandler): """ 微信取关事件 """ def handle(self): moniOpenId, moniAppId = self._message.fromUser, self._app.appid MoniUser.get_or_delete(moniAppId=moniAppId, moniOpenId=moniOpenId) self._app.__class__.unSubscribe(self._app) return super(WechatUnSubscribe, self).handle() class WechatScanEvent(WechatSubscribe): """ 扫码消息 """ pass