xuzhou.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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, VirtualCoin
  7. from apilib.utils_datetime import to_datetime
  8. from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND
  9. from apps.web.device.models import Group, Device
  10. from apps.web.eventer.base import WorkEvent, FaultEvent
  11. from apps.web.eventer import EventBuilder
  12. from apps.web.user.models import ServiceProgress, MyUser, CardRechargeOrder, UserVirtualCard, \
  13. VCardConsumeRecord, Card
  14. from apps.web.user.transaction_deprecated import refund_money
  15. logger = logging.getLogger(__name__)
  16. class builder(EventBuilder):
  17. def __getEvent__(self, device_event):
  18. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  19. if event_data is None or 'cmdCode' not in event_data:
  20. return None
  21. if 'duration' in device_event:
  22. event_data.update({'duration': device_event['duration']})
  23. if event_data['cmdCode'] in ['05', '04', '12']:
  24. return ChargingXUZHOUWorkEvent(self.deviceAdapter, event_data)
  25. if event_data['cmdCode'] == '0D':
  26. return FaultEvent(self.deviceAdapter, event_data)
  27. class ChargingXUZHOUWorkEvent(WorkEvent):
  28. def do(self, **args):
  29. devNo = self.device['devNo']
  30. logger.info('xuzhoudianzi charging event detected, devNo=%s' % (devNo,))
  31. if self.event_data['cmdCode'] == '05':
  32. port = str(self.event_data['port'])
  33. try:
  34. ctrInfo = Device.get_dev_control_cache(self.device['devNo'])
  35. lineInfo = ctrInfo.get(port)
  36. if 'duration' in self.event_data and self.event_data['duration'] > 0:
  37. usedTime = self.event_data['duration']
  38. else:
  39. if (not lineInfo) or (not lineInfo.has_key('startTime')):
  40. return
  41. startTime = to_datetime(lineInfo['startTime'])
  42. nowTime = datetime.datetime.now()
  43. if startTime > nowTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
  44. usedTime = 0
  45. else:
  46. usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
  47. group = Group.get_group(self.device['groupId'])
  48. consumeDict = {'reason': self.event_data['reason'], 'chargeIndex': port, 'duration': usedTime}
  49. isBackCoins = self.device.is_auto_refund
  50. backCoins = self.event_data['leftMoney']
  51. if isBackCoins:
  52. consumeDict.update({
  53. DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: VirtualCoin(backCoins).mongo_amount,
  54. })
  55. # 如果是刷卡的,直接更新消费记录,然后发送通知消息,不支持退费
  56. if lineInfo.has_key('cardNo'):
  57. card = Card.objects(cardNo = lineInfo['cardNo'], agentId = self.dealer.agentId).first()
  58. consumeDict.update({'balance': lineInfo['balance']})
  59. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  60. {'open_id': lineInfo['openId'], 'port': int(port),
  61. 'device_imei': self.device['devNo'],
  62. 'isFinished': False}, consumeDict)
  63. # 通知服务结束
  64. self.notify_user(card.managerialOpenId if card else '', 'service_complete',
  65. **{
  66. 'title': u'%s 卡号:%s,剩余时间:%s分钟' % (
  67. self.event_data['reason'],
  68. lineInfo['cardNo'],
  69. usedTime,
  70. 0),
  71. 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % (
  72. self.device['logicalCode'], port, group['address']),
  73. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  74. 'remark': u'谢谢您的支持'
  75. })
  76. elif lineInfo.has_key('consumeRcdId'):
  77. # 退额度
  78. try:
  79. vCardId = lineInfo['vCardId']
  80. vCard = UserVirtualCard.objects.get(id = vCardId)
  81. except DoesNotExist, e:
  82. logger.info('can not find the vCard id = %s' % vCardId)
  83. return
  84. # 通知服务结束
  85. self.notify_user(self.get_managerialOpenId_by_openId(lineInfo['openId']) if vCard else '',
  86. 'service_complete',
  87. **{
  88. 'title': u'%s,退费:%s元' % (
  89. self.event_data['reason'], backCoins) if not isBackCoins else self.event_data[
  90. 'reason'],
  91. 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % (
  92. self.device['logicalCode'], port, group['address']),
  93. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  94. 'remark': u'谢谢您的支持'
  95. })
  96. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  97. {'open_id': lineInfo['openId'], 'port': int(port),
  98. 'device_imei': self.device['devNo'],
  99. 'isFinished': False}, consumeDict)
  100. consumeRcdId = lineInfo.get('consumeRcdId', None)
  101. if consumeRcdId is None:
  102. logger.info('can not find consume rcd id')
  103. return
  104. try:
  105. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  106. except DoesNotExist, e:
  107. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  108. return
  109. vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, backCoins)
  110. else:
  111. if not lineInfo.has_key('openId'):
  112. return
  113. user = MyUser.objects(openId = lineInfo['openId'], groupId = self.device['groupId']).first()
  114. # 通知服务结束
  115. self.notify_user(user.managerialOpenId if user else '', 'service_complete',
  116. **{
  117. 'title': u'%s,退费:%s元' % (
  118. self.event_data['reason'], backCoins) if isBackCoins else self.event_data[
  119. 'reason'],
  120. 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % (
  121. self.device['logicalCode'], port, group['address']),
  122. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  123. 'remark': u'谢谢您的支持'
  124. })
  125. # 如果需要退款,计算退款数据.
  126. if not isBackCoins:
  127. ServiceProgress.update_progress_and_consume_rcd(
  128. self.device['ownerId'],
  129. {'open_id': lineInfo['openId'], 'port': int(port),
  130. 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict)
  131. else:
  132. refund_money(self.device, backCoins, lineInfo['openId'])
  133. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  134. {'open_id': lineInfo['openId'], 'port': int(port),
  135. 'device_imei': self.device['devNo'],
  136. 'isFinished': False}, consumeDict)
  137. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  138. 'title': u'%s 退金币:%s元,您下次可以接着使用哦' % (
  139. self.event_data['reason'], backCoins),
  140. 'backCount': u'金币:%s' % backCoins,
  141. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  142. })
  143. finally:
  144. Device.clear_port_control_cache(devNo, str(port))
  145. elif self.event_data['cmdCode'] == '04':
  146. cardNo = self.event_data['cardNo']
  147. card = self.update_card_dealer_and_type(cardNo, 'IC')
  148. if not card:
  149. return
  150. lineInfo = Device.update_port_control_cache(self.device['devNo'], self.event_data)
  151. lineInfo['openId'] = card.openId
  152. lineInfo = Device.update_port_control_cache(self.device['devNo'], lineInfo)
  153. balance = RMB(self.event_data['balance'])
  154. consumeMoney = RMB(self.event_data['coins'])
  155. if self.event_data['status'] == '01': # 扣款成功,表示马上需要使用卡了,需要登记
  156. desc = u'正在刷卡使用,卡号:%s,卡名称:%s,端口号:%s,扣费:%s,余额:%s' % (
  157. card.cardNo, card.cardName,
  158. self.event_data['port'],
  159. self.event_data['coins'], balance)
  160. orderNo, cardOrderNo = \
  161. self.record_consume_for_card(card = card,
  162. money = consumeMoney,
  163. desc = desc,
  164. servicedInfo = {
  165. 'balance': self.event_data['balance'],
  166. 'coin': self.event_data['coins'],
  167. 'port': self.event_data['port']})
  168. # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
  169. ServiceProgress.register_card_service(self.device, self.event_data['port'], card,
  170. {'orderNo': orderNo, 'coin': self.event_data['coins'],
  171. 'cardOrderNo': cardOrderNo})
  172. self.notify_balance_has_consume_for_card(card, consumeMoney, desc)
  173. # 更新下balance,便于刷卡记录中,更新到数据库中
  174. lineInfo['balance'] = str(balance)
  175. lineInfo['cardId'] = str(card.id)
  176. lineInfo['startTime'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  177. lineInfo['isStart'] = True
  178. lineInfo['status'] = Const.DEV_WORK_STATUS_WORKING
  179. Device.update_port_control_cache(self.device['devNo'], lineInfo)
  180. # 如果卡挂失掉了,立马把端口关闭掉
  181. if card.frozen:
  182. logger.debug('{} has been frozen.'.format(repr(card)))
  183. self.deviceAdapter.stop_charging_port(lineInfo['port'])
  184. elif self.event_data['status'] == '02': # 扣款失败,余额不足
  185. pass
  186. elif self.event_data['status'] == '03': # 返现
  187. balance = balance + consumeMoney
  188. self.update_card_balance(card, balance)
  189. elif self.event_data['cmdCode'] == '12': # 电川的板子充值是覆写方式,需要把上次的余额一起累加进来
  190. cardNo = self.event_data['cardNo']
  191. card = self.update_card_dealer_and_type(cardNo, 'IC') # type: Card
  192. if card.frozen:
  193. logger.debug('{} has been frozen.'.format(repr(card)))
  194. return
  195. preBalance = RMB(self.event_data['balance'])
  196. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder
  197. self.recharge_ic_card(card = card,
  198. preBalance = preBalance,
  199. rechargeType = 'overwrite',
  200. order = card_recharge_order,
  201. need_verify = False)