mxzv2.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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 Group, Device
  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.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, Card, MyUser, CardRechargeOrder
  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 'elec' in device_event:
  24. event_data.update({'elec': device_event['elec']})
  25. if event_data['cmdCode'] in ['02', '03', '04', '20']:
  26. return ChargingMOXIAOZHI2WorkEvent(self.deviceAdapter, event_data)
  27. return None
  28. class ChargingMOXIAOZHI2WorkEvent(WorkEvent):
  29. def do(self, **args):
  30. devNo = self.device['devNo']
  31. logger.info('moxiaozhi2 charging event detected, devNo=%s' % (devNo,))
  32. smartBox = self.deviceAdapter
  33. if self.event_data['cmdCode'] == '02': # 刷卡,用于查询余额.如果发现有充值订单,马上下发充值
  34. cardNo = self.event_data['cardNo']
  35. card = self.update_card_dealer_and_type(cardNo, 'ID') # type: Card
  36. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder
  37. result = self.recharge_id_card(card = card,
  38. rechargeType = 'append',
  39. order = card_recharge_order)
  40. card.reload()
  41. # 如果卡挂失,直接余额为0
  42. if card.frozen:
  43. balance = RMB(0)
  44. else:
  45. balance = result['balance']
  46. try:
  47. smartBox.response_card_balance(cardNo, balance)
  48. except Exception, e:
  49. logger.error('response card balance error=%s' % e)
  50. return
  51. elif self.event_data['cmdCode'] == '03': # 刷卡,开始结束充电。刷卡是后扣费,移动支付是先扣费,后退费
  52. group = Group.get_group(self.device['groupId'])
  53. portInfo = Device.update_port_control_cache(self.device['devNo'], self.event_data, 'overwrite')
  54. port = portInfo['port']
  55. card = self.update_card_dealer_and_type(portInfo['cardNo'], 'ID')
  56. portInfo['openId'] = card.openId
  57. portInfo['cardId'] = str(card.id)
  58. portInfo['startTime'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  59. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  60. Device.update_port_control_cache(self.device['devNo'], portInfo)
  61. # 如果是开始报文,最重要的是刷新内存计费相关数据,前面代码已经完成.刷卡不预扣费,等待结束后,直接扣费
  62. if portInfo['isStart']: # 如果是刷卡启动的,禁用的端口不允许充电
  63. isNormal = True
  64. otherConf = Device.objects.get(devNo = self.device['devNo']).otherConf
  65. if otherConf.has_key(str(port)) and otherConf[str(port)] == Const.DEV_WORK_STATUS_FORBIDDEN:
  66. logger.info('this port is forbidden port=%s' % (port,))
  67. isNormal = False
  68. # 刷卡启动,需要等级正在服务的progress
  69. ServiceProgress.register_card_service(self.device, port, card)
  70. try:
  71. smartBox.response_card_charging(isNormal)
  72. except Exception, e:
  73. logger.exception('response card=%s e=%s' % (portInfo['cardNo'], e))
  74. else:
  75. #: 结束,就需要扣费咯.先支持按时间扣费,后续再支持按电量扣费 ------------比较奇怪,从来没有收到这个协议
  76. #: 回复设备
  77. try:
  78. smartBox.response_card_charging(True)
  79. except Exception, e:
  80. logger.exception('response devNo=%s card charging e=%s' % (self.device['devNo'], e))
  81. if self.event_data.has_key('duration') and self.event_data['duration'] > 0:
  82. duration = self.event_data['duration']
  83. else:
  84. duration = (to_datetime(portInfo['endTime']) - to_datetime(
  85. portInfo['startTime'])).total_seconds() / 60.0
  86. if duration < 0:
  87. duration = 0
  88. if self.event_data.has_key('elec'):
  89. consumeElec = round(self.event_data['elec'] / 3600.0, 4)
  90. else:
  91. consumeElec = 0.03 * duration / 0.9 # 这里做个特殊的保护,只有模块出现异常的时候,但是需要计费
  92. if consumeElec < 0:
  93. consumeElec = 0
  94. consumeMoney, desc = smartBox.calc_consume_money(duration, consumeElec)
  95. card = self.update_card_dealer_and_type(portInfo['cardNo'], 'ID')
  96. self.consume_money_for_card(card, consumeMoney)
  97. self.record_consume_for_card(card, consumeMoney, desc = u'充电时间:%s分钟,充电电量%s度' % (duration, consumeElec))
  98. desc = u'您本次充电约:%s分钟,收费标准为:%s,共计花费:%s元' % (duration, desc, consumeMoney)
  99. self.notify_balance_has_consume_for_card(card, consumeMoney)
  100. self.notify_user(card.managerialOpenId if card else '', 'service_complete',
  101. **{
  102. 'title': desc,
  103. 'service': u'充电服务(设备编号:%s,端口:%s 地址:%s)' % (
  104. self.device['logicalCode'], port, group['address']),
  105. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  106. 'remark': u'谢谢您的支持'
  107. })
  108. elif self.event_data['cmdCode'] in ['04', '20']: # 收到的结束事件
  109. portInfo = Device.update_port_control_cache(self.device['devNo'], self.event_data)
  110. port = self.event_data['port']
  111. try:
  112. # 回复设备,04号报文是设备主动停止的,所以需要我们回复一条消息过去
  113. if self.event_data['cmdCode'] == '04':
  114. try:
  115. smartBox.response_finished_back(True)
  116. except Exception, e:
  117. logger.error('response devNo=%s card charging e=%s' % (self.device['devNo'], e))
  118. # 如果是开始报文,最重要的是刷新内存计费相关数据,前面代码已经完成.刷卡不预扣费,等待结束后,直接扣费
  119. if self.event_data['isStart']:
  120. pass
  121. else: # 结束,就需要扣费咯.支持按时间扣费,也支持按电量扣费
  122. if self.event_data.has_key('duration') and self.event_data['duration'] > 0:
  123. duration = self.event_data['duration']
  124. else:
  125. duration = (datetime.datetime.now() - to_datetime(portInfo['startTime'])).total_seconds() / 60.0
  126. if duration < 0:
  127. duration = 0
  128. if self.event_data.has_key('elec'):
  129. consumeElec = round(self.event_data['elec'] / 3600.0, 4)
  130. else:
  131. consumeElec = 0.03 * duration / 0.9 # 这里做个特殊的保护,只有模块出现异常的时候,但是需要计费
  132. if consumeElec < 0:
  133. consumeElec = 0
  134. if (not portInfo.has_key('cardNo')) and portInfo.has_key('openId') and (
  135. not portInfo.has_key('consumeRcdId')): # 非刷卡的是退费,刷卡的结束扣费。两种方式不一样
  136. consumeMoney, descFee = smartBox.calc_consume_money(duration, consumeElec)
  137. backMoney = RMB(portInfo['coins']) - consumeMoney
  138. if backMoney > RMB(0):
  139. refund_money(self.device, backMoney, portInfo['openId'])
  140. else:
  141. backMoney = RMB(0)
  142. desc = u'您本次充电使用%s号端口,共计:%s分钟,收费标准为:%s,共计花费:%s元,您预支了:%s元,退回:%s元到您的个人中心中。' % \
  143. (port, duration, descFee, consumeMoney, portInfo['coins'], backMoney)
  144. consumeDict = {'reason': self.event_data['reason'], 'duration': duration,
  145. 'feeType': descFee, 'refundedMoney': str(backMoney),
  146. 'spendMoney': str(consumeMoney), 'chargeIndex': port}
  147. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  148. {'open_id': portInfo['openId'], 'port': port,
  149. 'device_imei': self.device['devNo'],
  150. 'isFinished': False},
  151. consumeDict)
  152. user = MyUser.objects(openId = portInfo['openId'], groupId = self.device['groupId']).first()
  153. self.notify_user(user.managerialOpenId if user else '', 'refund_coins',
  154. **{
  155. 'title': '%s%s' % (self.event_data['reason'], desc),
  156. 'backCount': u'金币:%s' % backMoney,
  157. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  158. })
  159. self.notify_charging_finished(user.managerialOpenId if user else '')
  160. elif portInfo.has_key('consumeRcdId'):
  161. consumeMoney, descFee = smartBox.calc_consume_money(duration, consumeElec)
  162. backMoney = RMB(portInfo['coins']) - consumeMoney
  163. if backMoney < RMB(0):
  164. backMoney = RMB(0)
  165. desc = u'您本次充电使用%s号端口,共计:%s分钟,收费标准为:%s,共计花费:%s元,您预支了:%s元,退回:%s元到您的个人中心中。' % \
  166. (port, duration, descFee, consumeMoney, portInfo['coins'], backMoney)
  167. consumeDict = {'reason': self.event_data['reason'], 'duration': duration,
  168. 'feeType': descFee, 'chargeIndex': port}
  169. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  170. {'open_id': portInfo['openId'], 'port': port,
  171. 'device_imei': self.device['devNo'],
  172. 'isFinished': False},
  173. consumeDict)
  174. # 退额度
  175. try:
  176. vCardId = portInfo['vCardId']
  177. vCard = UserVirtualCard.objects.get(id = vCardId)
  178. except DoesNotExist, e:
  179. logger.info('can not find the vCard id = %s' % vCardId)
  180. return
  181. self.notify_user(self.get_managerialOpenId_by_openId(portInfo['openId']) if vCard else '',
  182. 'refund_coins',
  183. **{
  184. 'title': '%s%s' % (self.event_data['reason'], desc),
  185. 'backCount': u'金币:%s' % backMoney,
  186. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  187. })
  188. consumeRcdId = portInfo.get('consumeRcdId', None)
  189. if consumeRcdId is None:
  190. logger.info('can not find consume rcd id')
  191. return
  192. try:
  193. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  194. except DoesNotExist, e:
  195. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  196. return
  197. vCard.refund_quota(vCardConsumeRcd, duration, consumeElec, backMoney.mongo_amount)
  198. elif portInfo.has_key('cardNo'):
  199. card = self.update_card_dealer_and_type(portInfo['cardNo'], 'ID')
  200. consumeMoney, descFee = smartBox.calc_consume_money(duration, consumeElec)
  201. self.consume_money_for_card(card, consumeMoney)
  202. desc = u'您本次充电使用%s号端口,共计:%s分钟,收费标准为:%s,共计花费:%s元' % \
  203. (port, duration, descFee, consumeMoney)
  204. consumeDict = {'reason': self.event_data['reason'], 'duration': duration,
  205. 'feeType': descFee, 'spendMoney': str(consumeMoney),
  206. 'chargeIndex': port}
  207. self.record_consume_for_card(card, consumeMoney,
  208. desc = u'充电时间:%s分钟' % duration,
  209. servicedInfo = consumeDict)
  210. ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
  211. {'cardId': str(card.id), 'port': port,
  212. 'device_imei': self.device['devNo'],
  213. 'isFinished': False},
  214. consumeDict, False)
  215. self.notify_balance_has_consume_for_card(card, consumeMoney, desc)
  216. self.notify_charging_finished(card.managerialOpenId)
  217. finally:
  218. Device.clear_port_control_cache(self.device['devNo'], str(port))
  219. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  220. desc = self.event_data['reason'])