huopo.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. # encoding=utf-8
  2. import logging
  3. import datetime
  4. from apilib.monetary import RMB
  5. from apps.web.constant import DeviceCmdCode
  6. from apps.web.core.adapter.base import SmartBox, MQTT_TIMEOUT
  7. from apps.web.core.device_define.huopo import HuopoCacheMgr, DefaultParams, Caculater
  8. from apps.web.core.exceptions import ServiceException
  9. from apps.web.core.networking import MessageSender
  10. from apps.web.user.models import MyUser
  11. from apps.web.device.models import Group, Device
  12. from taskmanager.mediator import task_caller
  13. logger = logging.getLogger(__name__)
  14. class HuoPoBox(SmartBox):
  15. def __init__(self, device):
  16. super(HuoPoBox, self).__init__(device)
  17. def _send_data(self, funCode, data, cmd=DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC, timeout=MQTT_TIMEOUT.NORMAL):
  18. result = MessageSender.send(
  19. device=self.device,
  20. cmd=cmd,
  21. payload={
  22. "IMEI": self.device.devNo,
  23. "data": data,
  24. "funCode": funCode
  25. },
  26. timeout=timeout
  27. )
  28. if "rst" in result and result["rst"] != 0:
  29. if result['rst'] == -1:
  30. raise ServiceException({'result': 2, 'description': u'网络通信故障'})
  31. elif result['rst'] == 1:
  32. raise ServiceException({'result': 2, 'description': u'门禁主板连接故障'})
  33. else:
  34. raise ServiceException({'result': 2, 'description': u'系统错误'})
  35. return result
  36. def _open(self):
  37. otherConf = self.device.get("otherConf", dict())
  38. snNum = otherConf.get("snNum")
  39. try:
  40. snNum = int(snNum or "")
  41. except ValueError:
  42. raise ServiceException({"result": "", "description": u"道闸编号设置错误"})
  43. data = DefaultParams.INSTRUCT_FORMAT.format(
  44. snNum=snNum,
  45. dutou=DefaultParams.DUTOU_NUM,
  46. auth=DefaultParams.AUTH_NUM,
  47. stay=DefaultParams.STAY_NUM
  48. )
  49. return self._send_data("", data)
  50. def _get_card_wait(self):
  51. """
  52. 获取设备侧的参数
  53. :return:
  54. """
  55. result = self._send_data("GC", "", cmd=DeviceCmdCode.OPERATE_DEV_SYNC)
  56. return int(result.get("data")[:2], 16)
  57. def _set_card_wait(self, waitTime):
  58. if not self.device.driverVersion < "v2.0.0":
  59. data = "{:0>2X}".format(waitTime)
  60. self._send_data("CC", data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC)
  61. def _get_server_config(self):
  62. """
  63. 获取设备侧的参数
  64. :return:
  65. """
  66. otherConf = self.device.get("otherConf", dict())
  67. parkInfo = self.get_parkingInfo()
  68. return {
  69. "maxParking": otherConf.get("maxParking", DefaultParams.DEFAULT_MAX_PARKING),
  70. "VIPMaxParking": otherConf.get("VIPMaxParking", DefaultParams.DEFAULT_VIP_MAX_PARKING),
  71. "snNum": otherConf.get("snNum", DefaultParams.DEFAULT_SN_NUM),
  72. "freeTime": otherConf.get("freeTime", DefaultParams.DEFAULT_FREE_TIME),
  73. "maxConsume": otherConf.get("maxConsume", DefaultParams.DEFAULT_FREE_TIME),
  74. "parkingNum": parkInfo.get("maxParking", 0),
  75. "VIPParkingNum": parkInfo.get("VIPMaxParking", 0)
  76. }
  77. def _get_device_config(self):
  78. """
  79. 获取服务器侧参数
  80. :return:
  81. """
  82. if self.device.driverVersion < "v2.0.0":
  83. return {
  84. "cardWait": u"驱动版本过低,暂不支持"
  85. }
  86. return {
  87. "cardWait": self._get_card_wait() # 刷卡等待时间
  88. }
  89. def calculate_consume(self, duration, package):
  90. """计算在给定的小时内要扣除的数量"""
  91. maxConsume = self.device.get("otherConf", dict()).get("maxConsume", DefaultParams.DEFAULT_MAX_CONSUME)
  92. freeTime = self.device.get("otherConf", dict()).get("freeTime", DefaultParams.DEFAULT_FREE_TIME)
  93. duration = duration - freeTime * 60
  94. c = Caculater(duration, package)
  95. money = c.caculate()
  96. if maxConsume == DefaultParams.DEFAULT_MAX_CONSUME:
  97. return money
  98. return min(money, RMB(maxConsume))
  99. def get_parkingInfo(self):
  100. serviceInfo = HuopoCacheMgr.get_parking_cache(self.device.groupId)
  101. parkingInfo = {}
  102. if serviceInfo is not None:
  103. parkingInfo = serviceInfo.get("parkingInfo", {})
  104. return parkingInfo
  105. def start_device(self, package, openId, attachParas):
  106. """启动
  107. 不把扣费逻辑做到这里面,是否决定扣费由外层service来决定
  108. """
  109. # 获取开闸信号 和 进入出门
  110. # TODO 标记用户的control不见了
  111. chargeIndex = attachParas.get("chargeIndex")
  112. control = "exit" if chargeIndex == "1" else "enter"
  113. # 开启道闸
  114. result = self._open()
  115. # 获取用户是否是VIP,使用了虚拟卡支付的都是VIP
  116. if self._vcard_id:
  117. _key = "VIPMaxParking"
  118. else:
  119. _key = "maxParking"
  120. # 在设备启动时候已经 加了锁 对于该设备当前
  121. parkingInfo = self.get_parkingInfo()
  122. parkingNum = parkingInfo.get(_key, 0)
  123. if control == "exit":
  124. if parkingNum > 0:
  125. parkingNum -= 1
  126. elif control == "enter":
  127. parkingNum += 1
  128. # 更新当前的最大人数 扫码的VIP不限制
  129. if openId and _key == "VIPMaxParking":
  130. parkingInfo.update({_key: parkingNum})
  131. HuopoCacheMgr.set_parking_cache(self._device.groupId, {"parkingInfo": parkingInfo})
  132. return result
  133. def notify_user(self, order, cardStart=False):
  134. """通知用户订单结束"""
  135. logger.info("start notify to user order finished")
  136. if order.isNormal and order.finishedTime:
  137. # 服务完成的订单需要通知用户
  138. openId = order.openId
  139. user = MyUser.objects.filter(openId=openId, groupId=self._device['groupId']).first()
  140. dealerId = self._device["ownerId"]
  141. group = Group.get_group(self._device["groupId"])
  142. address = group.get("address", "")
  143. startType = u"刷卡启动" if cardStart else u"扫码启动"
  144. # 通知的时候告诉用户是否使用虚拟卡支付了此次的费用 判断依据是 attachParas 里面有没有 vCardId
  145. if not order.attachParas.get("vCardId") and not order.attachParas.get("cardId"):
  146. payType = u"账户余额支付"
  147. elif not order.attachParas.get("vCardId") and order.attachParas.get("cardId"):
  148. payType = u"卡余额支付"
  149. else:
  150. payType = u"虚拟卡支付"
  151. consumeDict = {
  152. "title": u"\\n\\n设备编号:\\t\\t{logicalCode}\\n\\n服务地址:\\t\\t{group}\\n\\n起始时间:\\t\\t{st}\\n\\n结束时间:\\t\\t{et}\\n\\n启动方式:\\t\\t{startType}\\n\\n支付方式:\\t\\t{payType}".format(
  153. logicalCode=order.logicalCode,
  154. group=address,
  155. st=order.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S"),
  156. et=order.finishedTime.strftime("%Y-%m-%d %H:%M:%S"),
  157. startType=startType,
  158. payType=payType
  159. ),
  160. "service": u"停车服务已经结束",
  161. "finishTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  162. "remark": u"谢谢您的支持"
  163. }
  164. task_caller(
  165. 'report_to_user_via_wechat',
  166. openId=user.managerialOpenId if user else "",
  167. dealerId=dealerId,
  168. templateName="service_complete",
  169. **consumeDict
  170. )
  171. def analyze_event_data(self, data):
  172. """
  173. 刷卡上报事件
  174. #2181113205,1,0010967430@
  175. #{sn号},{读头号(固定为1)},{刷卡卡号}@
  176. 返回数据 {"cmd":221,"IMEI":"866289037458447","funCode":"","data":"#2181113205,B1@"}
  177. """
  178. snNum, dutou, cardNoStr = data.replace("#", "").replace("@", "").split(",")
  179. cardNo = str(int(cardNoStr))
  180. return {"snNum": snNum, "cardNo": cardNo, "cardNoStr": cardNoStr, "dutou": dutou}
  181. def is_port_can_use(self, chargeIndex, canAdd=None):
  182. """这个地方不做判断 直接通过, 具体的停车人数在启动的时候对其进行判断,以免用户在扫码界面停留过久"""
  183. return True, u""
  184. def get_dev_setting(self):
  185. deviceConf = self._get_device_config()
  186. serverConf = self._get_server_config()
  187. conf = dict()
  188. conf.update(deviceConf)
  189. conf.update(serverConf)
  190. return conf
  191. def set_device_function_param(self, request, lastSetConf):
  192. """lastSetConf 缓存中的配置,更新的同时更新缓存"""
  193. maxConsume = int(request.POST.get("maxConsume"))
  194. cardWait = int(request.POST.get("cardWait"))
  195. freeTime = int(request.POST.get("freeTime"))
  196. maxParking = int(request.POST.get("maxParking"))
  197. vipMaxParking = int(request.POST.get("VIPMaxParking"))
  198. snNum = str(request.POST.get("snNum"))
  199. if snNum == DefaultParams.DEFAULT_SN_NUM:
  200. raise ServiceException({"result": "2", "description": u"保存失败,请配置主板编号"})
  201. # 配置驱动侧参数
  202. self._set_card_wait(cardWait)
  203. otherConf = self.device.get("otherConf", dict())
  204. otherConf.update({
  205. "maxConsume": maxConsume,
  206. "cardWait": cardWait,
  207. "freeTime": freeTime,
  208. "maxParking": maxParking,
  209. "VIPMaxParking": vipMaxParking,
  210. "snNum": snNum
  211. })
  212. Device.objects.filter(devNo=self.device.devNo).update(otherConf=otherConf)
  213. Device.invalid_device_cache(devNo=self.device.devNo)