yongxin.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from apilib.monetary import RMB, VirtualCoin
  6. from apilib.utils_sys import memcache_lock
  7. from apps.web.constant import Const
  8. from apps.web.core.device_define.yongxin import REASON_MAP
  9. from apps.web.device.models import Group, Device
  10. from apps.web.eventer import EventBuilder
  11. from apps.web.eventer.base import WorkEvent
  12. from apps.web.helpers import device_lock_key
  13. from apps.web.user.models import ServiceProgress, MyUser, Card, ConsumeRecord, CardConsumeRecord
  14. logger = logging.getLogger(__name__)
  15. class builder(EventBuilder):
  16. def __getEvent__(self, device_event):
  17. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  18. if event_data is None or 'cmdCode' not in event_data:
  19. return None
  20. if event_data['cmdCode'] in ['17', '19', '1D', '41', '11']:
  21. return YongxinWorkEvent(self.deviceAdapter, event_data)
  22. return None
  23. class YongxinWorkEvent(WorkEvent):
  24. def do(self, **args):
  25. devNo = self.device['devNo']
  26. logger.info('yong xin car charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
  27. if self.event_data["cmdCode"] == "11":
  28. self.do_login()
  29. elif self.event_data["cmdCode"] == "41":
  30. self.do_elec_price()
  31. elif self.event_data['cmdCode'] == '17': # 刷卡消费上报,需要记录下
  32. self.do_card_start()
  33. elif self.event_data['cmdCode'] == '19': # 充电实时数据;分扫码扣费,刷卡扣费
  34. self.do_report()
  35. elif self.event_data['cmdCode'] == '1D': # 订单上传,这里需要过滤掉,防止多次报文上报上来
  36. self.do_finish()
  37. else:
  38. logger.error("error cmd, cmd = <{}>, dev = <{}> , event data is <{}>".format(
  39. self.event_data["cmdCode"],
  40. self.device.devNo,
  41. self.event_data
  42. ))
  43. return
  44. def do_card_start(self):
  45. """
  46. 处理账单上传
  47. """
  48. sequanceNo = self.event_data["sequanceNo"]
  49. with memcache_lock(key = device_lock_key(self.event_data['cardNo']), value = sequanceNo,
  50. expire = 360) as acquired:
  51. if not acquired:
  52. return
  53. cardNo = self.event_data['cardNo']
  54. portStr = str(self.event_data["port"])
  55. balance = RMB(self.event_data["balance"])
  56. card = self.update_card_dealer_and_type(cardNo, 'IC', True)
  57. self.update_card_balance(card, RMB(self.event_data['balance']))
  58. order = ConsumeRecord.objects(sequanceNo=sequanceNo).first() # type: ConsumeRecord
  59. # 存在订单的情况下 直接回复就好了 可能是重复性报文
  60. if order:
  61. lineInfo = Device.get_port_control_cache(self.device.devNo, self.event_data['port'])
  62. old_orderNo = lineInfo.get('orderNo', '')
  63. if lineInfo.get('cardId', '') == str(card.id) and old_orderNo == order.orderNo:
  64. return self.device.deviceAdapter._response_card_start(portStr, sequanceNo)
  65. else:
  66. orderNo, cardOrderNo = self.add_record_consume_for_card(card, sequanceNo, balance)
  67. # 记录当前服务的progress
  68. ServiceProgress.register_card_service(self.device, self.event_data['port'], card, {'orderNo': orderNo, 'cardOrderNo': cardOrderNo})
  69. rv = {
  70. 'cardId': str(card.id),
  71. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  72. 'isStart': True,
  73. 'status': Const.DEV_WORK_STATUS_WORKING,
  74. 'useType': 'card',
  75. 'orderNo': orderNo,
  76. 'sequanceNo': sequanceNo,
  77. 'openId': card.openId,
  78. 'cardNo': self.event_data['cardNo'],
  79. 'balance': self.event_data['balance']
  80. }
  81. Device.update_dev_control_cache(self.device.devNo, {portStr: rv})
  82. return self.device.deviceAdapter._response_card_start(portStr, sequanceNo)
  83. def do_report(self):
  84. """
  85. 处理 充电数据上传
  86. """
  87. lineInfo = Device.get_port_control_cache(self.device.devNo, str(self.event_data["port"]))
  88. lineInfo.update(self.event_data)
  89. if not lineInfo.has_key('useType'): # 有可能实时数据先于刷卡数据过来
  90. return
  91. if lineInfo['useType'] == 'card': # 刷卡,直接返回就Ok
  92. servicedInfo = {
  93. 'outputVoltage': lineInfo['outputVoltage'],
  94. 'outputElec': lineInfo['outputElec'],
  95. 'elec': lineInfo['elec'],
  96. 'spendMoney': lineInfo['spendMoney'],
  97. 'duration': lineInfo['duration']
  98. }
  99. self.update_card_consume_record(
  100. orderNo=lineInfo['orderNo'],
  101. spendMoney=lineInfo['spendMoney'],
  102. desc=u'已经花费%s元,已充%s分钟,%s度电' % (
  103. lineInfo['spendMoney'], lineInfo['duration'], lineInfo['elec']),
  104. servicedInfo=servicedInfo
  105. )
  106. else:
  107. # 更新消费信息即可
  108. leftMoney = str(VirtualCoin(lineInfo.get("coins", 0)) - VirtualCoin(lineInfo["spendMoney"]))
  109. lineInfo["leftMoney"] = leftMoney
  110. Device.update_dev_control_cache(self.device.devNo, {str(self.event_data["port"]): lineInfo})
  111. def do_finish(self):
  112. """
  113. 处理 结算账单上传
  114. """
  115. sequanceNo = self.event_data['sequanceNo']
  116. portStr = str(self.event_data["port"])
  117. with memcache_lock(key = device_lock_key(sequanceNo), value = sequanceNo, expire = 360) as acquired:
  118. if not acquired:
  119. return
  120. self.device.deviceAdapter._response_finished(portStr, sequanceNo, 0)
  121. order = ConsumeRecord.objects(sequanceNo=sequanceNo).first() # type: ConsumeRecord
  122. if not order:
  123. logger.warning('order<no={}> is not exists.'.format(sequanceNo))
  124. return
  125. if order.remarks == u'刷卡消费':
  126. servicedInfo = {
  127. 'elec': self.event_data['elec'],
  128. 'spendMoney': self.event_data['spendMoney'],
  129. 'duration': self.event_data['duration']
  130. }
  131. _, cardConsumeRecord = self.update_card_consume_record(
  132. orderNo=order.orderNo,
  133. spendMoney=self.event_data['spendMoney'],
  134. desc=u'一共花费%s元,共充电%s分钟,消耗%s度电' % (
  135. self.event_data['spendMoney'],
  136. self.event_data['duration'],
  137. self.event_data['elec']),
  138. servicedInfo=servicedInfo
  139. )
  140. try:
  141. cardId = cardConsumeRecord.cardId
  142. card = Card.objects.get(id=cardId)
  143. card.balance = RMB(self.event_data['balance'])
  144. card.save()
  145. except Exception as e:
  146. logger.exception('some error=%s' % e)
  147. else:
  148. devCache = Device.get_dev_control_cache(self.device.devNo)
  149. portCache = devCache.get(portStr, {})
  150. payMoney = VirtualCoin(portCache["coins"])
  151. spendMoney = VirtualCoin(self.event_data["spendMoney"])
  152. refundMoney = payMoney - spendMoney
  153. logger.info("[YONG XIN device <{}> refund money is <{}>]".format(self.device.devNo, refundMoney))
  154. # 退款大于起始 的情况下 走售后
  155. if refundMoney > payMoney:
  156. refundMoney = VirtualCoin(0)
  157. group = Group.get_group(self.device['groupId'])
  158. user = order.user
  159. # 更新用户的余额以及此次的消费金额
  160. user.balance += RMB(refundMoney)
  161. order.coin = VirtualCoin(spendMoney)
  162. order.save()
  163. user.save()
  164. consumeDict = {
  165. 'chargeIndex': self.event_data['port'],
  166. 'elec': self.event_data['elec'],
  167. 'spendMoney': self.event_data['spendMoney'],
  168. 'duration': self.event_data['duration'],
  169. 'reason': REASON_MAP.get(self.event_data["reason"], "")
  170. }
  171. ServiceProgress.update_progress_and_consume_rcd(
  172. self.device['ownerId'],
  173. {
  174. 'open_id': order.openId,
  175. 'device_imei': self.device['devNo'],
  176. 'port': self.event_data['port'],
  177. 'isFinished': False
  178. },
  179. consumeDict
  180. )
  181. self.notify_user(
  182. managerialOpenId=user.managerialOpenId if user else "",
  183. templateName="service_complete",
  184. title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}\\n\\n充电时间:\\t\\t{duration}分钟\\n\\n消耗电量:\\t\\t{elec}度".format(
  185. reason=REASON_MAP.get(self.event_data["reason"], ""),
  186. logicalCode=self.device["logicalCode"],
  187. port=self.event_data["port"],
  188. group=group["address"],
  189. duration=self.event_data['duration'],
  190. elec=self.event_data['elec']
  191. ),
  192. service=u"充电桩充电服务",
  193. finishTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  194. remark=u'谢谢您的支持'
  195. )
  196. Device.clear_port_control_cache(self.device.devNo, portStr)
  197. def do_login(self):
  198. """
  199. 处理登录请求
  200. """
  201. self.device.deviceAdapter._response_login(self.event_data["devType"])
  202. def do_elec_price(self):
  203. """
  204. 处理电价查询
  205. """
  206. self.device.deviceAdapter._response_elec_price()
  207. def add_record_consume_for_card(self, card, sequanceNo, balance):
  208. servicedInfo = {}
  209. group = Group.get_group(self.device['groupId'])
  210. address = group['address']
  211. group_number = self.device['groupNumber']
  212. now = datetime.datetime.now()
  213. orderNo = ConsumeRecord.make_no()
  214. new_record = {
  215. 'orderNo': orderNo,
  216. 'dateTimeAdded': now,
  217. 'openId': card.openId,
  218. 'ownerId': self.device['ownerId'],
  219. 'coin': VirtualCoin('0.00').mongo_amount,
  220. 'money': RMB('0.00').mongo_amount,
  221. 'devNo': self.device['devNo'],
  222. 'logicalCode': self.device['logicalCode'],
  223. 'groupId': self.device['groupId'],
  224. 'address': address,
  225. 'groupNumber': group_number,
  226. 'groupName': group['groupName'],
  227. 'devTypeCode': self.device.devTypeCode,
  228. 'devTypeName': self.device.devTypeName,
  229. 'isNormal': True,
  230. 'status': ConsumeRecord.Status.RUNNING,
  231. 'remarks': u'刷卡消费',
  232. 'errorDesc': '',
  233. 'sequanceNo': sequanceNo,
  234. 'desc': "",
  235. 'attachParas': {},
  236. 'servicedInfo': {}
  237. }
  238. ConsumeRecord.get_collection().insert_one(new_record)
  239. # 刷卡消费也记录一条数据
  240. cardOrderNo = CardConsumeRecord.make_no()
  241. if not CardConsumeRecord.objects.filter(devNo = self.device['devNo'], orderNo=orderNo).count():
  242. new_card_record = {
  243. 'orderNo': cardOrderNo,
  244. 'openId': card.openId,
  245. 'cardId': str(card.id),
  246. 'money': RMB('0.00').mongo_amount,
  247. 'balance': balance.mongo_amount,
  248. 'devNo': self.device['devNo'],
  249. 'devTypeCode': self.device.devTypeCode,
  250. 'devTypeName': self.device.devTypeName,
  251. 'logicalCode': self.device['logicalCode'],
  252. 'groupId': self.device['groupId'],
  253. 'address': address,
  254. 'groupNumber': group_number,
  255. 'groupName': group['groupName'],
  256. 'result': 'success',
  257. 'remarks': u'刷卡消费',
  258. 'dateTimeAdded': datetime.datetime.now(),
  259. 'desc': "",
  260. 'servicedInfo': servicedInfo
  261. }
  262. CardConsumeRecord.get_collection().insert_one(new_card_record)
  263. return orderNo, cardOrderNo
  264. @staticmethod
  265. def update_card_consume_record(orderNo, spendMoney, desc, servicedInfo):
  266. consumeRcd = ConsumeRecord.objects(orderNo=orderNo).first()
  267. if not consumeRcd:
  268. logger.info('can not find the record')
  269. return None, None
  270. consumeRcd.coin = VirtualCoin(spendMoney)
  271. consumeRcd.money = RMB(spendMoney)
  272. consumeRcd.desc = desc
  273. consumeRcd.servicedInfo = servicedInfo
  274. consumeRcd.save()
  275. cardConsumeRcd = CardConsumeRecord.objects.get(orderNo = consumeRcd.orderNo)
  276. cardConsumeRcd.money = RMB(spendMoney)
  277. cardConsumeRcd.desc = desc
  278. cardConsumeRcd.servicedInfo = servicedInfo
  279. cardConsumeRcd.save()
  280. return consumeRcd, cardConsumeRcd