lishenhuanbao.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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 apilib.utils_string import make_title_from_dict
  8. from apps.web.constant import DEALER_CONSUMPTION_AGG_KIND, Const
  9. from apps.web.device.models import Group, Device
  10. from apps.web.eventer import EventBuilder
  11. from apps.web.eventer.base import FaultEvent, WorkEvent
  12. from apps.web.user.models import Card, CardRechargeOrder, CardConsumeRecord, MyUser, ServiceProgress, \
  13. UserVirtualCard, ConsumeRecord
  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 event_data is None:
  19. return None
  20. if event_data.has_key('status') and event_data.get('isFaultClass'):
  21. return LSHBFaultEvent(self.deviceAdapter, event_data)
  22. elif event_data.has_key('funCode') and event_data['funCode'] in ['15', '16', '17', '1B']: # 沥森环保的卡消费,需要记录一下
  23. return LSHBRechargeEvent(self.deviceAdapter, event_data)
  24. elif event_data.has_key('funCode') and event_data['funCode'] in ['19','20']: # 在线卡流程
  25. return LSHBonlineCardEvent(self.deviceAdapter, event_data)
  26. else:
  27. return WorkEvent(self.deviceAdapter, event_data)
  28. class LSHBRechargeEvent(WorkEvent):
  29. def support_playback(self):
  30. return self.event_data.get('funCode') == '1B'
  31. def do(self, **args):
  32. if self.event_data.get('funCode') == '15':
  33. cardNo = self.event_data['cardNo']
  34. card = self.update_card_dealer_and_type(cardNo, 'IC') # type: Card
  35. if not card:
  36. return
  37. if card.frozen:
  38. logger.debug('{} has been frozen.'.format(repr(card)))
  39. return
  40. preBalance = RMB(self.event_data['money'])
  41. Card.update_balance(card.id, preBalance)
  42. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  43. self.recharge_ic_card(card = card,
  44. preBalance = preBalance,
  45. rechargeType = 'append',
  46. order = card_recharge_order,
  47. need_verify = False)
  48. if self.event_data.get('funCode') == '16':
  49. cardNo = self.event_data['cardNo']
  50. card = self.update_card_dealer_and_type(cardNo, 'IC')
  51. if not card:
  52. return
  53. group = Group.objects.get(id = self.device['groupId'])
  54. newRcd = CardConsumeRecord(
  55. openId = card.openId,
  56. cardId = str(card.id),
  57. money = RMB(self.event_data['money']),
  58. devNo = self.device['devNo'],
  59. devType = self.device['devType']['name'],
  60. logicalCode = self.device['logicalCode'],
  61. groupId = str(group.id),
  62. address = group.address,
  63. groupNumber = self.device['groupNumber'],
  64. groupName = group.groupName
  65. )
  66. try:
  67. newRcd.save()
  68. Card.update_balance(card.id, card.balance - self.event_data['money'])
  69. except Exception, e:
  70. logger.error('save card consume rcd error=%s' % e)
  71. elif self.event_data.get('funCode') == '17':
  72. cardNo = self.event_data['cardNo']
  73. card = self.update_card_dealer_and_type(cardNo, 'IC')
  74. if not card:
  75. return
  76. if self.event_data.has_key('money'): # 如果有余额,先更新余额
  77. Card.update_balance(card.id, RMB(self.event_data['money']))
  78. elif self.event_data.get('funCode') == '1B': # 在线付款的用完后,需要根据实际消费,退还金币
  79. devNo = self.device['devNo']
  80. sequanceNo = self.event_data['sequanceNo']
  81. devCtrInfo = Device.get_dev_control_cache(devNo)
  82. if sequanceNo != devCtrInfo.get('sequanceNo'):
  83. logger.info('do finish event sequanceNo is error')
  84. return
  85. LeftMoney = float(self.event_data['money'])
  86. coins = float(devCtrInfo['coins'])
  87. backCoins = LeftMoney
  88. price = float(devCtrInfo['price'])
  89. refundRMB = RMB(price * (backCoins / coins))
  90. logger.debug(
  91. 'refund money is: {}; refund rmb is: {}'.format(str(backCoins), str(refundRMB.mongo_amount)))
  92. extra = []
  93. consumeDict = {}
  94. openId = devCtrInfo.get('openId', None)
  95. if not openId:
  96. logger.warning('open is null. devNo = {}, sequanceNo = {}'.format(self.device.devNo, sequanceNo))
  97. return
  98. user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
  99. group = Group.get_group(self.device['groupId'])
  100. if refundRMB == RMB(0) or backCoins > coins or not self.device.is_auto_refund:
  101. extra.append({u'消费金额': u'{}(元)'.format(price)})
  102. else:
  103. try:
  104. if devCtrInfo.get('rechargeRcdId'):
  105. self.refund_net_pay(user, devCtrInfo, refundRMB, VirtualCoin(0), consumeDict, True)
  106. extra.append({u"消费金额": u"{}(元)".format(RMB(price) - refundRMB)})
  107. extra.append({u"退款金额": u"{}(元)".format(refundRMB)})
  108. elif devCtrInfo.get('vCardId'):
  109. vCard = UserVirtualCard.objects.filter(id=devCtrInfo['vCardId']).first()
  110. extra.append({u'优惠卡券': u'{}--{}'.format(vCard.cardName, vCard.cardNo)})
  111. extra.append({u"消费金额": u"使用优惠卡券抵扣"})
  112. else:
  113. self.refund_net_pay(user, devCtrInfo, RMB(0), VirtualCoin(backCoins), consumeDict, False)
  114. extra.append({u"消费金币": u"{}(金币)".format(VirtualCoin(coins-backCoins))})
  115. extra.append({u"退款金币": u"{}(金币)".format(refundRMB)})
  116. except Exception, e:
  117. logger.error('feedback coins error=%s' % e)
  118. return
  119. ServiceProgress.update_progress_and_consume_rcd(
  120. self.device['ownerId'],
  121. {
  122. 'open_id': openId, 'device_imei': self.device['devNo'],
  123. 'port': devCtrInfo.get('port', 0), 'isFinished': False
  124. },
  125. consumeDict)
  126. self.notify_user_service_complete(
  127. service_name='使用设备',
  128. openid=user.managerialOpenId if user.managerialOpenId else '',
  129. port='',
  130. address=group.address,
  131. reason='当前服务已完成,谢谢您的使用,祝您生活愉快!!',
  132. finished_time=to_datetime(self.recvTime).strftime('%Y-%m-%d %H:%M:%S'),
  133. extra=extra)
  134. Device.invalid_device_control_cache(self.device['devNo'])
  135. class LSHBFaultEvent(FaultEvent):
  136. def do(self, **args):
  137. cmd = self.event_data.pop('cmd', None)
  138. if self.event_data['funCode'] != '01' or not cmd:
  139. return
  140. if cmd == '01' or cmd == '02': # 缺液或者缺货
  141. Device.update_dev_control_cache(self.device['devNo'], self.event_data)
  142. group = Group.get_group(self.device["groupId"])
  143. faultContent = self.event_data.get("statusInfo")
  144. if self.is_notify_dealer:
  145. self.notify_dealer(
  146. templateName="device_fault",
  147. title=u'注意!您的设备发生告警!',
  148. device=u'{}-{}'.format(self.device.devTypeName, self.device.logicalCode),
  149. fault=faultContent,
  150. location=u'{address}-{groupName}-{groupNumber}号设备({logicalCode})'.format(address=group["address"],
  151. groupName=group[
  152. "groupName"],
  153. groupNumber=self.device[
  154. "groupNumber"],
  155. logicalCode=self.device[
  156. "logicalCode"]),
  157. notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  158. )
  159. self.record(
  160. faultCode=self.event_data.get("FaultCode"),
  161. description=faultContent,
  162. title="注意!您的设备发生告警!",
  163. )
  164. logger.info('devNo=<{}> Report failure!!'.format(self.device.devNo))
  165. elif cmd == '04': # 上报工作中
  166. Device.update_dev_control_cache(self.device['devNo'], self.event_data)
  167. elif cmd == '00': # 消除故障
  168. ctrInfo = Device.get_dev_control_cache(self.device['devNo'])
  169. ctrInfo.update({'status': self.event_data.get('status')})
  170. ctrInfo.pop('funCode', None)
  171. ctrInfo.pop('statusInfo', None)
  172. Device.update_dev_control_cache(self.device['devNo'], ctrInfo)
  173. logger.info('devNo=<{}> Fault removal!!'.format(self.device.devNo))
  174. class LSHBonlineCardEvent(WorkEvent):
  175. def do(self, **args):
  176. if self.event_data.get('funCode') == '19': # 在线卡请求余额
  177. cardNo = self.event_data.get('cardNo', None)
  178. cardNoHex = self.event_data.get('cardNoHex', None)
  179. occupyData = self.event_data.get('occupyData')
  180. card = self.update_card_dealer_and_type(cardNo)
  181. if not card:
  182. logger.info('no bind card!! cardNo=<{}>'.format(cardNo))
  183. balance = 0
  184. else:
  185. #: 首先检查订单,并进行充值
  186. #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来
  187. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  188. if card_recharge_order:
  189. result = self.recharge_id_card(card=card,
  190. rechargeType='append',
  191. order=card_recharge_order)
  192. card.reload()
  193. if card.frozen:
  194. balance = 0
  195. else:
  196. balance = card.balance
  197. self.deviceAdapter.response_card_money(cardNoHex, balance, occupyData)
  198. elif self.event_data.get('funCode') == '20': # 在线卡请求更新卡余额
  199. cardNo = self.event_data.get('cardNo', None)
  200. cardNoHex = self.event_data.get('cardNoHex', None)
  201. occupyData = self.event_data.get('occupyData', None)
  202. card = self.update_card_dealer_and_type(cardNo)
  203. if not card:
  204. return
  205. else:
  206. card_left = RMB(card.balance)
  207. cardBalance = RMB(self.event_data.get('cardBalance', 0))
  208. if cardBalance >= card_left:
  209. # 处理充值的情况
  210. oper_money = cardBalance - card_left
  211. # 建立卡充值订单
  212. openId = card.cardNo
  213. cardId = card.id
  214. money = RMB(0)
  215. coins = RMB(oper_money)
  216. group = Group.get_group(self.device["groupId"])
  217. rechangeOrder = None
  218. cardRechangeOrder = CardRechargeOrder.new_one(openId, cardId, cardNo, money, coins, group,
  219. rechangeOrder,
  220. rechargeType="rewrite")
  221. cardRechangeOrder.update(remarks="经销商线下复写卡金额", status='finished')
  222. # 更新卡余额
  223. card.update(balance=cardBalance)
  224. # 充值必然是结算
  225. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB_NOTIFY:
  226. extra = []
  227. cacheInfo = Device.get_dev_control_cache(self.device.devNo)
  228. orderNo = cacheInfo.get('orderNo')
  229. order = ConsumeRecord.objects.get(orderNo=orderNo) # type:ConsumeRecord
  230. oldBalance = RMB(cacheInfo.get('oldBalance'))
  231. actualRefund = cardBalance - oldBalance
  232. spendMoney = order.money
  233. usedMoney = spendMoney - actualRefund
  234. newCard = self.update_card_dealer_and_type(cardNo)
  235. extra.append({"实体卡": u"{}--No:{}".format(card.cardName or card.nickName, card.cardNo)})
  236. extra.append({"使用金额": u"{} 元".format(usedMoney)})
  237. extra.append({"卡余额": u"{} 元".format(RMB(newCard.balance))})
  238. self.notify_user_service_complete(
  239. service_name='',
  240. openid=card.managerialOpenId,
  241. port=None,
  242. address=group['address'],
  243. reason=None,
  244. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  245. extra=extra
  246. )
  247. # 结束
  248. logger.info(
  249. 'devNo=<{}> cardNo=<{}> offline_recharge=<{}> last_balance=<{}> now_balance=<{}>'.format(
  250. self.device.devNo, cardNo, oper_money, card_left, cardBalance))
  251. elif cardBalance < card_left:
  252. # 处理扣费的情况
  253. # 如果是扣费,必然是刷卡启动
  254. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB_NOTIFY:
  255. self.notify_user(
  256. managerialOpenId=card.managerialOpenId,
  257. templateName="service_start",
  258. title=u'亲,您绑定的卡:%s(名称:%s),正在%s启动服务。\\n' % (card.cardNo,card.cardName,self.device.group.address),
  259. service=u"卡内余额{}元".format(card_left),
  260. time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  261. remark=""
  262. )
  263. oper_money = card_left - cardBalance
  264. servicedInfo = {
  265. DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: oper_money.mongo_amount,
  266. 'cardNo': cardNo,
  267. 'cardBalance': cardBalance.mongo_amount
  268. }
  269. # 建立卡消费订单
  270. orderNo, cardOrderNo = self.record_consume_for_card(card, oper_money, servicedInfo=servicedInfo)
  271. # 更新卡余额
  272. card.update(balance=cardBalance)
  273. Device.update_dev_control_cache(self.device.devNo,{'orderNo':orderNo,'oldBalance':cardBalance})
  274. # 结束
  275. logger.info(
  276. 'devNo=<{}> cardNo=<{}> consume_balance=<{}> last_balance=<{}> now_balance=<{}>'.format(
  277. self.device.devNo, cardNo, oper_money, card_left, cardBalance))
  278. pass
  279. else:
  280. # 不处理
  281. logger.info('cardNo=<{}> no change return !!!')
  282. self.deviceAdapter.response_card_change_sucess(cardNoHex, cardBalance, occupyData)