water_dispenser.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from apilib.monetary import RMB, VirtualCoin
  6. from apps import serviceCache
  7. from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND
  8. from apps.web.core.device_define.water_despenser import CMD_CODE
  9. from apps.web.dealer.models import Dealer
  10. from apps.web.device.models import Device, Group
  11. from apps.web.eventer.base import WorkEvent
  12. from apps.web.eventer import EventBuilder
  13. from apps.web.south_intf.platform import notify_event_to_north
  14. from apps.web.user.models import ServiceProgress, MyUser
  15. from taskmanager.mediator import task_caller
  16. logger = logging.getLogger(__name__)
  17. class builder(EventBuilder):
  18. def __getEvent__(self, device_event):
  19. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  20. if not event_data or 'cmdCode' not in event_data:
  21. return None
  22. if event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_ALERT_EVENT_CODE:
  23. return WaterDispenserAlertEvent(self.deviceAdapter, event_data)
  24. if event_data['cmdCode'] in [
  25. CMD_CODE.WATER_DISPENSE_SETTING_EVENT_CODE,
  26. CMD_CODE.WATER_DISPENSE_WORK_STATUS_EVENT_CODE,
  27. CMD_CODE.WATER_DISPENSE_FINISH_EVENT_CODE
  28. ]:
  29. return WaterDispenserWorkEvent(self.deviceAdapter, event_data)
  30. class WaterDispenserAlertEvent(WorkEvent):
  31. def do(self, **args):
  32. def _send_alert_message_to_dealer(dealer, group, fault):
  33. notifyData = {
  34. 'title': '设备故障',
  35. 'device': u'{gNum}组-{lc}'.format(gNum=self.device['groupNumber'], lc=self.device['logicalCode']),
  36. 'location': u'{address}-{groupName}'.format(address=group['address'], groupName=group['groupName']),
  37. 'fault': fault,
  38. 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  39. }
  40. task_caller(
  41. func_name='report_to_dealer_via_wechat',
  42. openId=dealer.managerialOpenId,
  43. dealerId=str(dealer.id),
  44. templateName='device_fault',
  45. **notifyData
  46. )
  47. devNo = self.device['devNo']
  48. logger.info('water dispenser event detected, devNo=%s, curInfo=%s' % (devNo, self.event_data))
  49. if self.event_data['eventKey'] != '00':
  50. pass
  51. else:
  52. if self.event_data['isError'] is True:
  53. group = Group.objects(id=self.device['groupId']).first()
  54. dealer = Dealer.objects(id=self.device['ownerId']).first()
  55. portStatus = {}
  56. temp = []
  57. if self.event_data['noWater'] is True:
  58. temp.append('noWater')
  59. if self.event_data['moreWater'] is True:
  60. temp.append('moreWater')
  61. if self.event_data['port1Leak'] is True:
  62. temp.append('port1Leak')
  63. if self.event_data['port2Leak'] is True:
  64. temp.append('port2Leak')
  65. if self.event_data['port1Error'] is True:
  66. temp.append('port1Error')
  67. if self.event_data['port2Error'] is True:
  68. temp.append('port2Error')
  69. cache_key = ''
  70. fault = u''
  71. statusErrorInfo1 = u''
  72. statusErrorInfo2 = u''
  73. # 遍历temp, 然后更新数据
  74. for _ in temp:
  75. cache_key += _
  76. portStatus = {
  77. '1': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'},
  78. '2': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'}
  79. }
  80. if 'noWater' == _:
  81. statusErrorInfo1 += u'水箱缺液'
  82. statusErrorInfo2 += u'水箱缺液'
  83. portStatus['1'].update({'statusErrorInfo': statusErrorInfo1})
  84. portStatus['2'].update({'statusErrorInfo': statusErrorInfo2})
  85. fault = u'水箱缺液!'
  86. if 'moreWater' == _:
  87. statusErrorInfo1 = statusErrorInfo1 + u' ' + u'水箱溢流'
  88. statusErrorInfo2 = statusErrorInfo2 + u' ' + u'水箱溢流'
  89. portStatus['1'].update({'statusErrorInfo': statusErrorInfo1})
  90. portStatus['2'].update({'statusErrorInfo': statusErrorInfo2})
  91. fault = fault + u' ' + u'水箱溢流!'
  92. if 'port1Leak' == _:
  93. statusErrorInfo1 = statusErrorInfo1 + u' ' + u'漏水'
  94. portStatus['1'].update({'statusErrorInfo': statusErrorInfo1})
  95. fault = fault + u' ' + u'通道1漏水!'
  96. if 'port2Leak' == _:
  97. statusErrorInfo2 = statusErrorInfo2 + u' ' + u'漏水'
  98. portStatus['2'].update({'statusErrorInfo': statusErrorInfo2})
  99. fault = fault + u' ' + u'通道2漏水!'
  100. if 'port1Error' == _:
  101. statusErrorInfo1 = statusErrorInfo1 + u' ' + u'电磁阀故障'
  102. portStatus['1'].update({'statusErrorInfo': statusErrorInfo1})
  103. portStatus['1'].update({'status': Const.DEV_WORK_STATUS_FAULT})
  104. fault = fault + u' ' + u'通道1电磁阀故障!'
  105. if 'port2Error' == _:
  106. statusErrorInfo2 = statusErrorInfo2 + u' ' + u'电磁阀故障'
  107. portStatus['2'].update({'statusErrorInfo': statusErrorInfo2})
  108. portStatus['2'].update({'status': Const.DEV_WORK_STATUS_FAULT})
  109. fault = fault + u' ' + u'通道2电磁阀故障!'
  110. jsjCache = serviceCache.get(dealer.username + '_jsj', 0)
  111. jsjData = dealer.username + '_' + cache_key
  112. if jsjCache == 0:
  113. _send_alert_message_to_dealer(dealer, group, fault)
  114. serviceCache.set(dealer.username + '_jsj', jsjData, 60 * 60)
  115. else:
  116. if jsjCache == jsjData:
  117. pass
  118. else:
  119. _send_alert_message_to_dealer(dealer, group, fault)
  120. serviceCache.set(dealer.username + '_jsj', jsjData, 60 * 60)
  121. Device.update_dev_control_cache(devNo, {'deviceId': self.event_data['deviceId']})
  122. Device.update_dev_control_cache(devNo, portStatus)
  123. else:
  124. portStatus = {
  125. '1': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'},
  126. '2': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'}
  127. }
  128. ctrlInfo = Device.get_dev_control_cache(devNo)
  129. if ctrlInfo.get('1', None) is not None and ctrlInfo.get('2', None) is not None:
  130. if ctrlInfo['1'].get('status', '') == 3:
  131. portStatus.update({'1': {'status': Const.DEV_WORK_STATUS_FORBIDDEN, 'statusErrorInfo': u'无'}})
  132. if ctrlInfo['2'].get('status', '') == 3:
  133. portStatus.update({'2': {'status': Const.DEV_WORK_STATUS_FORBIDDEN, 'statusErrorInfo': u'无'}})
  134. Device.update_dev_control_cache(devNo, {'deviceId': self.event_data['deviceId']})
  135. Device.update_dev_control_cache(devNo, portStatus)
  136. class WaterDispenserWorkEvent(WorkEvent):
  137. def calc_backCoins(self, reason, need, left, coins):
  138. device = Device.objects(logicalCode=self.device['logicalCode']).first()
  139. minConsumeRatio = device.otherConf.get('minConsumeRatio', 5)
  140. minConsumeTime = int(need * (float(minConsumeRatio) / 100))
  141. staticMinConsumeTime = int(need * 0.95)
  142. if left > need:
  143. backCoins = RMB('0.0')
  144. else:
  145. if reason in ['01', '05']:
  146. if (float(left) / float(need)) > (float(staticMinConsumeTime) / float(need)):
  147. backCoins = coins
  148. else:
  149. if (need - left) > minConsumeTime:
  150. backCoins = coins * (float(left) / float(need))
  151. else:
  152. backCoins = coins * (1 - float(minConsumeRatio) / 100)
  153. elif reason == '04':
  154. if (need - left) > minConsumeTime:
  155. backCoins = coins * (float(left) / float(need))
  156. else:
  157. backCoins= coins * (1-float(minConsumeRatio) / 100)
  158. elif reason == '06':
  159. if (float(left) / float(need)) > (float(staticMinConsumeTime) / float(need)):
  160. backCoins = coins
  161. else:
  162. backCoins = coins * (float(left) / float(need))
  163. elif reason in ['03']:
  164. backCoins = coins
  165. elif reason in ['02', '08', '09']:
  166. backCoins = coins * (float(left) / float(need))
  167. elif reason in ['07']:
  168. backCoins = RMB('0.0')
  169. else:
  170. backCoins = RMB('0.0')
  171. return backCoins
  172. def do(self, **args):
  173. devNo = self.device['devNo']
  174. logger.info('WaterDispenser event detected, devNo=%s, curInfo=%s' % (devNo, self.event_data))
  175. if self.event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_SETTING_EVENT_CODE:
  176. boardSoftVer = self.event_data['boardSoftVer']
  177. return self.deviceAdapter.init_dev_settings(boardSoftVer)
  178. if self.event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_WORK_STATUS_EVENT_CODE:
  179. Device.update_dev_control_cache(devNo, {str(self.event_data['port']): {'isPause': False if self.event_data['isPause'] == '02' else True}})
  180. return
  181. if self.event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_FINISH_EVENT_CODE:
  182. port = self.event_data['port']
  183. reason = self.event_data['reason']
  184. try:
  185. ctrInfo = Device.get_dev_control_cache(self.device['devNo'])
  186. lineInfo = ctrInfo.get(port)
  187. coins = lineInfo['coins']
  188. refundedMoney = RMB('0.0')
  189. refundCoins = VirtualCoin('0.0')
  190. consumeDict = {}
  191. reasonDesc = self.event_data['desc']
  192. reasonCode = self.event_data['reason']
  193. agentId = Dealer.objects(id=self.device['ownerId']).first().agentId
  194. users = MyUser.objects(openId=lineInfo['openId'], agentId=agentId)
  195. for _ in users:
  196. breakRuleTimes = _.blacklistConfig.get('breakRuleTimes', 0)
  197. if reasonCode in ['08', '09']:
  198. breakRuleTimes += 1
  199. if breakRuleTimes > 3:
  200. breakRuleTimes = 3
  201. else:
  202. breakRuleTimes -= 1
  203. if breakRuleTimes < 0:
  204. breakRuleTimes = 0
  205. _.blacklistConfig['breakRuleTimes'] = breakRuleTimes
  206. _.save()
  207. # 计时
  208. if lineInfo['consumeMode'] == '1':
  209. usedTime = self.event_data['duration']
  210. needTime = lineInfo['needTime']
  211. leftTime = needTime - usedTime
  212. consumeDict = {'reason': reasonDesc, 'desc': reasonDesc, 'chargeIndex': port, 'duration': usedTime}
  213. group = Group.get_group(self.device['groupId'])
  214. user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device['groupId']).first()
  215. # 通知服务结束
  216. self.notify_user(user.managerialOpenId if user else '', 'service_complete',
  217. **{
  218. 'title': u'%s' % reasonDesc,
  219. 'service': u'设备服务(设备编号:%s, 端口:%s,地址:%s)' % (
  220. self.device['logicalCode'], port, group['address']),
  221. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  222. 'remark': u'谢谢您的支持'
  223. })
  224. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  225. {'open_id': lineInfo['openId'],
  226. 'port': int(port),
  227. 'device_imei': self.device['devNo'],
  228. 'isFinished': False}, consumeDict)
  229. backCoins = self.calc_backCoins(reason, needTime, leftTime, RMB(lineInfo['coins']))
  230. refundedMoney = backCoins
  231. refundCoins = backCoins
  232. consumeDict.update({'refundedMoney': refundedMoney})
  233. isRefund = True
  234. # 计量
  235. elif lineInfo['consumeMode'] == '2':
  236. usedLitre = self.event_data['spendLitre']
  237. needLitre = lineInfo['needLitre']
  238. leftLitre = needLitre - usedLitre
  239. consumeDict = {'reason': reasonDesc, 'desc': reasonDesc, 'chargeIndex': port,
  240. 'usedLitre': usedLitre}
  241. group = Group.get_group(self.device['groupId'])
  242. user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device['groupId']).first()
  243. # 通知服务结束
  244. self.notify_user(user.managerialOpenId if user else '', 'service_complete',
  245. **{
  246. 'title': u'%s' % reasonDesc,
  247. 'service': u'设备服务(设备编号:%s, 端口:%s,地址:%s)' % (
  248. self.device['logicalCode'], port, group['address']),
  249. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  250. 'remark': u'谢谢您的支持'
  251. })
  252. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  253. {'open_id': lineInfo['openId'],
  254. 'port': int(port),
  255. 'device_imei': self.device['devNo'],
  256. 'isFinished': False}, consumeDict)
  257. backCoins = self.calc_backCoins(reason, needLitre, leftLitre, RMB(lineInfo['coins']))
  258. refundedMoney = backCoins
  259. refundCoins = backCoins
  260. consumeDict.update({'refundedMoney': refundedMoney})
  261. isRefund = True
  262. else:
  263. user = None
  264. group = None
  265. isRefund = False
  266. if self.device.is_auto_refund is True and isRefund is True:
  267. is_cash = False
  268. if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0):
  269. is_cash = True
  270. consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: VirtualCoin(coins).mongo_amount})
  271. if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0):
  272. consumeDict.update(
  273. {DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(coins) - refundCoins).mongo_amount})
  274. self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash)
  275. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  276. {'open_id': lineInfo['openId'], 'port': int(port),
  277. 'device_imei': self.device['devNo'],
  278. 'isFinished': False}, consumeDict)
  279. extra = []
  280. price = RMB(lineInfo['price'])
  281. coins = VirtualCoin(coins)
  282. if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
  283. real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH])
  284. if real_refund > RMB(0):
  285. extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)})
  286. extra.append({u'退款金额': '{}(元)'.format(real_refund)})
  287. else:
  288. extra.append({u'消费金额': '{}(元)'.format(price)})
  289. elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
  290. real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS])
  291. if real_refund > VirtualCoin(0):
  292. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)})
  293. extra.append({u'退款金额': '{}(金币)'.format(real_refund)})
  294. else:
  295. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  296. else:
  297. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  298. self.notify_user_service_complete(
  299. service_name='服务完成',
  300. openid=user.managerialOpenId if user else '',
  301. port=port,
  302. address=group['address'],
  303. reason=reasonDesc,
  304. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  305. extra=extra)
  306. finally:
  307. Device.clear_port_control_cache(devNo, str(port))
  308. notify_event_to_north(self.dealer, self.device, level=Const.EVENT_NORMAL, desc=reason)