jiuheng_baoxiansi.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from mongoengine import DoesNotExist
  6. from apilib.monetary import RMB
  7. from apilib.utils_datetime import to_datetime
  8. from apps.web.constant import Const
  9. from apps.web.device.models import Device, Group
  10. from apps.web.eventer.base import WorkEvent
  11. from apps.web.eventer import EventBuilder
  12. from apps.web.south_intf.platform import notify_event_to_north
  13. from apps.web.south_intf.zhejiang_fire import send_event_to_zhejiang
  14. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, MyUser
  15. from apps.web.user.transaction_deprecated import refund_money
  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 event_data is None or 'cmdCode' not in event_data:
  21. return None
  22. if 'duration' in device_event:
  23. event_data.update({'duration': device_event['duration']})
  24. if event_data['cmdCode'] in ['06']:
  25. return ChargingJNDZWorkEvent(self.deviceAdapter, event_data)
  26. return None
  27. class ChargingJNDZWorkEvent(WorkEvent):
  28. def do(self, **args):
  29. devNo = self.device['devNo']
  30. logger.info('jingnengdianzi charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
  31. if self.event_data['cmdCode'] == '06': # 结束的命令
  32. try:
  33. lineInfo = Device.update_port_control_cache(devNo, self.event_data)
  34. group = Group.get_group(self.device['groupId'])
  35. if not lineInfo.has_key('coins'):
  36. return
  37. if 'duration' in self.event_data and self.event_data['duration'] > 0:
  38. usedTime = self.event_data['duration']
  39. else:
  40. if (not lineInfo) or (not lineInfo.has_key('startTime')):
  41. return
  42. startTime = to_datetime(lineInfo['startTime'])
  43. nowTime = datetime.datetime.now()
  44. if startTime > nowTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
  45. usedTime = 0
  46. else:
  47. usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
  48. cardId = lineInfo.get('cardId', '')
  49. vCardId = lineInfo.get('vCardId', None)
  50. money = RMB(lineInfo['coins'])
  51. price = lineInfo.get('price', 0.0)
  52. leftTime = self.event_data['leftTime']
  53. refundProtection = lineInfo.get('refundProtection', 0)
  54. backCoins, backPrice = 0.0, 0.0
  55. if leftTime == 65535:
  56. actualNeedTime = 0
  57. backCoins = money
  58. backPrice = price
  59. usedTime = 0
  60. else:
  61. actualNeedTime = usedTime + leftTime
  62. leftTimeStr = leftTime
  63. needTime = lineInfo['needTime']
  64. backCoins = money * (float(leftTime) / float(actualNeedTime))
  65. # refundProtection 开关, 控制 5 分钟内全额退款
  66. if (refundProtection == 1 and usedTime < 5) and backCoins != 0:
  67. backCoins = money
  68. if backCoins > money:
  69. backCoins = money
  70. backPrice = round(price * float(backCoins) / float(money), 2)
  71. if cardId == '' and vCardId is None: # 扫码的方式
  72. openId = lineInfo['openId']
  73. leftTimeStr = leftTime if leftTime != 65535 else needTime
  74. title = u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % (
  75. self.event_data['reason'],
  76. actualNeedTime,
  77. leftTimeStr)
  78. # 通知充电完成
  79. user = MyUser.objects(openId = openId, groupId = self.device['groupId']).first()
  80. self.notify_user(user.managerialOpenId, 'service_complete',
  81. **{
  82. 'title': title,
  83. 'service': u'充电服务(设备编号:%s,端口:%s,地址:%s)' % (
  84. self.device['logicalCode'], self.event_data['port'], group['address']),
  85. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  86. 'remark': u'谢谢您的支持'
  87. })
  88. consumeDict = {'chargeIndex': lineInfo['port'],
  89. 'reason': lineInfo['reason'],
  90. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  91. 'duration': usedTime}
  92. leftTimeStr = leftTime if leftTime != 65535 else needTime
  93. consumeDict.update({'leftTime': leftTimeStr, 'needTime': u'扫码订购%s分钟' % needTime})
  94. # 如果需要退款,计算退款数据.
  95. if not self.device.is_auto_refund:
  96. ServiceProgress.update_progress_and_consume_rcd(
  97. self.device['ownerId'],
  98. {'open_id': openId, 'device_imei': self.device['devNo'],
  99. 'port': lineInfo['port'], 'isFinished': False}, consumeDict
  100. )
  101. else:
  102. # 扫码退钱, 退到个人账号
  103. refund_money(self.device, backCoins, lineInfo['openId'])
  104. consumeDict.update({'refundedMoney': str(backCoins)})
  105. ServiceProgress.update_progress_and_consume_rcd(
  106. self.device['ownerId'],
  107. {'open_id': openId, 'device_imei': self.device['devNo'],
  108. 'port': lineInfo['port'], 'isFinished': False}, consumeDict)
  109. leftTimeStr = leftTime if leftTime != 65535 else needTime
  110. desc = u'您使用的%s号端口充电,共付款:%s元,充电预定时间为:%s分钟,剩余时间:%s分钟,给您退款:%s元' % (
  111. lineInfo['port'], money, needTime, leftTimeStr, backCoins)
  112. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  113. 'title': desc,
  114. 'backCount': u'金币:%s' % backCoins,
  115. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  116. })
  117. elif vCardId is not None: # 使用的是虚拟卡
  118. leftTimeStr = leftTime if leftTime != 65535 else needTime
  119. title = u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % (
  120. self.event_data['reason'],
  121. actualNeedTime,
  122. leftTimeStr)
  123. # 通知充电完成
  124. try:
  125. vCard = UserVirtualCard.objects.get(id = vCardId)
  126. except DoesNotExist, e:
  127. logger.info('can not find the vCard id = %s' % vCardId)
  128. return
  129. self.notify_user(self.get_managerialOpenId_by_openId(lineInfo['openId']), 'service_complete',
  130. **{
  131. 'title': title,
  132. 'service': u'充电服务(设备编号:%s,端口:%s,地址:%s)' % (
  133. self.device['logicalCode'], self.event_data['port'], group['address']),
  134. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  135. 'remark': u'谢谢您的支持'
  136. })
  137. consumeDict = {'chargeIndex': lineInfo['port'],
  138. 'reason': lineInfo['reason'], 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  139. 'duration': usedTime}
  140. ServiceProgress.update_progress_and_consume_rcd(
  141. self.device['ownerId'],
  142. {'open_id': lineInfo['openId'], 'device_imei': self.device['devNo'],
  143. 'port': lineInfo['port'], 'isFinished': False}, consumeDict
  144. )
  145. consumeRcdId = lineInfo.get('consumeRcdId', None)
  146. if consumeRcdId is None:
  147. logger.info('can not find consume rcd id')
  148. return
  149. try:
  150. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  151. except DoesNotExist, e:
  152. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  153. return
  154. vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, backCoins.mongo_amount)
  155. except Exception, e:
  156. logger.exception('deal with jingneng devNo=%s event e=%s' % (devNo, e))
  157. finally:
  158. Device.clear_port_control_cache(devNo, str(self.event_data['port']))
  159. dataDict = {'backMoney': backPrice, 'backCoins': backCoins.mongo_amount}
  160. if lineInfo.has_key('orderNo'):
  161. dataDict.update({'orderNo': lineInfo['orderNo']})
  162. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  163. desc = self.event_data['reason'], dataDict = dataDict)
  164. send_event_to_zhejiang(self.dealer, self.device, self.event_data)