mycard.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. """
  4. 整个流程:
  5. MyWorkEvent
  6. 1 刷空后收到查询事件--> 2 根据卡号在本地查询卡信息(没有则创建) --> 3 根据卡信息找到卡片是否存在未付款订单 --> 4 清理付款这些订单
  7. --> 5 清理后订单后,收到余额,返回给模块
  8. MyWorkEvent
  9. 1 收到上报事件请求扣款(洗衣机已经启动) --> 2 创建订单(默认非正常订单) --> 3 洗衣机上报状态更新订单状态(扣款成功,
  10. 修改订单为正常,添加付款信息)--> 4 核销该上报事件
  11. 白名单:serviceCache.set(yc-card-card_no_hex,1) 白名单固定卡 757996699 不走查询 不会走扣费 会生存订单!
  12. 测试卡号:757996699
  13. 日志前缀:caiyi_
  14. """
  15. import datetime
  16. import json
  17. import logging
  18. import time
  19. from functools import wraps
  20. from arrow import Arrow
  21. from django.conf import settings
  22. from mongoengine import Q
  23. from typing import TYPE_CHECKING
  24. from apilib.monetary import VirtualCoin, RMB
  25. from apilib.utils_string import cn
  26. from apps import serviceCache
  27. from apps.web.constant import DeviceCmdCode, ErrorCode, DeviceErrorCodeDesc, START_DEVICE_STATUS, Const
  28. from apps.web.common.transaction import UserConsumeSubType
  29. from apps.web.core.adapter.base import reverse_hex
  30. from apps.web.core.exceptions import ServiceException
  31. from apps.web.core.networking import MessageSender
  32. from apps.web.dealer.models import Dealer
  33. from apps.web.device.models import Group, Device
  34. from apps.web.eventer.base import AckEvent, WorkEvent
  35. from apps.web.eventer import EventBuilder
  36. from apps.web.user.models import ConsumeRecord, MyUser, Card, ServiceProgress
  37. from apps.web.south_intf.yuchuanApi import YuChuanApi
  38. from apps.web.user.utils import freeze_user_balance, clear_frozen_user_balance
  39. from apps.web.utils import set_start_key_status
  40. if TYPE_CHECKING:
  41. pass
  42. logger = logging.getLogger(__name__)
  43. # 学校服务器地址
  44. # url = 'http://119.136.18.14:9002'
  45. # termId = '2'
  46. # 测试服务器地址
  47. # url = 'http://120.237.110.50:7622',
  48. # termId = '104',
  49. # 配置
  50. config_dic = {
  51. # 接口
  52. 'url': 'http://119.136.18.14:9002',
  53. 'systemName': 'schooladmin',
  54. 'termId': '101',
  55. 'bagCode': "1",
  56. 'roomNumb': '12345',
  57. # 中间库
  58. 'HOST': "119.136.18.14",
  59. 'PART': '1433',
  60. 'USER': 'yczn',
  61. 'PASSWORD': 'yczn123',
  62. 'DATABASE': 'q1_base',
  63. 'TABLE': 'USER_CARDINFO'
  64. }
  65. class Tools:
  66. @staticmethod
  67. def pass_same_event(exp = 30):
  68. def warpper(func):
  69. @wraps(func)
  70. def inner(self, *args, **kwargs):
  71. if serviceCache.get("yc_%s" % self.event_data['IMEI']):
  72. logger.info('\33[36m caiyi_相同查询事件上报 pass掉 \33[0m')
  73. return
  74. serviceCache.set("yc_%s" % self.event_data['IMEI'], 1, exp)
  75. try:
  76. func(self, *args, **kwargs)
  77. except Exception as e:
  78. pass
  79. serviceCache.delete("yc_%s" % self.event_data['IMEI'])
  80. return inner
  81. return warpper
  82. class builder(EventBuilder):
  83. def __getEvent__(self, device_event):
  84. if 'funCode' in device_event and device_event['funCode'] == '11':
  85. return MyWorkEvent(self.deviceAdapter, device_event)
  86. else:
  87. if 'order_id' in device_event:
  88. if device_event['order_type'] == 'com_start':
  89. return MyNetPayAckEvent(self.deviceAdapter, device_event)
  90. if device_event['order_type'] == 'id_start':
  91. return MyIDStartAckEvent(self.deviceAdapter, device_event)
  92. class MyWorkEvent(WorkEvent):
  93. # 保存用户到本地,没有余额信息(用card_no占用openId字段为用户以后扫码用户绑定时候直接获取根据卡号获取卡对象)
  94. def save_user_info(self, user_info ,devNo):
  95. """
  96. user_info = {"factoryFixId": 2869422464,
  97. "subsidyValue": 0,
  98. "bankCardNo": "",
  99. "creditValue": 11.27,
  100. "orderingValue": 0,
  101. "mainDeputyType": 1,
  102. "cardNo": 101,
  103. "userXm": "测试人员",
  104. "userNumb": "1001",
  105. "userId": "20050814503501000008",
  106. "consumeValue": 11.27,
  107. "cardStatusId": 1,
  108. "waterValue": 10.0,
  109. "cardId": "20050814505701000002",
  110. "repastValue": 0,
  111. "identityNumber": "",
  112. "xfPwd": "MTIzNDU2"}
  113. """
  114. cardNo = str(user_info.get('factoryFixId')) # 物理卡号
  115. cardName = str(user_info.get('userXm')) # 持卡人
  116. campus_user_num = str(user_info.get('userNumb'))
  117. # 存入本地服务器
  118. card = Card(cardNo = cardNo, cardName = cardName, remarks = '宇川一卡通', agentId = self.dealer.agentId,
  119. openId = cardNo, dealerId = str(self.dealer.id), cardType = 'YuChuanCard', isHaveBalance=False, devNo=devNo)
  120. card.attachParas = {'campus_user_num': campus_user_num, 'card_dealer': "宇川智能平台一卡通", "unpay_order": []}
  121. card.save()
  122. def get_old_order_by_card(self, card):
  123. # type:# (object)->Card
  124. dealers = Dealer.objects.filter(agentId = self.dealer.agentId)
  125. dealers = [str(dealer.id) for dealer in dealers]
  126. orders = ConsumeRecord.objects.filter(Q(openId__in = [card.openId, card.cardNo]) &
  127. Q(ownerId__in = dealers),
  128. remarks = 'YuChuanCard',
  129. isNormal = False,
  130. status__ne = 'finished')
  131. return orders
  132. # @Tools.pass_same_event(5)
  133. def do(self, **args):
  134. yc = YuChuanApi(**config_dic)
  135. factoryFixId_hex = str(self.event_data['cardNo'])
  136. factoryFixId = str(int(reverse_hex(factoryFixId_hex), 16))
  137. devNo = str(self.event_data.get('IMEI'))
  138. logger.info(
  139. '\33[32m caiyi_received data:{},cardNo:{} \33[0m'.format(json.dumps(self.event_data, ), factoryFixId))
  140. # 测试白名单
  141. test_card = serviceCache.get('yc-card-{}'.format(factoryFixId_hex))
  142. if test_card:
  143. factoryFixId = '757996699'
  144. logger.debug('\33[32m caiyi_yc_test_card,get_balance \33[0m')
  145. price = self.device['otherConf'].get('cardPrice', 1)
  146. packages = self.device['washConfig']
  147. package = max(packages.values(), key=lambda x: x["coins"])
  148. max_coin = int(package.get("coins"))
  149. each_coin = int(self.device['otherConf'].get('eachCoin', 1))
  150. payload = {'balance': RMB.yuan_to_fen(9999), 'price': int(price * 100), 'funCode': '11',
  151. 'cardNo': factoryFixId_hex,
  152. 'max_coin': max_coin, "driver_type": "aux_uart", "time": 15,'each_coin':each_coin}
  153. MessageSender.send_no_wait(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload)
  154. logger.info("\33[32m caiyi_yc_test_card_payload:%s\33[0m" % json.dumps(payload, ensure_ascii = False,
  155. encoding = 'utf-8'))
  156. return
  157. balance = RMB(0)
  158. payload = serviceCache.get('yuchuanyikatong_%s_%s' % (self.device.logicalCode, factoryFixId))
  159. if payload:
  160. MessageSender.send_no_wait(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload)
  161. logger.info(
  162. '\33[32m caiyi_payload(cache):%s\33[0m' % json.dumps(payload, encoding = 'utf-8', ensure_ascii = False))
  163. return
  164. # TODO 清理订单,请求余额
  165. # 先查询卡,如果没有就创建卡信息
  166. card = Card.objects.filter(cardNo = factoryFixId, cardType = 'YuChuanCard').first()
  167. if not card:
  168. user_info = yc.get_user_info(factoryFixId)
  169. # 如果宇川服务器上找不到卡号,则卡不对,不返回数据
  170. if not user_info:
  171. logger.info(
  172. '\33[32m caiyi_The server did not find the user cardNo:{},cardNo_hex:{}\33[0m'.format(factoryFixId,
  173. factoryFixId_hex))
  174. return
  175. self.save_user_info(user_info,devNo)
  176. balance = RMB(user_info.get('consumeValue'))
  177. # 如果有卡,查看之前的订单是否都付款成功
  178. else:
  179. unpay_ordet_list = card.attachParas.get('unpay_order')
  180. if unpay_ordet_list:
  181. unpay_orders = ConsumeRecord.objects.filter(id__in = unpay_ordet_list)
  182. userNumb = card.attachParas.get('campus_user_num')
  183. for order in unpay_orders:
  184. data = {
  185. "orderSerial": str(order.orderNo),
  186. "userNumb": str(userNumb),
  187. "factoryFixId": str(factoryFixId),
  188. "consumeValue": str(order.coin),
  189. }
  190. # 需要测试确认扣费成功
  191. res = yc.pay_order(**data)
  192. if not res:
  193. logger.info(
  194. '\33[32m caiyi_Clear order is error,cardNo:{},orderNo:{},msg:{} \33[0m'.format(factoryFixId,
  195. order.orderNo,
  196. json.dumps(
  197. res,
  198. encoding = 'utf-8',
  199. ensure_ascii = False)))
  200. continue
  201. if res['success'] == False:
  202. logger.info(
  203. "\33[32m caiyi_Clear order failed,cardNo:{},orderNo:{},msg:{} \33[0m".format(factoryFixId,
  204. order.orderNo,
  205. json.dumps(res,
  206. encoding = 'utf-8',
  207. ensure_ascii = False)))
  208. continue
  209. if res['success'] == True:
  210. order.paymentInfo['coins'] = str(order.coin)
  211. order.attachParas['coins'] = str(order.coin)
  212. order.attachParas['isCleanOrder'] = True
  213. order.status = 'finished'
  214. order.isNormal = True
  215. order.save()
  216. unpay_ordet_list.remove(str(order.id))
  217. balance = res.get('data').get('consumeValue')
  218. logger.info(
  219. "\33[32m caiyi_Clear order success,coin:{},orderNo:{},msg:{}\33[0m".format(order.coin,
  220. order.orderNo,
  221. json.dumps(res,
  222. encoding = 'utf-8',
  223. ensure_ascii = False)))
  224. # 将清单后的ordet_set塞回去
  225. card.attachParas['unpay_order'] = unpay_ordet_list
  226. card.save()
  227. # 如果还有未付订单,直接返回,无法使用!!!
  228. if unpay_ordet_list:
  229. logger.info(
  230. '\33[32m caiyi_card has unpay orders!!!,cardNo:{},cardNo_hex:{} \33[0m'.format(factoryFixId,
  231. factoryFixId))
  232. return
  233. # 没有欠费订单
  234. else:
  235. user_info = yc.get_user_info(factoryFixId)
  236. if not user_info:
  237. logger.info(
  238. '\33[32m caiyi_The YC_server did not find the user cardNo:{},cardNo_hex:{}\33[0m'.format(
  239. factoryFixId,
  240. factoryFixId_hex))
  241. return
  242. balance = RMB(user_info.get('consumeValue'))
  243. # 添加自定义定价
  244. price = int(self.device['otherConf'].get('cardPrice', 1))
  245. # 判断balance 是否能完成本次支付
  246. if balance < RMB(price):
  247. logger.info(
  248. '\33[32m caiyi_The balance on the card is insufficient. balance:{} price:{} cardNo:{},cardNo_heX:{} \33[0m'.format(
  249. balance, price, factoryFixId, factoryFixId_hex))
  250. return
  251. packages = self.device['washConfig']
  252. package = max(packages.values(), key = lambda x: x["coins"])
  253. max_coin = int(package.get("coins"))
  254. time_value = int(package.get("time", 15))
  255. # 下多少个脉冲
  256. each_coin = int(self.device['otherConf'].get('eachCoin', 1))
  257. payload = {'balance': RMB.yuan_to_fen(balance), 'price': price * 100, 'funCode': '11',
  258. 'cardNo': factoryFixId_hex,
  259. 'max_coin': int(max_coin), "driver_type": "aux_uart", "time": time_value,'each_coin':each_coin}
  260. serviceCache.set('yuchuanyikatong_%s_%s' % (self.device.logicalCode, factoryFixId), payload, 10)
  261. MessageSender.send_no_wait(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload)
  262. logger.info("\33[32m caiyi_payload:%s\33[0m" % json.dumps(payload, ensure_ascii = False, encoding = 'utf-8'))
  263. class MyIDStartAckEvent(AckEvent):
  264. def get_or_create_order(self, order_id, card_no, rmb, campus_user_num):
  265. packages = self.device['washConfig']
  266. package = packages.get(str(int(rmb)), {})
  267. order = ConsumeRecord.objects(startKey = str(order_id)).first()
  268. if not order:
  269. attach_paras = {
  270. 'card_dealer': 'YuChuanCard',
  271. 'coins': str(VirtualCoin(0).mongo_amount),
  272. 'card_no': card_no,
  273. 'campus_user_num': campus_user_num,
  274. 'isCleanOrder': False}
  275. order = ConsumeRecord.new_one(
  276. order_no = ConsumeRecord.make_no(card_no, UserConsumeSubType.CARD),
  277. user = MyUser(openId = card_no, nickname = ''),
  278. device = self.device,
  279. group = Group.get_group(self.device.groupId),
  280. package = package, # TODO: 补充刷卡单价配置
  281. attach_paras = attach_paras,
  282. pay_info = {
  283. 'via': 'card',
  284. 'coins': str(VirtualCoin(0).mongo_amount),
  285. },
  286. start_key = str(order_id))
  287. order.coin = rmb
  288. order.remarks = 'YuChuanCard'
  289. order.save()
  290. return order
  291. def do_impl(self, **args):
  292. yc = YuChuanApi(**config_dic)
  293. order_id = self.event_data['order_id']
  294. card_no_hex = str(self.event_data['cardNo'])
  295. card_no = str(int(reverse_hex(card_no_hex), 16))
  296. devNo = str(self.event_data.get('IMEI'))
  297. logger.info('\33[32m caiyi_received data:{},cardNo:{} \33[0m'.format(json.dumps(self.event_data, ), card_no))
  298. # 测试白名单
  299. test_card = serviceCache.get('yc-card-{}'.format(card_no_hex))
  300. if test_card:
  301. card_no = '757996699'
  302. logger.debug('caiyi_yc_test_card,to pay!!!')
  303. status = self.event_data['status']
  304. duration = self.event_data.get('duration', 0) # 本次的使用时间,单位秒 只有状态为running的时候才会出现
  305. rmb = RMB.fen_to_yuan(self.event_data['fee']) # 扣除的费用, 分为单位,转换为元
  306. # 查询该卡片
  307. card = Card.objects.filter(cardNo = card_no, cardType = 'YuChuanCard').first()
  308. if not card:
  309. # 先查询余额的时候已经做过卡片核实,如果查不到该卡片,说明有问题
  310. logger.info('\33[32m caiyi_The server did not find the user cardNo:{},cardNo_hex:{}\33[0m'.format(card_no,
  311. card_no_hex))
  312. raise ServiceException({'result': 2, 'description': u"没有找到该卡片"})
  313. userNumb = card.attachParas.get('campus_user_num')
  314. order = self.get_or_create_order(order_id, card_no, rmb, userNumb) # type: ConsumeRecord
  315. # 卡片记录最后一次刷卡的设备
  316. card.devNo = devNo
  317. card.save()
  318. # 白名单订单处理
  319. if test_card:
  320. order.paymentInfo.update({'coins': str(rmb), 'duration': str(int(duration) / 60)})
  321. order.attachParas.update({'coins': str(rmb)})
  322. order.status = self.event_data['status']
  323. order.isNormal = True
  324. order.save()
  325. logger.info(
  326. "\33[32m caiyi_order is finished, cardNo:%s,cardNo_hex:%s,coin:%s,orderNo:%s,\33[0m" % (
  327. card_no, card_no_hex, order.coin, order.orderNo,))
  328. return
  329. if status == 'running' or status == 'finished':
  330. if order.status == 'created':
  331. factoryFixId = str(card_no)
  332. pay_order_model = {
  333. "orderSerial": str(order.orderNo),
  334. "userNumb": userNumb,
  335. "factoryFixId": factoryFixId,
  336. "consumeValue": str(order.coin),
  337. }
  338. n = 0
  339. unpay_ordet_list = card.attachParas.get('unpay_order')
  340. while n < 5:
  341. res = yc.pay_order(**pay_order_model)
  342. if res['success'] == True:
  343. order.paymentInfo.update({'coins': str(rmb), 'duration': str(int(duration) / 60)})
  344. order.attachParas.update({'coins': str(rmb)})
  345. order.status = self.event_data['status']
  346. order.isNormal = True
  347. order.save()
  348. logger.info("\33[32m caiyi_order is finished, coin:%s,orderNo:%s,msg:%s\33[0m" % (
  349. order.coin, order.orderNo,
  350. json.dumps(res,
  351. encoding = 'utf-8',
  352. ensure_ascii = False)
  353. ))
  354. break
  355. if res['success'] == False:
  356. # 保存不在未支付的订单号
  357. if str(order.id) not in unpay_ordet_list:
  358. unpay_ordet_list.append(str(order.id))
  359. card.attachParas['unpay_order'] = unpay_ordet_list
  360. card.save()
  361. logger.info(
  362. "caiyi_pay order fail! devNo:%s,orderNo:%s,coin:%s,msg:%s" % (order.devNo, order.orderNo,
  363. order.coin,
  364. json.dumps(res,
  365. encoding = 'utf-8',
  366. ensure_ascii = False)))
  367. break
  368. time.sleep(1)
  369. n += 1
  370. if n == 5:
  371. unpay_ordet_list.append(str(order.id))
  372. card.attachParas['unpay_order'] = unpay_ordet_list
  373. card.save()
  374. logger.info(
  375. "\33[32m caiyi_pay order fail! cardNo:%s,orderNo:%s,coin:%s\33[0m" % (factoryFixId, order.coin,
  376. order.orderNo))
  377. elif order.status == 'running' or order.status == 'finished':
  378. # 如果该笔订单显示不正常(默认值为False)
  379. if order.isNormal is False:
  380. pay_order_model = {
  381. "orderSerial": str(order.orderNo),
  382. "userNumb": userNumb,
  383. "factoryFixId": str(card_no),
  384. "consumeValue": str(order.coin),
  385. }
  386. res = yc.pay_order(**pay_order_model)
  387. if res['success'] != True:
  388. logger.info("\33[32m caiyi_pay order fail! cardNo:%s,orderNo:%s,coin:%s,msg:%s\33[0m" % (
  389. card_no, order.coin,
  390. order.orderNo,
  391. json.dumps(res, encoding = 'utf-8', ensure_ascii = False)))
  392. return
  393. if res['success'] == True:
  394. order.paymentInfo.update({'coins': str(rmb), 'duration': str(int(duration) / 60)})
  395. order.attachParas.update({'coins': str(rmb)})
  396. order.status = self.event_data['status']
  397. order.isNormal = True
  398. order.save()
  399. logger.info("\33[32m caiyi_order is finished,cardNo:%s,coin:%s,orderNo:%s,msg:%s\33[0m" % (
  400. card_no, order.coin,
  401. order.orderNo,
  402. json.dumps(res, encoding = 'utf-8', ensure_ascii = False),))
  403. # 该笔订单已经扣费成功了,直接更改状态
  404. else:
  405. if order.status != 'finished':
  406. order.status = status
  407. order.save()
  408. logger.info("\33[32m caiyi_order is finished,cardNo:%s,coin:%s,orderNo:%s\33[0m" % (
  409. card_no, order.coin, order.orderNo,))
  410. serviceCache.delete('yuchuanyikatong_%s' % (card_no)) # 删除payload
  411. class MyNetPayAckEvent(AckEvent):
  412. def deal_running_event(self, order):
  413. # type: (ConsumeRecord)->None
  414. def do_running_order(order, result):
  415. # type: (ConsumeRecord, dict)->None
  416. if order.status in ['running', 'finished']:
  417. logger.debug('order<{}> no need to ack. this has done.'.format(repr(order)))
  418. return
  419. if order.status == 'timeout':
  420. freeze_user_balance(self.device, Group.get_group(order.groupId), order)
  421. err_desc = u'事件上报成功,补充扣款'
  422. else:
  423. err_desc = ''
  424. order.isNormal = True
  425. order.status = 'running'
  426. order.startTime = datetime.datetime.fromtimestamp(result['sts'])
  427. order.save()
  428. do_running_order(order, self.event_data)
  429. start_time = Arrow.fromdatetime(order.startTime, tzinfo = settings.TIME_ZONE)
  430. cache_info = {
  431. 'startTime': start_time.format('YYYY-MM-DD HH:mm:ss'),
  432. 'status': Const.DEV_WORK_STATUS_WORKING,
  433. 'openId': order.openId,
  434. 'orderNo': order.orderNo,
  435. 'coins': order.coin,
  436. 'money': order.money,
  437. 'estimatedTs': int(start_time.timestamp + order.my_package.estimated_duraion),
  438. 'unit': order.my_package.unit,
  439. 'needKind': order.my_package.need_kind,
  440. 'needValue': order.my_package.need_value
  441. }
  442. Device.update_dev_control_cache(self.device.devNo, cache_info)
  443. ServiceProgress.new_progress_for_order(order = order,
  444. device = self.device,
  445. cache_info = cache_info)
  446. def deal_finished_event(self, order):
  447. # type: (ConsumeRecord)->None
  448. def do_finished_order(order, result):
  449. if order.status == 'finished':
  450. logger.debug('order<{}> no need to ack. this has done.'.format(repr(order)))
  451. return
  452. if order.status == 'running':
  453. order.status = 'finished'
  454. order.finishedTime = datetime.datetime.fromtimestamp(result['fts'])
  455. order.save()
  456. else:
  457. if order.status == 'timeout':
  458. freeze_user_balance(self.device, Group.get_group(order.groupId), order)
  459. err_desc = u'事件上报成功,补充扣款'
  460. else:
  461. err_desc = ''
  462. order.isNormal = True
  463. order.status = 'finished'
  464. order.errorDesc = err_desc
  465. order.startTime = datetime.datetime.fromtimestamp(result['sts'])
  466. order.finishedTime = datetime.datetime.fromtimestamp(result['fts'])
  467. order.save()
  468. clear_frozen_user_balance(self.device, order, round(self.event_data['duration'] / 60.0, 2), 0, RMB(0))
  469. if order.status == 'finished':
  470. logger.debug('order<{}> has finished.'.format(repr(order)))
  471. return
  472. do_finished_order(order, self.event_data)
  473. current_cache_info = Device.get_dev_control_cache(self.device.devNo)
  474. if current_cache_info and order.orderNo == current_cache_info.get('orderNo', None):
  475. Device.invalid_device_control_cache(self.device.devNo)
  476. ServiceProgress.objects(open_id = order.openId,
  477. device_imei = self.device.devNo,
  478. port = int(order.used_port),
  479. consumes = order.orderNo).update_one(
  480. upsert = False,
  481. **{
  482. 'isFinished': True,
  483. 'finished_time': Arrow.fromdatetime(order.finishedTime, tzinfo = settings.TIME_ZONE).timestamp
  484. })
  485. def do_impl(self, **args):
  486. order_id = self.event_data['order_id']
  487. order = ConsumeRecord.objects(ownerId = self.device.ownerId,
  488. orderNo = order_id).first() # type: ConsumeRecord
  489. if not order:
  490. logger.debug('order<no={}> is not exist.'.format(self.event_data['order_id']))
  491. return
  492. if order.status == 'finished':
  493. logger.debug('order<{}> has been fished.'.format(repr(order)))
  494. return
  495. if self.event_data['rst'] == ErrorCode.DEVICE_CONN_FAIL:
  496. logger.error('order<{}> timeout.'.format(repr(order)))
  497. if order.status == 'created':
  498. order.isNormal = False
  499. order.status = 'timeout'
  500. order.errorDesc = DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_FAIL)
  501. set_start_key_status(start_key = order.startKey,
  502. state = START_DEVICE_STATUS.TIMEOUT,
  503. reason = cn(DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_FAIL)))
  504. return
  505. if self.event_data['rst'] != ErrorCode.DEVICE_SUCCESS:
  506. logger.error('order<{}> failure.'.format(repr(order)))
  507. if 'errorDesc' in self.event_data:
  508. error_desc = self.event_data['errorDesc']
  509. else:
  510. error_desc = DeviceErrorCodeDesc.get(self.event_data['rst'])
  511. order.status = 'finished'
  512. order.isNormal = False
  513. order.finishedTime = datetime.datetime.fromtimestamp(self.event_data['fts'])
  514. order.errorDesc = error_desc
  515. order.save()
  516. set_start_key_status(start_key = order.startKey,
  517. state = START_DEVICE_STATUS.FAILURE,
  518. reason = cn(error_desc))
  519. return
  520. set_start_key_status(start_key = order.startKey,
  521. state = START_DEVICE_STATUS.FINISHED,
  522. order_id = str(order.id))
  523. if self.event_data['status'] == 'running':
  524. return self.deal_running_event(order)
  525. if self.event_data['status'] == 'finished':
  526. return self.deal_finished_event(order)