utils.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. # coding=utf-8
  2. import time
  3. import logging
  4. import xmltodict
  5. from django.http import HttpResponse
  6. from typing import TYPE_CHECKING
  7. from apps.web.user.models import MoniUser
  8. from apps.web.utils import concat_user_center_entry_url, concat_user_login_entry_url
  9. if TYPE_CHECKING:
  10. from apps.web.dealer.models import Dealer
  11. from apps.web.agent.models import MoniApp
  12. logger = logging.getLogger(__name__)
  13. class UserConsumeFilter(object):
  14. """
  15. 用户端的消费信息显示过滤器
  16. 用于过滤掉某些 用户的敏感信息
  17. """
  18. _DEFAULT_DATA = [
  19. 'deviceStatTime',
  20. 'reason',
  21. 'deviceFinishedTime',
  22. 'elec',
  23. 'power',
  24. 'orderStatus',
  25. 'consumeType',
  26. 'coins',
  27. 'amount',
  28. 'spendMoney',
  29. 'refundedMoney',
  30. 'cardOrderNo',
  31. 'vCardOrderNo',
  32. 'cardNo',
  33. 'errorDesc',
  34. 'feeType',
  35. 'cardDeduct',
  36. 'vCardDeduct',
  37. 'billTime',
  38. 'batteryType',
  39. 'voltage',
  40. 'oldBatteryImei',
  41. 'newBatteryImei',
  42. 'pw',
  43. ]
  44. def __init__(self, dealer, consumeDict): # type:(Dealer, dict) -> None
  45. self._supportFields = dealer.supportedConsumptionShow or UserConsumeFilter._DEFAULT_DATA
  46. self._consumeDict = consumeDict.copy()
  47. @classmethod
  48. def default_filter(cls):
  49. return cls._DEFAULT_DATA
  50. def filter(self):
  51. """
  52. 重新赋值 并过滤掉显示为空的部分
  53. """
  54. # 默认不显示
  55. self._consumeDict["needTime"] = self.needTime
  56. self._consumeDict["usedTime"] = self.usedTime
  57. self._consumeDict["leftTime"] = self.leftTime
  58. self._consumeDict["needElec"] = self.needElec
  59. self._consumeDict["elec"] = self.usedElec
  60. self._consumeDict["leftElec"] = self.leftElec
  61. # 默认需要显示
  62. self._consumeDict['deviceStatTime'] = self.deviceStatTime
  63. self._consumeDict['reason'] = self.reason
  64. self._consumeDict['deviceFinishedTime'] = self.deviceFinishedTime
  65. self._consumeDict['elec'] = self.elec
  66. self._consumeDict['orderStatus'] = self.orderStatus
  67. self._consumeDict['consumeType'] = self.consumeType
  68. self._consumeDict['coins'] = self.coins
  69. self._consumeDict['amount'] = self.amount
  70. self._consumeDict['spendMoney'] = self.spendMoney
  71. self._consumeDict['refundedMoney'] = self.refundedMoney
  72. self._consumeDict['cardOrderNo'] = self.cardOrderNo
  73. self._consumeDict['vCardOrderNo'] = self.vCardOrderNo
  74. self._consumeDict['cardNo'] = self.cardNo
  75. self._consumeDict['errorDesc'] = self.errorDesc
  76. self._consumeDict['feeType'] = self.feeType
  77. self._consumeDict['cardDeduct'] = self.cardDeduct
  78. self._consumeDict['vCardDeduct'] = self.vCardDeduct
  79. self._consumeDict['billTime'] = self.billTime
  80. self._consumeDict['batteryType'] = self.batteryType
  81. self._consumeDict['voltage'] = self.voltage
  82. self._consumeDict['oldBatteryImei'] = self.oldBatteryImei
  83. self._consumeDict['newBatteryImei'] = self.newBatteryImei
  84. self._consumeDict['pw'] = self.pw
  85. consumeDict = dict()
  86. for _k, _v in self._consumeDict.items():
  87. if _v is None:
  88. continue
  89. consumeDict[_k] = _v
  90. return consumeDict
  91. @property
  92. def needTime(self):
  93. if "needTime" in self._supportFields and "needTime" in self._consumeDict:
  94. return self._consumeDict["needTime"]
  95. @property
  96. def usedTime(self):
  97. if "usedTime" in self._consumeDict:
  98. usedTime = self._consumeDict["usedTime"]
  99. elif "duration" in self._consumeDict:
  100. usedTime = self._consumeDict["duration"]
  101. else:
  102. usedTime = None
  103. if "usedTime" in self._supportFields:
  104. return usedTime
  105. @property
  106. def leftTime(self):
  107. if "leftTime" in self._supportFields and "leftTime" in self._consumeDict:
  108. return self._consumeDict["leftTime"]
  109. @property
  110. def needElec(self):
  111. if "needElec" in self._supportFields and "needElec" in self._consumeDict:
  112. return self._consumeDict["needElec"]
  113. @property
  114. def usedElec(self):
  115. if "usedElec" in self._consumeDict:
  116. usedElec = self._consumeDict["usedElec"]
  117. elif "elec" in self._consumeDict:
  118. usedElec = self._consumeDict["elec"]
  119. else:
  120. usedElec = None
  121. if "usedElec" in self._supportFields:
  122. return usedElec
  123. @property
  124. def leftElec(self):
  125. if "leftElec" in self._supportFields and "leftElec" in self._consumeDict:
  126. return self._consumeDict["leftElec"]
  127. @property
  128. def deviceStatTime(self):
  129. if 'deviceStatTime' in self._supportFields and 'deviceStatTime' in self._consumeDict:
  130. return self._consumeDict['deviceStatTime']
  131. @property
  132. def reason(self):
  133. if 'reason' in self._supportFields and 'reason' in self._consumeDict:
  134. return self._consumeDict['reason']
  135. @property
  136. def deviceFinishedTime(self):
  137. if 'deviceFinishedTime' in self._supportFields and 'deviceFinishedTime' in self._consumeDict:
  138. return self._consumeDict['deviceFinishedTime']
  139. @property
  140. def elec(self):
  141. if 'elec' in self._supportFields and 'elec' in self._consumeDict:
  142. return self._consumeDict['elec']
  143. @property
  144. def orderStatus(self):
  145. """
  146. 订单状态必须返回, 不在判断模板
  147. :return:
  148. """
  149. if 'orderStatus' in self._consumeDict:
  150. return self._consumeDict['orderStatus']
  151. @property
  152. def consumeType(self):
  153. if 'consumeType' in self._supportFields and 'consumeType' in self._consumeDict:
  154. return self._consumeDict['consumeType']
  155. @property
  156. def coins(self):
  157. if 'coins' in self._supportFields and 'coins' in self._consumeDict:
  158. return self._consumeDict['coins']
  159. @property
  160. def amount(self):
  161. if 'amount' in self._supportFields and 'amount' in self._consumeDict:
  162. return self._consumeDict['amount']
  163. @property
  164. def spendMoney(self):
  165. if 'spendMoney' in self._supportFields and 'spendMoney' in self._consumeDict:
  166. return self._consumeDict['spendMoney']
  167. @property
  168. def refundedMoney(self):
  169. if 'refundedMoney' in self._supportFields and 'refundedMoney' in self._consumeDict:
  170. return self._consumeDict['refundedMoney']
  171. @property
  172. def cardOrderNo(self):
  173. if 'cardOrderNo' in self._supportFields and 'cardOrderNo' in self._consumeDict:
  174. return self._consumeDict['cardOrderNo']
  175. @property
  176. def vCardOrderNo(self):
  177. if 'vCardOrderNo' in self._supportFields and 'vCardOrderNo' in self._consumeDict:
  178. return self._consumeDict['vCardOrderNo']
  179. @property
  180. def cardNo(self):
  181. if 'cardNo' in self._supportFields and 'cardNo' in self._consumeDict:
  182. return self._consumeDict['cardNo']
  183. @property
  184. def errorDesc(self):
  185. if 'errorDesc' in self._supportFields and 'errorDesc' in self._consumeDict:
  186. return self._consumeDict['errorDesc']
  187. @property
  188. def feeType(self):
  189. if 'feeType' in self._supportFields and 'feeType' in self._consumeDict:
  190. return self._consumeDict['feeType']
  191. @property
  192. def cardDeduct(self):
  193. if 'cardDeduct' in self._supportFields and 'cardDeduct' in self._consumeDict:
  194. return self._consumeDict['cardDeduct']
  195. @property
  196. def vCardDeduct(self):
  197. if 'vCardDeduct' in self._supportFields and 'vCardDeduct' in self._consumeDict:
  198. return self._consumeDict['vCardDeduct']
  199. @property
  200. def billTime(self):
  201. if 'billTime' in self._supportFields and 'billTime' in self._consumeDict:
  202. return self._consumeDict['billTime']
  203. @property
  204. def batteryType(self):
  205. if 'batteryType' in self._supportFields and 'batteryType' in self._consumeDict:
  206. return self._consumeDict['batteryType']
  207. @property
  208. def voltage(self):
  209. if 'voltage' in self._supportFields and 'voltage' in self._consumeDict:
  210. return self._consumeDict['voltage']
  211. @property
  212. def oldBatteryImei(self):
  213. if 'oldBatteryImei' in self._supportFields and 'oldBatteryImei' in self._consumeDict:
  214. return self._consumeDict['oldBatteryImei']
  215. @property
  216. def newBatteryImei(self):
  217. if 'newBatteryImei' in self._supportFields and 'newBatteryImei' in self._consumeDict:
  218. return self._consumeDict['newBatteryImei']
  219. @property
  220. def pw(self):
  221. if 'pw' in self._supportFields and 'pw' in self._consumeDict:
  222. return self._consumeDict['pw']
  223. @property
  224. def power(self):
  225. if 'power' in self._supportFields and 'power' in self._consumeDict:
  226. return self._consumeDict['power']
  227. class WechatMessage(object):
  228. """
  229. 微信消息总成
  230. """
  231. def __init__(self, source):
  232. self._source = source
  233. self._data = self.parse_xml(xmlData=source)
  234. self._successor = None
  235. def __str__(self):
  236. return self._data.__str__()
  237. @property
  238. def isEvent(self):
  239. return self._data["MsgType"] == "event"
  240. @property
  241. def isSubscribeEvent(self):
  242. return self._data["Event"] == "subscribe"
  243. @property
  244. def isUnSubscribeEvent(self):
  245. return self._data["Event"] == "unsubscribe"
  246. @property
  247. def isMenuEvent(self):
  248. return self._data["Event"] == "VIEW"
  249. @property
  250. def isScanEvent(self):
  251. return self._data["Event"] == "SCAN"
  252. @property
  253. def isText(self):
  254. return self._data["MsgType"] == "text"
  255. @property
  256. def eventKey(self):
  257. if self.isEvent and self._data["EventKey"]:
  258. return self._data["EventKey"].replace("qrscene_", "")
  259. return ""
  260. @staticmethod
  261. def parse_xml(xmlData):
  262. payload = xmltodict.parse(xmlData)['xml']
  263. return payload
  264. @staticmethod
  265. def un_parse_xml(xmlDict):
  266. return xmltodict.unparse(xmlDict)
  267. @property
  268. def fromUser(self):
  269. return self._data["FromUserName"]
  270. @property
  271. def toUser(self):
  272. return self._data["ToUserName"]
  273. @property
  274. def receiveTime(self):
  275. return self._data["CreateTime"]
  276. def get_text_response(self, context):
  277. xmlDict = {
  278. "xml" : {
  279. "ToUserName": self.fromUser,
  280. "FromUserName": self.toUser,
  281. "CreateTime": int(time.time()),
  282. "MsgType": "text",
  283. "Content": context
  284. }
  285. }
  286. return HttpResponse(self.un_parse_xml(xmlDict))
  287. class MessageHandler(object):
  288. def __init__(self, message, app): # type:(WechatMessage, MoniApp) -> None
  289. self._message = message
  290. self._app = app
  291. @classmethod
  292. def defaultResponse(cls):
  293. return HttpResponse()
  294. def handle(self):
  295. return self.defaultResponse()
  296. def get_text_response(self, content):
  297. xmlDict = {
  298. "xml" : {
  299. "ToUserName": self._message.fromUser,
  300. "FromUserName": self._message.toUser,
  301. "CreateTime": int(time.time()),
  302. "MsgType": "text",
  303. "Content": content
  304. }
  305. }
  306. return HttpResponse(self._message.un_parse_xml(xmlDict))
  307. def get_news_response(self, linkUrl, imageUrl, content=None, title=None):
  308. content = content or u"🔋🔋🔋点击开始使用"
  309. title = title or u"点击使用"
  310. xmlDict = {
  311. "xml" : {
  312. "ToUserName": self._message.fromUser,
  313. "FromUserName": self._message.toUser,
  314. "CreateTime": int(time.time()),
  315. "MsgType": "news",
  316. "ArticleCount": 1,
  317. "Articles": {
  318. "item": {
  319. "Title": title,
  320. "Description": content,
  321. "PicUrl": imageUrl,
  322. "Url": linkUrl
  323. }
  324. }
  325. }
  326. }
  327. return HttpResponse(self._message.un_parse_xml(xmlDict))
  328. class WechatText(MessageHandler):
  329. """
  330. 文本类消息
  331. # TODO 智能机器人待添加
  332. """
  333. def handle(self):
  334. logger.info("{} handle event, event = {}".format(self.__class__.__name__, self._message))
  335. return self.defaultResponse()
  336. class WechatMenu(MessageHandler):
  337. pass
  338. class WechatSubscribe(MessageHandler):
  339. """
  340. 微信关注事件
  341. """
  342. def handle(self):
  343. """
  344. 微信关注一共分为两种 第一种 是扫描带参数二维码的 第二种是不带参数二维码的
  345. """
  346. eventKey = self._message.eventKey
  347. if not eventKey or not isinstance(eventKey, (str, unicode)):
  348. content = "您好,欢迎关注{}".format(self._app.appName)
  349. openId, logicalCode, productAgentId, chargeIndex = "", "", "", ""
  350. response = self.get_text_response(content)
  351. else:
  352. productAgentId, openId, logicalCode, chargeIndex = eventKey.split(":")
  353. title = "您好,欢迎关注 {}".format(self._app.appName)
  354. if logicalCode:
  355. url = concat_user_login_entry_url(l=logicalCode, chargeIndex=chargeIndex)
  356. else:
  357. url = concat_user_center_entry_url(productAgentId)
  358. response = self.get_news_response(linkUrl=url, imageUrl="", title=title)
  359. # 创建一条关联记录
  360. MoniUser.get_or_create(
  361. moniOpenId=self._message.fromUser, moniAppId=self._app.appid,
  362. openId=openId, subLogicalCode=logicalCode, subAgentId=productAgentId, isSubscribe=True
  363. )
  364. self._app.__class__.subscribe(self._app)
  365. return response
  366. class WechatUnSubscribe(MessageHandler):
  367. """
  368. 微信取关事件
  369. """
  370. def handle(self):
  371. moniOpenId, moniAppId = self._message.fromUser, self._app.appid
  372. MoniUser.get_or_delete(moniAppId=moniAppId, moniOpenId=moniOpenId)
  373. self._app.__class__.unSubscribe(self._app)
  374. return super(WechatUnSubscribe, self).handle()
  375. class WechatScanEvent(WechatSubscribe):
  376. """
  377. 扫码消息
  378. """
  379. pass