weifule2_policy.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from apilib.monetary import RMB
  6. from apilib.utils_sys import memcache_lock
  7. from apps.web.constant import FAULT_CODE, FAULT_LEVEL, ErrorCode
  8. from apps.web.device.models import Group
  9. from apps.web.eventer import EventBuilder
  10. from apps.web.eventer.base import WorkEvent, FaultEvent
  11. from apps.web.eventer.weifuleCommon import WeiFuLePolicyProcess
  12. from apps.web.user.models import WeifuleCardStamp, Card, CardRechargeOrder, CardRechargeRecord
  13. logger = logging.getLogger(__name__)
  14. created_order_32 = 32
  15. executing_order_33 = 33
  16. finished_order_34 = 34
  17. id_card_request_35 = 35
  18. card_recharge_order_37 = 37
  19. fault_event_overload_38 = 38 # 整机功率过载
  20. fault_event_relay_39 = 39 # 继电器故障
  21. fault_event_counter_40 = 40 # 计量芯片故障
  22. fault_event_mcu_36 = 36 # mcu重启
  23. power_event_41 = 999 # 待设备实现
  24. ic_consume_event_48 = 48 # ic卡花钱的时候,会上报此事件
  25. part_sn_event = 49 # 组件上报相关信息
  26. card_is_normal = 1
  27. card_not_in_db = 2
  28. card_is_forzen = 3
  29. card_has_not_order = 4 # IC卡适用
  30. card_less_balance = 5 # ID卡适用
  31. card_type_is_ic = 6 # IC卡不允许当做ID卡使用
  32. no_load_code = 7
  33. class builder(EventBuilder):
  34. def __getEvent__(self, device_event):
  35. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  36. if event_data is None:
  37. return None
  38. if event_data['fun_code'] in [created_order_32, executing_order_33, finished_order_34, id_card_request_35,
  39. card_recharge_order_37]:
  40. return ChargingWEIFULEWorkEvent(self.deviceAdapter, event_data)
  41. if event_data['fun_code'] in [fault_event_mcu_36, fault_event_overload_38, fault_event_relay_39,
  42. fault_event_counter_40]:
  43. return WEIFULEFaultEvent(self.deviceAdapter, event_data)
  44. if event_data['fun_code'] in [ic_consume_event_48]:
  45. return WEIFULEICCardConsume(self.deviceAdapter, event_data)
  46. if event_data['fun_code'] in [power_event_41]:
  47. return WEIFULEPowerEvent(self.deviceAdapter, event_data)
  48. class WEIFULEPowerEvent(WorkEvent):
  49. def do(self, **args):
  50. power = int(self.event_data['power'])
  51. orderNo = str(self.event_data['orderNo'])
  52. # PowerInfoManager.instence().append_power(orderNo, power)
  53. class WEIFULEICCardConsume(FaultEvent):
  54. def do(self, **args):
  55. cardNo = str(int(self.event_data['card_no'], 16))
  56. stamp = self.event_data['stamp']
  57. isCopy = WeifuleCardStamp.is_copy_card(cardNo, self.device['ownerId'], stamp)
  58. if isCopy:
  59. self.event_data.update({
  60. 'faultName': u'复制卡告警',
  61. 'faultCode': FAULT_CODE.COPY_CARD,
  62. 'level': FAULT_LEVEL.CRITICAL,
  63. 'desc': u'卡号为:%s的卡,极可能是复制卡,建议冻结处理。' % cardNo
  64. })
  65. super(WEIFULEICCardConsume, self).do()
  66. newObj = WeifuleCardStamp(
  67. cardNo=cardNo,
  68. dealerId=self.device['ownerId'],
  69. stamp=str(stamp),
  70. dateTimeAdded=datetime.datetime.now()
  71. )
  72. newObj.save()
  73. class WEIFULEFaultEvent(FaultEvent):
  74. def do(self, **args):
  75. if self.event_data['fun_code'] == fault_event_mcu_36:
  76. self.event_data.update({
  77. 'faultName': u'单片机告警',
  78. 'faultCode': FAULT_CODE.MCU_REBOOT,
  79. 'level': FAULT_LEVEL.NORMAL,
  80. 'desc': u'充电主板上的单片机重启。'
  81. })
  82. elif self.event_data['fun_code'] == fault_event_relay_39:
  83. self.event_data.update({
  84. 'faultName': u'继电器告警',
  85. 'port': int(self.event_data['port']),
  86. 'faultCode': FAULT_CODE.RELAY_FAULT,
  87. 'level': FAULT_LEVEL.CRITICAL,
  88. 'desc': u'继电器发送粘连。'
  89. })
  90. elif self.event_data['fun_code'] == fault_event_counter_40:
  91. self.event_data.update({
  92. 'faultName': u'计量芯片告警',
  93. 'port': int(self.event_data['port']),
  94. 'faultCode': FAULT_CODE.COUNTER_FAULT,
  95. 'level': FAULT_LEVEL.CRITICAL,
  96. 'desc': u'计量芯片获取功率失败。'
  97. })
  98. elif self.event_data['fun_code'] == fault_event_overload_38:
  99. self.event_data.update({
  100. 'faultName': u'整机功率过载告警',
  101. 'faultCode': FAULT_CODE.DEV_OVERLOAD,
  102. 'level': FAULT_LEVEL.FATAL,
  103. 'desc': u'整机功率超过7500瓦。'
  104. })
  105. else:
  106. pass
  107. super(WEIFULEFaultEvent, self).do()
  108. class ChargingWEIFULEWorkEvent(WeiFuLePolicyProcess):
  109. # 微付乐的板子:根据设备上报上来的订单,创建正在服务的信息
  110. def translate_reason(self, order):
  111. cause = order.get('cause')
  112. if cause == 0:
  113. if self.duration < self.refundProtectionTime:
  114. return u'充电已结束,如有异常情况,请联系本台设备经销商。'
  115. else:
  116. return u'订购的套餐已用完。'
  117. elif cause == 1:
  118. return u'用户拔掉充电器,或者插座脱落。'
  119. elif cause == 2:
  120. return u'用户刷卡停止充电。'
  121. elif cause == 3:
  122. return u'远程停止。'
  123. elif cause == 4:
  124. return u'整机过载,系统为了安全,关闭掉所有充电端口。'
  125. elif cause == 5:
  126. return u'充电端口电流过载,系统为了安全,关闭此充电端口。'
  127. elif cause == 6:
  128. return u'端口功率过载,系统为了安全,关闭此充电端口。'
  129. elif cause == 7:
  130. return u'端口空载。可能是插座松动、充电端口故障、或者充电电池故障。'
  131. elif cause == 8:
  132. return u'恭喜您电池已经充满。'
  133. elif cause == 9:
  134. if self.duration < self.refundProtectionTime:
  135. return u'充电已结束,如有异常情况,请联系设备经销商。'
  136. else:
  137. return u'套餐金额已用完'
  138. elif cause == 12:
  139. if self.duration < self.refundProtectionTime:
  140. return u'充电已结束,如有异常情况,请联系本台设备经销商。'
  141. else:
  142. return u'订购的时间已用完'
  143. elif cause == 13:
  144. if self.duration < self.refundProtectionTime:
  145. return u'充电已结束,如有异常情况,请联系本台设备经销商。'
  146. else:
  147. return u'订购的电量已用完'
  148. return u'充电结束。'
  149. def deal_with_ic_charge_event(self, msgDict):
  150. cardNo = str(int(self.event_data['card_no'], 16))
  151. card = self.update_card_dealer_and_type(cardNo, 'IC')
  152. if not card:
  153. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_not_in_db)
  154. elif card.frozen:
  155. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_is_forzen)
  156. preBalance = RMB(self.event_data['balance'] / 100.0)
  157. self.update_balance_for_IC_card(card, preBalance)
  158. rechargeOrder = CardRechargeOrder.get_last_to_do_one(str(card.id))
  159. if rechargeOrder:
  160. self.recharge_ic_card(card=card,
  161. preBalance=preBalance,
  162. rechargeType='append',
  163. order=rechargeOrder,
  164. need_verify=False)
  165. else:
  166. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_has_not_order)
  167. def analyse_need_from_package(self, order):
  168. needKind, needValue, unit = 'needElec', 0, u'度'
  169. if order['chrmt'] == 'TIME':
  170. needKind = 'needTime'
  171. needValue = order['amount_time'] / 60
  172. unit = u'分钟'
  173. else:
  174. needValue = order['amount_elec'] / 1000000.0
  175. return needKind, needValue, unit
  176. def do(self, **args):
  177. devNo = self.device['devNo']
  178. funCode = self.event_data['fun_code']
  179. if funCode == card_recharge_order_37: # 如果是卡充值,直接回复订单
  180. self.deal_with_ic_charge_event(self.event_data)
  181. elif funCode == id_card_request_35:
  182. self.response_id_card()
  183. else: # 处理任务事件
  184. order = self.event_data['order']
  185. logger.info('weifule charging event detected, devNo=%s' % (devNo,))
  186. with memcache_lock(key='%s-%s-%s-finished' % (devNo, order['id'], funCode), value='1',
  187. expire=120) as acquired:
  188. if acquired:
  189. self._do_ack_order(order)
  190. try:
  191. if funCode == created_order_32:
  192. self._do_created_order_32(order)
  193. elif funCode == executing_order_33:
  194. self._do_exec_order_33(order)
  195. elif funCode == finished_order_34 and order['order_type'] != 'card_charge':
  196. self._do_finished_order_34(order)
  197. elif funCode == finished_order_34 and order['order_type'] == 'card_charge':
  198. self.update_card_recharge_for_success_event(order['id'], RMB(order['balance'] / 100.0))
  199. except Exception:
  200. import traceback
  201. logger.warn(traceback.format_exc())
  202. logger.info('deal order is finished < funCode: {} order: {} >'.format(funCode, order.get('id')))
  203. else:
  204. logger.info('weifule charging event is doing !!!, devNo=%s' % (devNo,))
  205. def recharge_ic_card(self, card, preBalance, rechargeType, order, need_verify=True):
  206. # type:(Card, RMB, str, CardRechargeOrder, bool)->bool
  207. """
  208. # rechargeType有两种,一种是用直接覆写overwrite的方式,一种是append追加钱的方式。
  209. # 不同的的设备,充值的方式还不一样.注意:money是实际用户付的钱,coins是给用户充值的钱,比如付10块(money),充15(coins)。
  210. :param card:
  211. :param preBalance:
  212. :param rechargeType:
  213. :param order:
  214. :return:
  215. """
  216. if not order or order.coins == RMB(0):
  217. return False
  218. status = Card.get_card_status(str(card.id))
  219. if status == 'busy':
  220. return False
  221. Card.set_card_status(str(card.id), 'busy')
  222. try:
  223. # IC卡需要下发到设备,设备写卡,把余额打入卡中
  224. if rechargeType == 'overwrite':
  225. sendMoney = preBalance + order.coins
  226. else:
  227. sendMoney = order.coins
  228. # 先判断order最近一次充值是否OK. 满足三个条件在认为上次充值成功:
  229. # 1、操作时间已经超过三天
  230. # 2、操作结果是串口超时, 即result == 1
  231. # 3、当前余额大于最后一次充值操作的充值前余额
  232. if need_verify and len(order.operationLog) > 0:
  233. log = order.operationLog[-1]
  234. result = log['result']
  235. time_delta = (datetime.datetime.now() - log['time']).total_seconds()
  236. last_pre_balance = RMB(log['preBalance'])
  237. if (result == ErrorCode.DEVICE_CONN_FAIL or result == ErrorCode.BOARD_UART_TIMEOUT) \
  238. and (time_delta > 3 * 24 * 3600 or preBalance > last_pre_balance):
  239. logger.debug('{} recharge verify result is finished.'.format(repr(card)))
  240. order.update_after_recharge_ic_card(device=self.device,
  241. sendMoney=sendMoney,
  242. preBalance=preBalance,
  243. result=ErrorCode.SUCCESS,
  244. description=u'充值校验结束')
  245. # 现将订单状态改为待充值
  246. CardRechargeRecord.add_record(
  247. card=card,
  248. group=Group.get_group(order.groupId),
  249. order=order,
  250. device=self.device
  251. )
  252. return False
  253. if self.device.support_reliable: # 如果是新版本的,只管发,结果根据异步的事件进行处理
  254. self.deviceAdapter.recharge_card_async(card.cardNo, sendMoney, str(order.id))
  255. return False
  256. else:
  257. operation_result, balance = self.deviceAdapter.recharge_card(card.cardNo, sendMoney, str(order.id))
  258. order.update_after_recharge_ic_card(device=self.device,
  259. sendMoney=sendMoney,
  260. preBalance=preBalance,
  261. syncBalance=balance,
  262. result=operation_result['result'],
  263. description=operation_result['description'])
  264. if operation_result['result'] != ErrorCode.SUCCESS:
  265. return False
  266. if not balance:
  267. balance = preBalance + order.coins
  268. CardRechargeRecord.add_record(
  269. card=card,
  270. group=Group.get_group(order.groupId),
  271. order=order,
  272. device=self.device
  273. )
  274. # 刷新卡里面的余额
  275. card.balance = balance
  276. card.lastMaxBalance = balance
  277. card.save()
  278. return True
  279. except Exception as e:
  280. logger.exception(e)
  281. return False
  282. finally:
  283. Card.set_card_status(str(card.id), 'idle')