hainiaov2.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import logging
  4. from mongoengine import DoesNotExist
  5. from apilib.monetary import RMB
  6. from apilib.utils_datetime import to_datetime
  7. from apps.web.constant import Const, 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.south_intf.platform import notify_event_to_north
  12. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, Card, MyUser
  13. from apps.web.user.transaction_deprecated import refund_money
  14. logger = logging.getLogger(__name__)
  15. class builder(EventBuilder):
  16. def __getEvent__(self, device_event):
  17. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  18. if not event_data or 'cmdCode' not in event_data:
  19. return None
  20. if 'duration' in device_event:
  21. event_data.update({'duration': device_event['duration']})
  22. if event_data['cmdCode'] in ['86']:
  23. return ChargingHaiNiaoV2WorkEvent(self.deviceAdapter, event_data)
  24. class ChargingHaiNiaoV2WorkEvent(WorkEvent):
  25. def support_playback(self):
  26. return self.event_data['cmdCode'] == '86'
  27. def do(self, **args):
  28. devNo = self.device['devNo']
  29. logger.info('hainiao charging event detected, devNo=%s, curInfo=%s' % (devNo, self.event_data))
  30. if self.event_data['cmdCode'] == '86':
  31. port = str(self.event_data['port'])
  32. reason = self.event_data['reason']
  33. if reason == u'成功!':
  34. return
  35. try:
  36. lineInfo = Device.clear_port_control_cache(self.device['devNo'], str(port))
  37. recvTime = to_datetime(self.recvTime)
  38. if 'duration' in self.event_data and self.event_data['duration'] > 0:
  39. usedTime = self.event_data['duration']
  40. else:
  41. if (not lineInfo) or (not lineInfo.has_key('startTime')):
  42. return
  43. startTime = to_datetime(lineInfo['startTime'])
  44. if startTime > recvTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
  45. usedTime = 0
  46. else:
  47. usedTime = int(round(((recvTime - startTime).total_seconds() / 60.0)))
  48. leftTime = int(self.event_data['leftTime'])
  49. leftTimeStr = self.event_data['leftTime']
  50. actualNeedTime = usedTime + leftTime
  51. group = Group.get_group(self.device['groupId'])
  52. consumeDict = {'reason': reason, 'leftTime': leftTimeStr,
  53. 'chargeIndex': port, 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  54. 'duration': usedTime}
  55. user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device['groupId']).first()
  56. if user is None:
  57. return
  58. # 如果是刷卡的,直接更新消费记录,然后发送通知消息,不支持退费
  59. if lineInfo.has_key('cardNo'):
  60. card = Card.objects(cardNo = lineInfo['cardNo'], agentId = self.dealer.agentId).first()
  61. consumeDict.update({'balance': lineInfo['balance']})
  62. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  63. {'open_id': lineInfo['openId'], 'port': int(port),
  64. 'device_imei': self.device['devNo'],
  65. 'isFinished': False}, consumeDict)
  66. # 通知服务结束
  67. self.notify_user(user.managerialOpenId if user else '', 'service_complete',
  68. **{
  69. 'title': u'%s 卡号:%s,按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % (
  70. reason,
  71. lineInfo['cardNo'],
  72. actualNeedTime,
  73. leftTimeStr),
  74. 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % (
  75. self.device['logicalCode'], port, group['address']),
  76. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  77. 'remark': u'谢谢您的支持'
  78. })
  79. elif lineInfo.has_key('consumeRcdId'):
  80. coins = RMB(lineInfo['coins'])
  81. backCoins = coins * (float(leftTime) / float(actualNeedTime))
  82. try:
  83. vCardId = lineInfo['vCardId']
  84. vCard = UserVirtualCard.objects.get(id = vCardId)
  85. except DoesNotExist, e:
  86. logger.info('can not find the vCard id = %s' % vCardId)
  87. return
  88. # 通知服务结束
  89. self.notify_user(user.managerialOpenId if user else '',
  90. 'service_complete',
  91. **{
  92. 'title': u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % (
  93. reason,
  94. actualNeedTime,
  95. leftTimeStr),
  96. 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % (
  97. self.device['logicalCode'], port, group['address']),
  98. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  99. 'remark': u'谢谢您的支持'
  100. })
  101. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  102. {'open_id': lineInfo['openId'], 'port': int(port),
  103. 'device_imei': self.device['devNo'],
  104. 'isFinished': False}, consumeDict)
  105. consumeRcdId = lineInfo.get('consumeRcdId', None)
  106. if consumeRcdId is None:
  107. logger.info('can not find consume rcd id')
  108. return
  109. try:
  110. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  111. except DoesNotExist, e:
  112. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  113. return
  114. vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, backCoins.mongo_amount)
  115. else:
  116. # 通知服务结束
  117. self.notify_user(user.managerialOpenId if user else '', 'service_complete',
  118. **{
  119. 'title': u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % (
  120. reason,
  121. actualNeedTime,
  122. leftTimeStr),
  123. 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % (
  124. self.device['logicalCode'], port, group['address']),
  125. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S'),
  126. 'remark': u'谢谢您的支持'
  127. })
  128. # 如果需要退款,计算退款数据.
  129. if not self.device.is_auto_refund:
  130. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  131. {'open_id': lineInfo['openId'],
  132. 'port': int(port),
  133. 'device_imei': self.device['devNo'],
  134. 'isFinished': False}, consumeDict)
  135. return
  136. coins = RMB(lineInfo['coins'])
  137. backCoins = coins * (float(leftTime) / float(actualNeedTime))
  138. # 直接退现金
  139. if RMB(0) < backCoins <= coins:
  140. self.refund_net_pay(user, lineInfo, backCoins, backCoins, consumeDict, True)
  141. refund = RMB(consumeDict.get(DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH, '0.00'))
  142. if refund > RMB(0):
  143. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  144. 'title': reason,
  145. 'backCount': u'%s元' % refund,
  146. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S')
  147. })
  148. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  149. {'open_id': lineInfo['openId'], 'port': int(port),
  150. 'device_imei': self.device['devNo'],
  151. 'isFinished': False}, consumeDict)
  152. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  153. 'title': u'%s 您订购的充电时间为%s分钟,按动态功率计算总时间为:%s分钟,还有:%s分钟的时间未使用完,给您退还成相应的金币:%s元,您下次可以接着使用哦' % (
  154. reason, lineInfo['needTime'], actualNeedTime, leftTimeStr, backCoins),
  155. 'backCount': u'金币:%s' % backCoins,
  156. 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S')
  157. })
  158. finally:
  159. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL, desc = reason)