dianchuanCFJ.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import json
  5. import random
  6. from typing import TYPE_CHECKING
  7. from apilib.monetary import RMB, VirtualCoin
  8. from apilib.utils_datetime import to_datetime
  9. from apps.web.device.models import Device
  10. from apps.web.eventer.base import WorkEvent, logger
  11. from apps.web.eventer import EventBuilder
  12. from apps.web.user.transaction_deprecated import refund_money
  13. from apps.web.user.models import Card, UserVirtualCard, ServiceProgress, VCardConsumeRecord, MyUser
  14. if TYPE_CHECKING:
  15. from apps.web.device.models import GroupDict
  16. class builder(EventBuilder):
  17. def __getEvent__(self, device_event):
  18. event_data = self.deviceAdapter.analyze_event_data(device_event.get("data"))
  19. logger.info("lz_reve event eventData:{}".format(json.dumps(event_data, ensure_ascii=False)))
  20. return CFJWorkEvent(self.deviceAdapter, event_data)
  21. class CFJWorkEvent(WorkEvent):
  22. def _parse_device_finished_data(self, event_data):
  23. duration = event_data.get('duration', -1)
  24. if duration != -1:
  25. if 'v' in event_data:
  26. duration = ((duration + 59) / 60)
  27. elec = event_data.get('elec', -1)
  28. if elec != -1:
  29. if 'v' in event_data:
  30. elec = round(elec / (10000.0 * 3600.0), 3)
  31. else:
  32. elec = round(elec / 3600.0, 3)
  33. logger.debug('device duration is {}, device elec is {}'.format(duration, elec))
  34. return duration, elec
  35. def do(self, **args):
  36. cmd = self.event_data.get("cmd", "E")
  37. if cmd == "E":
  38. logger.info("cfj_no this event!!!! event_data: {}".format(json.dumps(self.event_data, ensure_ascii=False)))
  39. return
  40. elif cmd == "05":
  41. logger.info("cfj_is finished event event_data: {}".format(json.dumps(self.event_data, ensure_ascii=False)))
  42. devNo = self.device.devNo
  43. port = str(self.event_data.get('port','1'),)
  44. try:
  45. ctrInfo = Device.get_dev_control_cache(devNo)
  46. lineInfo = ctrInfo.get(port)
  47. if not lineInfo:
  48. logger.debug('cfj_get null control cache from {}'.format(repr(self.device)))
  49. return
  50. billingType = lineInfo.get("billingType", "time")
  51. if billingType == "time":
  52. self._do_time_finish(devNo, port, lineInfo, self.event_data)
  53. except Exception as e:
  54. logger.error("cfj_do finished event is error!!! e={} event_data: {}".format(e,
  55. json.dumps(self.event_data, ensure_ascii=False)))
  56. finally:
  57. Device.clear_port_control_cache(devNo, str(port))
  58. def _do_time_finish(self, devNo, port, lineInfo, msgDict):
  59. refundProtectionTime = lineInfo.get('refundProtectionTime', 0)
  60. deviceDuration, deviceElec = self._parse_device_finished_data(self.event_data)
  61. if lineInfo is not None and 'startTime' in lineInfo:
  62. startTime = to_datetime(lineInfo['startTime'])
  63. nowTime = datetime.datetime.now()
  64. if startTime > nowTime:
  65. logger.error('start time is bigger than now time,devNo={}'.format(devNo))
  66. serverDuration = -1
  67. else:
  68. serverDuration = int(round((((nowTime - startTime).total_seconds() + 59) / 60.0)))
  69. else:
  70. logger.info('lineinfo has not startTime,devNo=%s' % devNo)
  71. serverDuration = -1
  72. if deviceDuration > 0:
  73. usedTime = deviceDuration
  74. elif serverDuration >= 0:
  75. usedTime = serverDuration
  76. else:
  77. usedTime = -1
  78. leftTime = int(self.event_data['leftTime'])
  79. if leftTime != 65535:
  80. leftTimeStr = leftTime
  81. if usedTime == -1:
  82. actualNeedTime = -1
  83. else:
  84. actualNeedTime = usedTime + leftTime
  85. else:
  86. leftTimeStr = u'端口未使用'
  87. actualNeedTime = 0
  88. group = self.device.group # type: GroupDict
  89. if actualNeedTime == -1:
  90. if 'cardNo' in self.event_data and self.event_data['cardNo']:
  91. card = Card.objects(cardNo=str(self.event_data['cardNo']), agentId=self.dealer.agentId).first()
  92. if card:
  93. self.notify_user_service_complete(
  94. service_name=u'使用吹风机',
  95. openid=card.managerialOpenId if card else '',
  96. port=port,
  97. address=group['address'],
  98. reason=self.event_data['reason'],
  99. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  100. extra=[{
  101. u'实体卡号': self.event_data['cardNo']
  102. }]
  103. )
  104. logger.debug('has no actual need time. ignore this event.')
  105. return
  106. consumeDict = {
  107. 'reason': self.event_data['reason'],
  108. 'leftTime': leftTimeStr,
  109. 'chargeIndex': port,
  110. 'actualNeedTime': u'动态计算时间为%s分钟' % actualNeedTime,
  111. 'duration': usedTime,
  112. # 'deviceDuration': deviceDuration,
  113. # 'serverDuration': serverDuration
  114. }
  115. if deviceElec != -1:
  116. consumeDict.update({'elec': deviceElec})
  117. else:
  118. deviceObj = Device.objects(devNo=self.device.devNo).first()
  119. if deviceObj.otherConf.get('zhuxing', None) is not None:
  120. spendElec = round((float(random.randint(15, 19)) / 100) * (float(usedTime) / 60), 3)
  121. consumeDict.update({'elec': spendElec})
  122. consumeDict.update({'elecFee': self.deviceAdapter.calc_elec_fee(spendElec)})
  123. else:
  124. spendElec = 0.0
  125. consumeDict.update({'elec': 0.0})
  126. consumeDict.update({'elecFee': RMB(0.0).mongo_amount})
  127. if 'cardNo' in lineInfo and lineInfo['cardNo']:
  128. # 如果是刷卡的,直接更新消费记录,发通知消息,支持ID卡的退费。
  129. # IC卡的退费, 如果结束原因是刷卡退费(05), 则会把退费信息返回;
  130. # 否则不会把退费信息传过来,会通过11号命令返回
  131. card = Card.objects(cardNo=lineInfo['cardNo'], agentId=self.dealer.agentId).first()
  132. if not card:
  133. logger.error('not exist this card no.')
  134. return
  135. if self.event_data['cardType'] == 'ID':
  136. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  137. if self.event_data.has_key('backMoney') and self.event_data['backMoney'] > 0:
  138. self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id)
  139. # 通知微信,已经退费
  140. self.notify_user(card.managerialOpenId, 'refund_coins', **{
  141. 'title': u'退币完成!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
  142. 'backCount': u'金币:%s' % VirtualCoin(self.event_data['backMoney']),
  143. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  144. })
  145. else:
  146. # IC 并且结束code是05 表示卡贴上去了
  147. if self.event_data['endType'] == '05': # 刷卡退费结束的时候,才能够刷新IC卡的余额
  148. self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id)
  149. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  150. else:
  151. consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来
  152. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  153. {'open_id': lineInfo['openId'], 'port': int(port),
  154. 'device_imei': self.device.devNo,
  155. 'isFinished': False}, consumeDict)
  156. extra = [{
  157. u'实体卡号': lineInfo['cardNo']
  158. }]
  159. if VirtualCoin(self.event_data['backMoney']) > VirtualCoin(0):
  160. extra.append({
  161. u'退费金额': u'{}(金币)'.format(self.event_data['backMoney'])
  162. })
  163. self.notify_user_service_complete(
  164. service_name=u'充电',
  165. openid=card.managerialOpenId if card else '',
  166. port=port,
  167. address=group['address'],
  168. reason=self.event_data['reason'],
  169. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  170. extra=extra)
  171. else:
  172. # 计算退费信息
  173. coins = VirtualCoin(lineInfo['coins'])
  174. backCoins = VirtualCoin(0)
  175. if self.device.is_auto_refund:
  176. if leftTime != 65535:
  177. backCoins = coins * (float(leftTime) / float(actualNeedTime))
  178. else:
  179. backCoins = coins
  180. # if (refundProtection == 1 and usedTime < refundProtectionTime) and backCoins != VirtualCoin(0):
  181. if usedTime < refundProtectionTime and backCoins != VirtualCoin(0):
  182. backCoins = coins
  183. if backCoins > coins:
  184. backCoins = coins
  185. logger.debug(
  186. 'lefttime = {}, usedTime = {}, need time = {}, back coins = {}'.format(leftTime, usedTime,
  187. actualNeedTime,
  188. backCoins))
  189. if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']:
  190. vCardId = lineInfo['vCardId']
  191. vCard = UserVirtualCard.objects(id=vCardId).first() # type: UserVirtualCard
  192. if not vCard:
  193. logger.info('can not find the vCard id = %s' % vCardId)
  194. return
  195. try:
  196. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  197. {'open_id': lineInfo['openId'],
  198. 'port': int(port),
  199. 'device_imei': self.device.devNo,
  200. 'isFinished': False}, consumeDict)
  201. if backCoins > VirtualCoin(0):
  202. vCardConsumeRcd = VCardConsumeRecord.objects.get(id=lineInfo['consumeRcdId'])
  203. vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, backCoins.mongo_amount)
  204. finally:
  205. user = MyUser.objects(openId=lineInfo['openId'],
  206. groupId=self.device.groupId).first()
  207. self.notify_user_service_complete(
  208. service_name=u'充电',
  209. openid=user.managerialOpenId if user else '',
  210. port=port,
  211. address=group['address'],
  212. reason=self.event_data['reason'],
  213. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  214. extra=[
  215. {u'虚拟卡号': vCard.cardNo}
  216. ]
  217. )
  218. elif 'openId' in lineInfo and lineInfo['openId']:
  219. try:
  220. if backCoins > VirtualCoin(0):
  221. consumeDict.update({'refundedMoney': str(backCoins)})
  222. refund_money(self.device, backCoins, lineInfo['openId'])
  223. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  224. {'open_id': lineInfo['openId'],
  225. 'port': int(port),
  226. 'device_imei': self.device.devNo,
  227. 'isFinished': False}, consumeDict)
  228. finally:
  229. extra = []
  230. if backCoins > VirtualCoin(0):
  231. extra.append({u'消费金额': '{}(金币)'.format(coins - backCoins)})
  232. extra.append({u'退款金额': '{}(金币)'.format(backCoins)})
  233. else:
  234. extra.append({u'消费金额': '{}(金币)'.format(coins)})
  235. user = MyUser.objects(openId=lineInfo['openId'],
  236. groupId=self.device.groupId).first()
  237. self.notify_user_service_complete(
  238. service_name=u'充电',
  239. openid=user.managerialOpenId if user else '',
  240. port=port,
  241. address=group['address'],
  242. reason=self.event_data['reason'],
  243. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  244. extra=extra
  245. )
  246. else:
  247. logger.error('not net pay rather user virtual card pay. something is wrong.')