nanjiguang2.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from apilib.monetary import RMB, VirtualCoin
  6. from apilib.utils_datetime import to_datetime
  7. from apps.web.agent.models import Agent
  8. from apps.web.dealer.models import Dealer
  9. from apps.web.device.models import Group, Device
  10. from apps.web.eventer.base import WorkEvent
  11. from apps.web.eventer import EventBuilder
  12. from apps.web.eventer.errors import NoCommandHandlerAvailable
  13. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, MyUser
  14. from apps.web.user.transaction_deprecated import refund_money
  15. logger = logging.getLogger(__name__)
  16. service_id_generator = lambda dev_no, port, ts: '{}_{}_{}'.format(dev_no, port, ts)
  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 event_data['cmdCode'] in [0x09]:
  23. return ChargingNanjiguangWorkEvent(self.deviceAdapter, event_data)
  24. class ChargingNanjiguangWorkEvent(WorkEvent):
  25. def do(self, **args):
  26. devNo = self.device['devNo']
  27. logger.info('nanjiguang charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
  28. cmdCode = self.event_data['cmdCode']
  29. #: 结束的命令
  30. if cmdCode in [0x09]:
  31. group = Group.get_group(self.device['groupId'])
  32. dealer = Dealer.objects(id = group['ownerId']).first()
  33. if not dealer:
  34. logger.error('dealer is not found, dealerId=%s' % group['ownerId'])
  35. return
  36. agent = Agent.objects(id = dealer.agentId).first()
  37. if not agent:
  38. logger.error('agent is not found, agentId=%s' % dealer.agentId)
  39. return
  40. ctrl_info = Device.get_dev_control_cache(self.device['devNo'])
  41. lineInfo = ctrl_info.get(str(self.event_data['port']))
  42. if 'ts' not in lineInfo or lineInfo['ts'] != self.event_data['ts']:
  43. service_progress = ServiceProgress.objects(
  44. id = service_id_generator(dev_no = devNo, port = self.event_data['port'],
  45. ts = self.event_data['ts'])).first()
  46. if not service_progress:
  47. logger.error(
  48. 'not find port status info. devNo = {}, port = {}'.format(devNo, self.event_data['port']))
  49. return
  50. lineInfo = {
  51. }
  52. vCardId = lineInfo.get('vCardId', None)
  53. coins = VirtualCoin(lineInfo['coins'])
  54. price = RMB(lineInfo.get('price', 0.0))
  55. spendTime = int(self.event_data['consumeTime'])
  56. spendElec = round(float(self.event_data['consumeElec']), 2)
  57. billingType = lineInfo.get('billingType')
  58. backCoins, backPrice = VirtualCoin(0.0), RMB(0.0)
  59. try:
  60. if billingType == 'autoClose': # 充满自停
  61. left_elec = lineInfo['needElec'] - spendElec
  62. if left_elec < 0:
  63. left_elec = 0
  64. else:
  65. backCoins = coins * (float(left_elec) / float(lineInfo['needElec']))
  66. backPrice = price * (float(left_elec) / float(lineInfo['needElec']))
  67. startTime = to_datetime(lineInfo['startTime'])
  68. nowTime = datetime.datetime.now()
  69. if startTime > nowTime:
  70. duration = 0
  71. else:
  72. duration = int(round(((nowTime - startTime).total_seconds() / 60.0)))
  73. else:
  74. leftTime = lineInfo['needTime'] - spendTime
  75. if leftTime < 0:
  76. leftTime = 0
  77. else:
  78. backCoins = coins * (float(leftTime) / float(lineInfo['needTime']))
  79. backPrice = price * (float(leftTime) / float(lineInfo['needTime']))
  80. duration = int(lineInfo['needTime'] / 60.0)
  81. is_auto_refund = self.device.is_auto_refund
  82. openId = lineInfo['openId']
  83. consumeDict = {
  84. 'chargeIndex': lineInfo['port'],
  85. 'duration': duration
  86. }
  87. if backCoins > VirtualCoin(0):
  88. consumeDict.update({'refundedMoney': str(backCoins)})
  89. ServiceProgress.update_progress_and_consume_rcd(
  90. self.device['ownerId'],
  91. {'open_id': openId, 'device_imei': self.device['devNo'],
  92. 'port': lineInfo['port'], 'isFinished': False}, consumeDict)
  93. if vCardId is None: # 扫码的方式
  94. if is_auto_refund:
  95. # 扫码退钱, 退到个人账号
  96. refund_money(self.device, backCoins, lineInfo['openId'])
  97. #: 使用的是虚拟卡
  98. elif vCardId is not None:
  99. try:
  100. consumeRcdId = lineInfo.get('consumeRcdId', None)
  101. if consumeRcdId:
  102. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  103. vCard = UserVirtualCard.objects.get(id = vCardId)
  104. vCard.refund_quota(vCardConsumeRcd, duration, spendElec, backCoins.mongo_amount)
  105. except Exception as e:
  106. logger.exception(e)
  107. except Exception as e:
  108. logger.exception('deal with jingneng devNo=%s event e=%s' % (devNo, e))
  109. finally:
  110. Device.clear_port_control_cache(devNo, str(self.event_data['port']))
  111. title = u'充电结束,感谢您的使用!'
  112. if is_auto_refund and backCoins > 0:
  113. title = u'充电结束,感谢您的使用!退款金额已经返还到您的账号,请注意查收。'
  114. if billingType == 'autoClose':
  115. service_notify = u'自助充电\r\n' \
  116. u'设备编号:{logicalCode}\r\n' \
  117. u'充电端口:{port}\r\n' \
  118. u'预付金额:{money}币\r\n' \
  119. u'退款金额:{back}币\r\n' \
  120. u'设备地址:{address}\r\n' \
  121. u'充电状态:{status}'.format(
  122. logicalCode = self.device['logicalCode'], port = self.event_data['port'],
  123. money = coins, back = backCoins,
  124. address = group['address'],
  125. status = self.event_data['statusDesc'])
  126. else:
  127. service_notify = u'自助充电\r\n' \
  128. u'设备编号:{logicalCode}\r\n' \
  129. u'充电端口:{port}\r\n' \
  130. u'预付金额:{money}币\r\n' \
  131. u'退款金额:{back}币\r\n' \
  132. u'订购时间:{reverseTime}\r\n' \
  133. u'剩余时间:{leftTime}\r\n' \
  134. u'设备地址:{address}\r\n' \
  135. u'充电状态:{status}'.format(
  136. logicalCode = self.device['logicalCode'], port = self.event_data['port'],
  137. money = coins, back = backCoins,
  138. reverseTime = lineInfo['needTime'], leftTime = leftTime,
  139. address = group['address'],
  140. status = self.event_data['statusDesc'])
  141. user = MyUser.objects(openId = openId, groupId = self.device['groupId']).first()
  142. self.notify_user(
  143. user.managerialOpenId,
  144. 'service_complete',
  145. **{
  146. 'title': title,
  147. 'service': service_notify,
  148. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  149. 'remark': u'谢谢您的支持'
  150. })
  151. else:
  152. raise NoCommandHandlerAvailable(
  153. '[nanjiguang] no command handler for cmd %s, curDevInfo=%s' % (cmdCode, self.event_data))