weifule_policy_classic.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from typing import TYPE_CHECKING
  6. from apilib.monetary import RMB
  7. from apilib.utils_sys import memcache_lock
  8. from apps.web.constant import ErrorCode
  9. from apps.web.device.models import Group
  10. from apps.web.eventer import EventBuilder
  11. from apps.web.eventer.weifuleCommon import WeiFuLeStatusEvent, WeiFuLePolicyProcess
  12. from apps.web.user.models import ServiceProgress, Card, CardRechargeOrder, CardRechargeRecord, UserVirtualCard
  13. logger = logging.getLogger(__name__)
  14. created_order_32 = 32
  15. exec_order_33 = 33
  16. finished_order_34 = 34
  17. id_card_request_35 = 35
  18. card_recharge_order_36 = 36
  19. status_change_event_44 = 44
  20. ic_consume_event_48 = 48 # ic卡花钱的时候,会上报此事件
  21. part_sn_event = 49 # 组件上报相关信息
  22. card_is_normal = 1
  23. card_not_in_db = 2
  24. card_is_forzen = 3
  25. card_has_not_order = 4 # IC卡适用
  26. card_less_balance = 5 # ID卡适用
  27. card_type_is_ic = 6 # IC卡不允许当做ID卡使用
  28. no_load_code = 7
  29. if TYPE_CHECKING:
  30. from apps.web.core.adapter.base import SmartBox
  31. from apps.web.core.adapter.weifule_policy import POLICYBox
  32. class builder(EventBuilder):
  33. def __getEvent__(self, device_event):
  34. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  35. if event_data is None:
  36. return None
  37. if event_data['fun_code'] in [created_order_32, exec_order_33, finished_order_34, id_card_request_35,
  38. card_recharge_order_36]:
  39. return ChargingSocketWorkEvent(self.deviceAdapter, event_data)
  40. if event_data['fun_code'] in [status_change_event_44]:
  41. return WeiFuLeStatusEvent(self.deviceAdapter, device_event)
  42. class ChargingSocketWorkEvent(WeiFuLePolicyProcess):
  43. def __init__(self, smartBox, event_data):
  44. # type:(SmartBox,dict)->None
  45. super(ChargingSocketWorkEvent, self).__init__(smartBox, event_data)
  46. self.deviceAdapter = smartBox # type: POLICYBox
  47. def create_progress_for_socket_order(self, consumeRcd, devInfo):
  48. try:
  49. port = int(devInfo['port'])
  50. progress = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=port,
  51. devTypeCode=self.device.devTypeCode).first()
  52. if not progress:
  53. progress = ServiceProgress(device_imei=self.device.devNo, port=port,
  54. devTypeCode=self.device.devTypeCode)
  55. progress.start_time = devInfo['create_time']
  56. progress.finished_time = devInfo['create_time'] + 60 * 60 * 12
  57. progress.isFinished = False
  58. else:
  59. if devInfo['id'] in progress.consumes:
  60. return
  61. if progress.isFinished == False:
  62. progress.finished_time = progress.finished_time + 60 * 60 * 12
  63. else:
  64. progress.consumes = []
  65. progress.start_time = devInfo['create_time']
  66. progress.finished_time = devInfo['create_time'] + devInfo.get('amount_time', 60 * 60 * 12)
  67. progress.isFinished = False
  68. progress.open_id = consumeRcd.openId
  69. progress.consumes.append(devInfo['id'])
  70. progress.status = 'running'
  71. progress.save()
  72. except Exception as e:
  73. logger.exception(e)
  74. def do(self, **args):
  75. devNo = self.device['devNo']
  76. funCode = self.event_data.get('fun_code')
  77. order = self.event_data.get('order', {})
  78. if funCode == id_card_request_35:
  79. return self.response_id_card()
  80. logger.info('weifule charging event detected, devNo=%s' % (devNo,))
  81. with memcache_lock(key='%s-%s-%s-finished' % (devNo, order.get('id'), funCode), value='1',
  82. expire=120) as acquired:
  83. if acquired:
  84. self._do_ack_order(order)
  85. try:
  86. if funCode == created_order_32:
  87. self._do_created_order_32(order)
  88. elif funCode == exec_order_33:
  89. self._do_exec_order_33(order)
  90. elif funCode == finished_order_34 and order['order_type'] != 'card_charge':
  91. self._do_finished_order_34(order)
  92. elif funCode == finished_order_34 and order['order_type'] == 'card_charge':
  93. self.update_card_recharge_for_success_event(order['id'], RMB(order['balance'] / 100.0))
  94. elif funCode == card_recharge_order_36: # 如果是卡充值,直接回复订单
  95. self.deal_with_ic_charge_event()
  96. except Exception:
  97. import traceback
  98. logger.warn(traceback.format_exc())
  99. logger.info('deal order is finished < funCode: {} order: {} >'.format(funCode, order.get('id')))
  100. else:
  101. logger.info('weifule charging event is doing !!!, devNo=%s' % (devNo,))
  102. def translate_reason(self, order):
  103. cause = order.get('cause')
  104. if cause == 1:
  105. if self.duration < self.refundProtectionTime:
  106. return u'充电已结束,如有异常情况,请联系本台设备经销商。'
  107. else:
  108. return u'订购的套餐已用完。'
  109. elif cause == 2:
  110. return u'用户远程停止。'
  111. elif cause == 3:
  112. return u'管理员操作停止。'
  113. elif cause == 4:
  114. return u'经销商远程停止。'
  115. elif cause == 5:
  116. return u'用户拔掉充电器,或者插座脱落。'
  117. elif cause == 6:
  118. return u'端口功率过载,系统为了安全,关闭此充电端口。'
  119. elif cause == 7:
  120. return u'整机电压过载,系统为了安全,关闭所有充电端口。'
  121. elif cause == 8:
  122. return u'端口电流过载,系统为了安全,关闭此充电端口。'
  123. elif cause == 9:
  124. return u'整机功率超限,系统为了安全,关闭所有充电端口。'
  125. elif cause == 10:
  126. return u'检测到温度超限,系统为了安全,关闭所有充电端口。'
  127. elif cause == 11:
  128. return u'恭喜您电池已经充满'
  129. elif cause == 12:
  130. if self.duration < self.refundProtectionTime:
  131. return u'充电已结束,如有异常情况,请联系本台设备经销商。'
  132. else:
  133. return u'订购的时间已用完'
  134. elif cause == 13:
  135. if self.duration < self.refundProtectionTime:
  136. return u'充电已结束,如有异常情况,请联系本台设备经销商。'
  137. else:
  138. return u'订购的电量已用完'
  139. elif cause == 0x0E:
  140. return u"当前充电功率超过套餐允许最大功率"
  141. elif cause == 20:
  142. return u'端口功率过小。可能是电池已经充满,也可能是所接负载功率太小'
  143. return u'充电结束。'
  144. def deal_with_ic_charge_event(self):
  145. cardNo = self.event_data['card_no']
  146. card = self.update_card_dealer_and_type(cardNo, 'IC')
  147. if not card:
  148. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_not_in_db)
  149. elif card.frozen:
  150. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_is_forzen)
  151. preBalance = card.balance
  152. rechargeOrder = CardRechargeOrder.get_last_to_do_one(str(card.id))
  153. if rechargeOrder:
  154. self.recharge_ic_card(card=card,
  155. preBalance=preBalance,
  156. rechargeType='append',
  157. order=rechargeOrder,
  158. need_verify=False)
  159. else:
  160. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_has_not_order)
  161. def recharge_ic_card(self, card, preBalance, rechargeType, order, need_verify=True):
  162. # type:(Card, RMB, str, CardRechargeOrder, bool)->bool
  163. """
  164. # rechargeType有两种,一种是用直接覆写overwrite的方式,一种是append追加钱的方式。
  165. # 不同的的设备,充值的方式还不一样.注意:money是实际用户付的钱,coins是给用户充值的钱,比如付10块(money),充15(coins)。
  166. :param card:
  167. :param preBalance:
  168. :param rechargeType:
  169. :param order:
  170. :return:
  171. """
  172. if not order or order.coins == RMB(0):
  173. return False
  174. status = Card.get_card_status(str(card.id))
  175. if status == 'busy':
  176. return False
  177. Card.set_card_status(str(card.id), 'busy')
  178. try:
  179. # IC卡需要下发到设备,设备写卡,把余额打入卡中
  180. if rechargeType == 'overwrite':
  181. sendMoney = preBalance + order.coins
  182. else:
  183. sendMoney = order.coins
  184. # 先判断order最近一次充值是否OK. 满足三个条件才认为上次充值成功:
  185. # 1、操作时间已经超过三天
  186. # 2、操作结果是串口超时, 即result == 1
  187. # 3、当前余额大于最后一次充值操作的充值前余额
  188. if need_verify and len(order.operationLog) > 0:
  189. log = order.operationLog[-1]
  190. result = log['result']
  191. time_delta = (datetime.datetime.now() - log['time']).total_seconds()
  192. last_pre_balance = RMB(log['preBalance'])
  193. if (result == ErrorCode.DEVICE_CONN_FAIL or result == ErrorCode.BOARD_UART_TIMEOUT) \
  194. and (time_delta > 3 * 24 * 3600 or preBalance > last_pre_balance):
  195. logger.debug('{} recharge verify result is finished.'.format(repr(card)))
  196. order.update_after_recharge_ic_card(device=self.device,
  197. sendMoney=sendMoney,
  198. preBalance=preBalance,
  199. result=ErrorCode.SUCCESS,
  200. description=u'充值校验结束')
  201. CardRechargeRecord.add_record(
  202. card=card,
  203. group=Group.get_group(order.groupId),
  204. order=order,
  205. device=self.device)
  206. return False
  207. try:
  208. operation_result, balance = self.deviceAdapter.recharge_card(card.cardNo, sendMoney,
  209. orderNo=str(order.id))
  210. order.update_after_recharge_ic_card(device=self.device,
  211. sendMoney=sendMoney,
  212. preBalance=preBalance,
  213. syncBalance=balance,
  214. result=operation_result['result'],
  215. description=operation_result['description'])
  216. if operation_result['result'] != ErrorCode.SUCCESS:
  217. return False
  218. if not balance:
  219. balance = preBalance + order.coins
  220. CardRechargeRecord.add_record(
  221. card=card,
  222. group=Group.get_group(order.groupId),
  223. order=order,
  224. device=self.device)
  225. # 刷新卡里面的余额
  226. card.balance = balance
  227. card.lastMaxBalance = balance
  228. card.save()
  229. return True
  230. except Exception as e:
  231. order.update_after_recharge_ic_card(device=self.device,
  232. sendMoney=sendMoney,
  233. preBalance=preBalance,
  234. syncBalance=balance,
  235. result=ErrorCode.EXCEPTION,
  236. description=e.message)
  237. return False
  238. except Exception as e:
  239. logger.exception(e)
  240. return False
  241. finally:
  242. Card.set_card_status(str(card.id), 'idle')
  243. def prepaid_end_for_app_start(self, order):
  244. """
  245. :param order: 主板上报的 object order 信息
  246. """
  247. # 虚拟卡支付的
  248. if self.consumeRcd and self.consumeRcd.virtual_card_id:
  249. ue = order["elec"] / 1000 * 1000
  250. ut = order["time"] / 60.0
  251. vcardRcd = UserVirtualCard.objects.get(id=self.consumeRcd.virtual_card_id) # type: UserVirtualCard
  252. modified, consumeTotal, consumeDay = vcardRcd.clear_frozen_quota(str(self.consumeRcd.id), ut, ue, 0)
  253. # 支付完成之后 穿件一笔消费记录
  254. if not modified:
  255. return
  256. vcardRcd.new_consume_record(self.device, self.consumeRcd.user, consumeTotal)
  257. else:
  258. super(ChargingSocketWorkEvent, self).prepaid_end_for_app_start(order)