hongzhuo.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  6. from apilib.monetary import VirtualCoin, RMB
  7. from apilib.utils_datetime import to_datetime
  8. from apps.web.constant import Const
  9. from apps.web.device.models import Device, Group
  10. from apps.web.eventer.base import FaultEvent, WorkEvent
  11. from apps.web.eventer import EventBuilder
  12. from apps.web.south_intf.platform import notify_event_to_north
  13. from apps.web.user.models import ServiceProgress, MyUser
  14. from apps.web.user.transaction_deprecated import refund_money
  15. logger = logging.getLogger(__name__)
  16. class builder(EventBuilder):
  17. def __getEvent__(self, device_event):
  18. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  19. if event_data is None or 'cmdCode' not in event_data:
  20. return None
  21. if 'duration' in device_event:
  22. event_data.update({'duration': device_event['duration']})
  23. if event_data['cmdCode'] in ("16", "10"):
  24. return ChargingHongZhuoWorkEvent(self.deviceAdapter, event_data)
  25. if event_data['cmdCode'] == '0A':
  26. return FaultEvent(self.deviceAdapter, event_data)
  27. return None
  28. class ChargingHongZhuoWorkEvent(WorkEvent):
  29. SUCCESS = "01"
  30. FAIL = "00"
  31. def support_playback(self):
  32. return self.event_data['cmdCode'] == '16'
  33. def do(self, **args):
  34. devNo = self.device['devNo']
  35. logger.info('hongzhuo charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
  36. if self.event_data['cmdCode'] == '16':
  37. lineInfo = Device.clear_port_control_cache(devNo, str(self.event_data['port']))
  38. recvTime = to_datetime(self.recvTime)
  39. cardNo = lineInfo.get("cardNo")
  40. # 构建 发向山东省平台的数据
  41. coins = float(lineInfo.get('coins', 0))
  42. if not coins:
  43. logger.info("Cache is missing or Offline card , pass!! ") # 缓存丢失 或者使用离线卡
  44. return
  45. northerDict = {
  46. "elec": self.event_data.get("elec"),
  47. "startTime": lineInfo.get("startTime"),
  48. "spendMoney": round(coins - self.event_data.get("leftMoney", 0),2) if coins > self.event_data.get("leftMoney", 0) else 0
  49. }
  50. # 刷卡启动的结束事件
  51. if cardNo:
  52. try:
  53. card = self.update_card_dealer_and_type(cardNo)
  54. user = MyUser.objects.filter(openId=card.openId, groupId=self.device["groupId"]).first()
  55. consumeDict = {
  56. "chargeIndex": self.event_data.get("portStr"),
  57. "reason": self.event_data.get("reason"),
  58. 'actualNeedTime': lineInfo.get("needTime"),
  59. "duration": self.event_data.get("duration"),
  60. "elec": self.event_data.get("elec")
  61. }
  62. # 设备支持余额回收并且 有余额可以回收
  63. refundMoney = self.event_data.get("leftMoney")
  64. if refundMoney and refundMoney > 0 and self.device.is_auto_refund:
  65. refundMoney = VirtualCoin(refundMoney)
  66. self.refund_money_for_card(refundMoney, str(card.id))
  67. consumeDict.update({
  68. "refundMoney": str(refundMoney)
  69. })
  70. desc = u'您使用的%s号端口充电,卡付款:%s元,给您退款:%s元' % (
  71. self.event_data['port'], lineInfo.get("coins"), refundMoney)
  72. self.notify_user(
  73. user.managerialOpenId if user else '',
  74. 'refund_coins',
  75. **{
  76. 'title': desc,
  77. 'backCount': u'金币:%s' % refundMoney,
  78. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S')
  79. }
  80. )
  81. # 通知用户充电结束
  82. group = Group.get_group(self.device["groupId"])
  83. self.notify_user(
  84. managerialOpenId=user.managerialOpenId if user else "",
  85. templateName="service_complete",
  86. title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}".format(
  87. reason=self.event_data["reason"],
  88. logicalCode=self.device["logicalCode"],
  89. port=self.event_data["port"],
  90. group=group["address"],
  91. ),
  92. service=u"充电桩充电服务",
  93. finishTime=datetime.datetime.strftime(recvTime, "%Y-%m-%d %H:%M:%S"),
  94. remark=u'谢谢您的支持'
  95. )
  96. # 结束充电服务进程,并且累计相关信息
  97. ServiceProgress.update_progress_and_consume_rcd(
  98. self.device["ownerId"],
  99. {
  100. "open_id": card.openId,
  101. "device_imei": self.device["devNo"],
  102. "port": int(self.event_data.get("port")),
  103. "isFinished": False
  104. },
  105. consumeDict
  106. )
  107. except Exception as e:
  108. logger.exception('deal with hongzhuo devNo=%s event e=%s' % (devNo, e))
  109. finally:
  110. logger.info('hongzhuo_notify_to_sd_norther:{}'.format(northerDict))
  111. self.notify_to_sd_norther(portStr=str(self.event_data.get("port")), consumeDict=northerDict)
  112. Device.clear_port_control_cache(devNo, str(self.event_data['port']))
  113. else:
  114. dataDict = dict()
  115. try:
  116. if not lineInfo.has_key('coins'):
  117. return
  118. if 'duration' in self.event_data and self.event_data['duration'] > 0:
  119. usedTime = self.event_data['duration']
  120. else:
  121. if (not lineInfo) or (not lineInfo.has_key('startTime')):
  122. return
  123. startTime = to_datetime(lineInfo['startTime'])
  124. if startTime > recvTime:#如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
  125. usedTime = 0
  126. else:
  127. usedTime = int(round(((recvTime - startTime).total_seconds() / 60.0)))
  128. money = float(lineInfo['coins'])
  129. leftMoney = float(self.event_data['leftMoney'])
  130. if leftMoney > money:
  131. leftMoney = money
  132. workMode = self.event_data['mode']
  133. openId = lineInfo['openId']
  134. user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
  135. if workMode == 2:
  136. # 计算退币金额
  137. backCoins = VirtualCoin(leftMoney)
  138. consumeDict = {'chargeIndex': self.event_data['port'],
  139. 'reason': self.event_data['reason'],
  140. 'duration': usedTime}
  141. if not self.device.is_auto_refund:
  142. ServiceProgress.update_progress_and_consume_rcd(
  143. self.device['ownerId'],
  144. {'open_id': openId, 'device_imei': self.device['devNo'],
  145. 'port': self.event_data['port'], 'isFinished': False}, consumeDict
  146. )
  147. else:
  148. refund_money(self.device, backCoins, lineInfo['openId'])
  149. consumeDict.update({'refundedMoney': str(backCoins)})
  150. ServiceProgress.update_progress_and_consume_rcd(
  151. self.device['ownerId'],
  152. {'open_id': openId, 'device_imei': self.device['devNo'],
  153. 'port': self.event_data['port'], 'isFinished': False}, consumeDict)
  154. desc = u'您使用的%s号端口充电,共付款:%s元,给您退款:%s元' % (
  155. self.event_data['port'], money, backCoins)
  156. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  157. 'title': desc,
  158. 'backCount': u'金币:%s' % backCoins,
  159. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S')
  160. })
  161. dataDict.update({'backCoins': float(backCoins)})
  162. except Exception, e:
  163. logger.exception('deal with hongzhuo devNo=%s event e=%s' % (devNo, e))
  164. finally:
  165. logger.info('hongzhuo_notify_to_sd_norther:{}'.format(northerDict))
  166. self.notify_to_sd_norther(portStr=str(self.event_data.get("port")), consumeDict=northerDict)
  167. if lineInfo.has_key('orderNo'):
  168. dataDict.update({'orderNo': lineInfo['orderNo']})
  169. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  170. desc = self.event_data['reason'], dataDict = dataDict)
  171. # 刷卡启动事件
  172. elif self.event_data['cmdCode'] == "10":
  173. cardNo = self.event_data.get("cardNo")
  174. preFee = self.event_data.get("preFee")
  175. portStr = self.event_data.get("portStr")
  176. portCache = Device.get_dev_control_cache(self.device["devNo"]).get(portStr, {})
  177. if portCache.get("status", Const.DEV_WORK_STATUS_IDLE) == Const.DEV_WORK_STATUS_WORKING:
  178. logger.info("port is working!")
  179. card = self.update_card_dealer_and_type(cardNo)
  180. # 无效的卡
  181. if not card or not card.openId:
  182. logger.info("bad card, cardNo is {}".format(cardNo))
  183. self.deviceAdapter.response_use_card(self.FAIL, portStr, 0)
  184. return
  185. # 卡冻结
  186. if card.frozen:
  187. logger.info("card is frozen, cardNo is {}".format(cardNo))
  188. balance = float(card.balance) * 10
  189. self.deviceAdapter.response_use_card(self.FAIL, portStr, balance)
  190. return
  191. # 余额不足
  192. payMoney = RMB(preFee / 10.0)
  193. if float(card.balance) < float(payMoney):
  194. logger.info("card balance is not enough, cardNo is {}".format(card.balance))
  195. balance = float(card.balance) * 10
  196. self.deviceAdapter.response_use_card(self.FAIL, portStr, balance)
  197. return
  198. # 正常扣费流程, 先创建订单,再注册服务
  199. orderNo, cardOrderNo = self.record_consume_for_card(card, payMoney)
  200. ServiceProgress.register_card_service(
  201. self.device,
  202. int(portStr),
  203. card,
  204. {
  205. "cardOrderNo": cardOrderNo,
  206. "orderNo": orderNo,
  207. "money": payMoney.mongo_amount,
  208. "coin": payMoney.mongo_amount,
  209. "needTime": 0,
  210. }
  211. )
  212. leftBalance = float(card.balance - payMoney) * 10
  213. # 卡扣钱
  214. self.consume_money_for_card(card, payMoney)
  215. # 回复主板
  216. self.deviceAdapter.response_use_card(self.SUCCESS, portStr, leftBalance)
  217. # 通知已经扣费
  218. self.notify_balance_has_consume_for_card(card, payMoney)
  219. portDict = {
  220. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  221. 'status': Const.DEV_WORK_STATUS_WORKING,
  222. 'finishedTime': int(time.time()) + 12 * 60 * 60,
  223. 'coins': float(payMoney),
  224. 'isStart': True,
  225. 'price': str(float(payMoney)),
  226. 'openId': card.openId,
  227. 'refunded': False,
  228. "cardNo": cardNo
  229. }
  230. Device.update_dev_control_cache(self.device["devNo"], {portStr: portDict})
  231. # 设备上报的本地付费打开信息,需更新有用的端口信息
  232. elif self.event_data['cmdCode'] == "20":
  233. portStr = self.event_data.get("portStr")
  234. devCache = Device.get_dev_control_cache(self.device["devNo"])
  235. portCache = devCache.get(portStr)
  236. # 不干扰宝东的扫码支付
  237. if not portCache or not portCache.get("cardNo") or self.event_data.get("typeCode") != "01":
  238. logger.info("no port card start cache, so this info is useless!")
  239. return
  240. portCache.update({
  241. "coins": self.event_data.get("money"),
  242. })