dekang.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python
  3. import datetime
  4. import logging
  5. from apilib.monetary import RMB, VirtualCoin, Ratio
  6. from apilib.utils_datetime import to_datetime
  7. from apps.web.constant import DEALER_CONSUMPTION_AGG_KIND
  8. from apps.web.device.models import Device, Group
  9. from apps.web.eventer.base import WorkEvent
  10. from apps.web.eventer import EventBuilder
  11. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, MyUser, ConsumeRecord
  12. logger = logging.getLogger(__name__)
  13. class builder(EventBuilder):
  14. def __getEvent__(self, device_event):
  15. if device_event['cmd'] == 100:
  16. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  17. return DeKangEvent(self.deviceAdapter, event_data)
  18. return None
  19. class DeKangEvent(WorkEvent):
  20. def __init__(self, smartBox, event_data):
  21. super(DeKangEvent, self).__init__(smartBox, event_data)
  22. def do(self, **args):
  23. """
  24. 状态:
  25. 00 : 未插 空闲 AA5524019B010000000008CA000000 00 000000000000000000000000000000000000000000B409BB
  26. 11 : 插上 检测负载 AA5524019B010000000008CA000000 11 0000000000000000000000000000000000000000002AD9BB
  27. 12 : 付款 继电器连接 AA5524019B01000000000000043B3B 12 1400000000000000000000000000000000000000003401BB
  28. 13 : 付款 继电器断开 AA5524019B010000000025D404330B 13 1400000000000000000000000000000000000000005529BB
  29. 52 : 启动 使用 AA5524019B01000000000000043B3A 52 14000000000000000000000000000000000000000065B1BB
  30. :param args:
  31. :return:
  32. """
  33. devNo = self.device['devNo']
  34. portStatus = self.event_data.get('portStatus')
  35. portStr = self.event_data.pop('portStr')
  36. if portStatus in ['0000', '0001', '0100']: # 0000:未插空闲 (拔插头) #0001 负载接入状态 #0100 充电完成
  37. self.do_finished_or_update_cache(portStr)
  38. elif portStatus in ['0010', '0011']:
  39. portInfo = Device.get_dev_control_cache(devNo).get(portStr, {})
  40. needTime = portInfo.get('needTime') # 第一次上报初始化一个最大时间
  41. if not needTime:
  42. portInfo.update({'needTime': self.event_data.get('leftTime')})
  43. portInfo.update(self.event_data)
  44. Device.update_dev_control_cache(devNo, {portStr: portInfo})
  45. else:
  46. logger.error('undefine port status! dev: %s port: %s status: %s' % (devNo, portStr, portStatus))
  47. def do_finished_or_update_cache(self, portStr):
  48. devNo = self.device.devNo
  49. lineInfo = Device.get_dev_control_cache(devNo).get(portStr, {})
  50. orderNo = lineInfo.get('orderNo')
  51. if not self.check_order_status(orderNo):
  52. # 主板切换到状态 却没有 缓存信息 说明是 启动用户 否则则为 结束用户
  53. Device.clear_port_control_cache(devNo, portStr)
  54. Device.update_port_control_cache(devNo, self.event_data)
  55. logger.info('devNo=<{}> port=<{}> data={}> now do Cache updating'.format(devNo, portStr, self.event_data))
  56. return
  57. openId = lineInfo.get('openId')
  58. coins = VirtualCoin(lineInfo['coins'])
  59. price = RMB(lineInfo['price'])
  60. actualNeedTime = lineInfo.get('needTime') # 总共需要时间
  61. if not actualNeedTime:
  62. Device.clear_port_control_cache(devNo, portStr)
  63. Device.update_port_control_cache(devNo, self.event_data)
  64. return
  65. startTime = to_datetime(lineInfo['startTime'])
  66. nowTime = datetime.datetime.now()
  67. usedTime = ((nowTime - startTime).total_seconds() + 59) / 60
  68. if usedTime > actualNeedTime:
  69. usedTime = actualNeedTime
  70. leftTime = actualNeedTime - usedTime
  71. refundProtectionTime = self.device['otherConf'].get('refundProtectionTime', 5)
  72. if usedTime <= refundProtectionTime:
  73. backCoins = VirtualCoin(coins)
  74. refundRMB = RMB(price)
  75. else:
  76. if self.device.is_auto_refund:
  77. backCoins = coins * Ratio(float(leftTime) / float(actualNeedTime))
  78. refundRMB = price * Ratio(float(leftTime) / float(actualNeedTime))
  79. else:
  80. backCoins = VirtualCoin(0)
  81. refundRMB = RMB(0)
  82. try:
  83. title = u'您的充电服务已结束,端口已经断开连接,感谢您的使用! '
  84. vCardId = lineInfo.get('vCardId', None)
  85. user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
  86. group = Group.get_group(self.device['groupId'])
  87. self.notify_user(user.managerialOpenId, 'service_complete',
  88. **{
  89. 'title': title,
  90. 'service': u'充电服务(设备编号:%s,分机:%s,地址:%s)' % (
  91. self.device['logicalCode'], portStr, group['address']),
  92. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  93. 'remark': u'谢谢您的支持'
  94. })
  95. logger.info('notify user completed!')
  96. # 处理退费!!
  97. # 扫码支付
  98. if not vCardId:
  99. # 服务结束通知
  100. consumeDict = {
  101. 'reason': u'充电结束',
  102. 'needTime': actualNeedTime,
  103. DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime,
  104. DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount
  105. }
  106. logger.info('refund money start!')
  107. if backCoins > VirtualCoin(0) or refundRMB > RMB(0):
  108. payInfo = lineInfo.get('payInfo')
  109. refundCash = 'refundRMB_device_event' in self.device.owner.features
  110. extra = {'title': u'退款通知', 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
  111. if refundCash and payInfo:
  112. self.refund_net_pay(user, lineInfo, refundRMB, VirtualCoin(0), consumeDict, True)
  113. consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (price - refundRMB).mongo_amount})
  114. extra.update({'backCount': u'金额:%s' % refundRMB})
  115. else:
  116. self.refund_net_pay(user, lineInfo, RMB(0), backCoins, consumeDict, False)
  117. extra.update({'backCount': u'金币:%s' % backCoins})
  118. # 退款通知
  119. self.notify_user(user.managerialOpenId, 'refund_coins',**extra)
  120. logger.info('server complete, no money refund!')
  121. # 虚拟卡支付
  122. else:
  123. # 通知充电完成
  124. vCard = UserVirtualCard.objects.filter(id=vCardId).first()
  125. if not vCard:
  126. logger.info('devNo=<{}> port=<{}> vCardId=<{}> no this vCard'.format(devNo, portStr, vCardId))
  127. consumeDict = {
  128. 'reason': u'充电结束',
  129. DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime,
  130. 'actualNeedTime': actualNeedTime,
  131. }
  132. consumeRcdId = lineInfo.get('consumeRcdId', None)
  133. if consumeRcdId is None:
  134. logger.info('can not find consume rcd id')
  135. return
  136. vCardConsumeRcd = VCardConsumeRecord.objects.filter(id=consumeRcdId).first()
  137. if not vCardConsumeRcd:
  138. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  139. return
  140. # 消费单位都为次 直接用算好的退币进行退款
  141. vCard.refund_quota(vCardConsumeRcd, 0, 0, backCoins.mongo_amount)
  142. ServiceProgress.update_progress_and_consume_rcd(
  143. self.device['ownerId'],
  144. {'open_id': openId, 'device_imei': self.device['devNo'], 'port': int(portStr),
  145. 'isFinished': False},
  146. consumeDict
  147. )
  148. except Exception:
  149. import traceback
  150. logger.info(traceback.format_exc())
  151. finally:
  152. Device.clear_port_control_cache(devNo, portStr)
  153. Device.update_port_control_cache(devNo, self.event_data)
  154. def check_order_status(self, orderNo):
  155. """
  156. 防重入 和 校验信息
  157. :param orderNo:
  158. :return:
  159. """
  160. if not orderNo:
  161. return False
  162. order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
  163. if not order:
  164. return False
  165. if order.status == 'finished':
  166. return False
  167. else:
  168. order.update(status='finished', finishedTime=datetime.datetime.now())
  169. return True