nanjiguang.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  6. from mongoengine import DoesNotExist
  7. from apilib.monetary import RMB, VirtualCoin
  8. from apilib.utils_sys import memcache_lock
  9. from apps.web.agent.models import Agent
  10. from apps.web.constant import Const, DeviceCmdCode
  11. from apps.web.dealer.models import Dealer
  12. from apps.web.device.models import Group, Device
  13. from apps.web.eventer import EventBuilder
  14. from apps.web.eventer.base import WorkEvent, FaultEvent
  15. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, Card, MyUser
  16. from apps.web.user.transaction_deprecated import refund_money
  17. logger = logging.getLogger(__name__)
  18. class builder(EventBuilder):
  19. def __getEvent__(self, device_event):
  20. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  21. if event_data is None or 'cmdCode' not in event_data:
  22. return None
  23. if event_data['cmdCode'] in ["08", "0C", "0E"]:
  24. if event_data['cmdCode'] == "08":
  25. event_data.update({{
  26. 'answer': device_event['data'][42:-4]
  27. }})
  28. return ChargingNanjiguangWorkEvent(self.deviceAdapter, event_data)
  29. if event_data["cmdCode"] in ["12"]:
  30. return ChargingNanjiguangFaultEvent(self.deviceAdapter, event_data)
  31. class ChargingNanjiguangWorkEvent(WorkEvent):
  32. def do(self, **args):
  33. cmdCode = self.event_data.get("cmdCode")
  34. devNo = self.device["devNo"]
  35. with memcache_lock(key = "{devNo}.{cmdCode}.event".format(devNo = devNo, cmdCode = cmdCode),
  36. value = '1') as acquired:
  37. if acquired:
  38. # 扫码结束充电
  39. if cmdCode == "08":
  40. sendData = self.event_data['answer']
  41. self.answer_device(funcCode="09", sendData=sendData)
  42. self.do_finish_charging()
  43. # 刷卡开始
  44. elif cmdCode == "0C":
  45. sendData = self.event_data.get("portHex") + self.event_data.get("timeStampHex")
  46. self.answer_device(funcCode="0D", sendData=sendData)
  47. self.do_start_card_charging()
  48. # 刷卡结束
  49. elif cmdCode == "0E":
  50. sendData = self.event_data.get("portHex") + self.event_data.get("timeStampHex")
  51. self.answer_device(funcCode="0F", sendData=sendData)
  52. self.do_finish_card_charging()
  53. else:
  54. logger.error("undefined cmd")
  55. def answer_device(self, funcCode, sendData):
  56. self.deviceAdapter._send_data(funcCode=funcCode, sendData=sendData, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  57. def do_finish_charging(self):
  58. """
  59. 扫码结束充电
  60. :return:
  61. """
  62. portStr = self.event_data.get("port")
  63. devCache = Device.get_dev_control_cache(self.device["devNo"])
  64. portCache = devCache.get(portStr)
  65. openId = portCache.get("openId")
  66. vCardId = portCache.get("vCardId")
  67. coins = portCache.get("coins")
  68. needTime = portCache.get("needTime")
  69. spendTime = self.event_data.get("spendTime")
  70. nowTime = datetime.datetime.now()
  71. group = Group.get_group(self.device["groupId"])
  72. dealer = Dealer.objects.filter(id=group["ownerId"]).first()
  73. if not openId:
  74. logger.error("open id is null")
  75. if not dealer:
  76. logger.error('dealer is not found, dealerId=%s' % group['ownerId'])
  77. return
  78. agent = Agent.objects(id=dealer.agentId).first()
  79. if not agent:
  80. logger.error('agent is not found, agentId=%s' % dealer.agentId)
  81. return
  82. user = MyUser.objects.filter(openId=openId, groupId=self.device["groupId"]).first()
  83. # 计算退费
  84. leftTime = needTime * 60 - spendTime if needTime * 60 > spendTime else 0
  85. refundCoins = VirtualCoin((leftTime / (needTime * 60)) * coins)
  86. self.notify_user(
  87. managerialOpenId=user.managerialOpenId,
  88. templateName="service_complete",
  89. title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}\\n\\n订购时间:\\t\\t{needTime}分钟\\n\\n剩余时间:\\t\\t{leftTime}分钟".format(
  90. reason=u"充电结束",
  91. logicalCode=self.device["logicalCode"],
  92. port=self.event_data["port"],
  93. group=group["address"],
  94. needTime=needTime,
  95. leftTime=int(leftTime / 60)
  96. ),
  97. service=u"充电桩充电服务",
  98. finishTime=datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S"),
  99. remark = u'谢谢您的支持'
  100. )
  101. consumeDict = {
  102. 'chargeIndex': portStr,
  103. 'reason': u"充电结束",
  104. 'actualNeedTime': needTime,
  105. 'duration': int(spendTime / 60),
  106. 'elec': round(self.event_data["spendElec"], 2),
  107. 'elecFee': self.calc_elec_fee(self.event_data["spendElec"]),
  108. 'leftTime': int(leftTime / 60),
  109. 'needTime': u'扫码订购%s分钟' % needTime
  110. }
  111. if int(refundCoins) > 0 and self.device.is_auto_refund:
  112. if vCardId is None:
  113. refund_money(self.device, refundCoins, openId)
  114. else:
  115. # 虚拟卡退费
  116. try:
  117. vCard = UserVirtualCard.objects.get(id=vCardId)
  118. except DoesNotExist:
  119. logger.info('can not find the vCard id = %s' % vCardId)
  120. return
  121. consumeRecordId = portCache.get("consumeRcdId")
  122. if consumeRecordId is None:
  123. logger.info('can not find consume rcd id')
  124. return
  125. try:
  126. vCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRecordId)
  127. except DoesNotExist, e:
  128. logger.info('can not find the consume rcd id = %s' % consumeRecordId)
  129. return
  130. vCard.refund_quota(
  131. vCardConsumeRcd,
  132. int(spendTime/60),
  133. self.event_data["spendElec"],
  134. refundCoins.mongo_amount
  135. )
  136. consumeDict.update({"refundCoins": refundCoins.mongo_amount})
  137. refundTitle = u'您使用的%s号端口充电,共付款:%s元,充电预定时间为:%s分钟,剩余时间:%s分钟,给您退款:%s元' % (portStr, coins, int(needTime/60), int(leftTime/60), refundCoins)
  138. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  139. 'title': refundTitle,
  140. 'backCount': u'金币:%s' % refundCoins,
  141. 'finishTime': datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S")
  142. })
  143. ServiceProgress.update_progress_and_consume_rcd(
  144. self.device["ownerId"],
  145. {
  146. "open_id": openId,
  147. "device_imei": self.device["devNo"],
  148. "port": int(portStr),
  149. "isFinished": False
  150. },
  151. consumeDict
  152. )
  153. # 事件结束之后清空端口的信息 更新设备的服务信息
  154. Device.clear_port_control_cache(self.device["devNo"], portStr)
  155. def do_start_card_charging(self):
  156. """
  157. 刷卡开始
  158. :return:
  159. """
  160. portStr = self.event_data.get("port")
  161. timeStamp = self.event_data.get("timeStamp")
  162. cardNo = self.event_data.get("cardNo")
  163. coins = self.event_data.get("coins")
  164. startTime = time.strftime("%Y-%m-%d %H:%M", time.localtime(timeStamp))
  165. card = self.update_card_dealer_and_type(cardNo, cardType="IC", isHaveBalance=False)
  166. if not card.openId:
  167. logger.error("card has not openId, cardNo is %s" % card.cardNo)
  168. return
  169. orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(self.event_data["coins"]))
  170. # 记录当前的卡消费的 progress
  171. fee = RMB(coins)
  172. ServiceProgress.register_card_service(
  173. self.device,
  174. int(portStr),
  175. card,
  176. {
  177. "orderNo": orderNo,
  178. "money": fee.mongo_amount,
  179. "coin": fee.mongo_amount,
  180. "cardOrderNo": cardOrderNo
  181. }
  182. )
  183. # 通知卡消费成功
  184. self.notify_balance_has_consume_for_card(card, fee)
  185. # 更新一下端口缓存
  186. self.event_data.update({'cardId': str(card.id)})
  187. self.event_data.update({'openId': card.openId})
  188. self.event_data.update({'coins': int(fee)})
  189. self.event_data.update({'startTime': startTime})
  190. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  191. Device.update_dev_control_cache(self.device['devNo'], {portStr :self.event_data})
  192. def do_finish_card_charging(self):
  193. """
  194. # 刷卡结束上报
  195. :return:
  196. """
  197. portStr = self.event_data.get("port")
  198. spendTime = self.event_data.get("spendTime")
  199. spendElec = self.event_data.get("spendElec")
  200. devCache = Device.get_dev_control_cache(self.device["devNo"])
  201. portCache = devCache.get(portStr)
  202. if not portCache:
  203. logger.error("not port cache")
  204. return
  205. cardId = portCache.get("cardId")
  206. try:
  207. card = Card.objects.get(id=cardId)
  208. except DoesNotExist:
  209. logger.error("card don't exist")
  210. return
  211. openId = card.openId
  212. group = Group.get_group(self.device["groupId"])
  213. user = MyUser.objects.filter(openId=openId, groupId=self.device["groupId"]).first()
  214. consumeDict = {
  215. 'chargeIndex': portStr,
  216. 'reason': u"刷卡充电结束",
  217. 'duration': int(spendTime / 60),
  218. 'elec': round(spendElec, 2),
  219. 'elecFee': self.calc_elec_fee(self.event_data["spendElec"]),
  220. }
  221. nowTime = datetime.datetime.now()
  222. self.notify_user(
  223. managerialOpenId=user.managerialOpenId,
  224. templateName="service_complete",
  225. title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}\\n\\n订购金额:\\t\\t{coins}".format(
  226. reason=u"刷卡充电结束",
  227. logicalCode=self.device["logicalCode"],
  228. port=self.event_data["port"],
  229. group=group["address"],
  230. coins=portCache.get("coin")
  231. ),
  232. service=u"充电桩充电服务",
  233. finishTime=datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S"),
  234. remark = u'谢谢您的支持'
  235. )
  236. ServiceProgress.update_progress_and_consume_rcd(
  237. self.device["ownerId"],
  238. {
  239. "open_id": openId,
  240. "device_imei": self.device["devNo"],
  241. "port": int(portStr),
  242. "isFinished": False
  243. },
  244. consumeDict
  245. )
  246. # 事件结束之后清空端口的信息 更新设备的服务信息
  247. Device.clear_port_control_cache(self.device["devNo"], portStr)
  248. class ChargingNanjiguangFaultEvent(FaultEvent):
  249. def do(self, **args):
  250. """
  251. 烟感报警
  252. :param **args:
  253. :return:
  254. """
  255. # 首先发送确认消息
  256. self.deviceAdapter._send_data(funCode=13, sendData=self.event_data.get("timeStampHex"), cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
  257. group = Group.get_group(self.device["groupId"])
  258. eventTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.event_data.get("timeStamp")))
  259. self.notify_dealer(
  260. templateName="device_fault",
  261. title="注意!设备烟感报警!",
  262. device=u"{groupNumber}组-{logicalCode}".format(groupNumber=self.device["groupNumber"], logicalCode=self.device["logicalCode"]),
  263. location=u"{address}-{groupName}".format(address=group["address"], groupName=group["groupName"]),
  264. fault=u"设备当前触发烟感,可能发生了火警!",
  265. notifyTime=eventTime
  266. )