weifule_anjian.py 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import json
  5. import logging
  6. from mongoengine import DoesNotExist
  7. from apilib.monetary import RMB, VirtualCoin
  8. from apilib.utils_string import make_title_from_dict
  9. from apilib.utils_sys import memcache_lock
  10. from apps.web.constant import Const, ErrorCode, DEALER_CONSUMPTION_AGG_KIND
  11. from apps.web.device.models import Group, Device
  12. from apps.web.eventer import EventBuilder
  13. from apps.web.eventer.base import WorkEvent
  14. from apps.web.eventer.weifuleCommon import WeiFuLeStatusEvent, WeiFuLeCommonEvent
  15. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, \
  16. ConsumeRecord, Card, CardConsumeRecord, CardRechargeOrder, MyUser, CardRechargeRecord, RechargeRecord, \
  17. MonthlyPackage
  18. logger = logging.getLogger(__name__)
  19. created_order_32 = 32
  20. exec_order_33 = 33
  21. finished_order_34 = 34
  22. id_card_request_35 = 35
  23. card_recharge_order_36 = 36
  24. status_change_event_44 = 44
  25. ic_consume_event_48 = 48 # ic卡花钱的时候,会上报此事件
  26. part_sn_event = 49 # 组件上报相关信息
  27. card_is_normal = 1
  28. card_not_in_db = 2
  29. card_is_forzen = 3
  30. card_has_not_order = 4 # IC卡适用
  31. card_less_balance = 5 # ID卡适用
  32. card_type_is_ic = 6 # IC卡不允许当做ID卡使用
  33. no_load_code = 7
  34. class builder(EventBuilder):
  35. def __getEvent__(self, device_event):
  36. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  37. if event_data is None:
  38. return None
  39. if event_data['fun_code'] in [created_order_32, exec_order_33, finished_order_34, id_card_request_35,
  40. card_recharge_order_36]:
  41. return ChargingSocketWorkEvent(self.deviceAdapter, event_data)
  42. if event_data['fun_code'] in [status_change_event_44]:
  43. return WeiFuLeStatusEvent(self.deviceAdapter, device_event)
  44. class ChargingSocketWorkEvent(WorkEvent, WeiFuLeCommonEvent):
  45. def analyse_need_from_package(self, order):
  46. needKind, needValue, unit = 'needElec', 0, u'度'
  47. if order['chrmt'] == 'TIME':
  48. needKind = 'needTime'
  49. needValue = order['amount_time'] / 60
  50. unit = u'分钟'
  51. else:
  52. needValue = order['amount_elec'] / 1000000.0
  53. return needKind, needValue, unit
  54. def create_progress_for_socket_order(self, consumeRcd, order):
  55. try:
  56. port = int(order['port'])
  57. progress = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=port).first()
  58. if not progress:
  59. progress = ServiceProgress(device_imei=self.device.devNo, port=port)
  60. progress.start_time = order['create_time']
  61. progress.finished_time = order['create_time'] + order.get('amount_time', 60 * 60 * 12)
  62. progress.isFinished = False
  63. else:
  64. if order['id'] in progress.consumes:
  65. return
  66. if progress.isFinished == False:
  67. progress.finished_time = progress.finished_time + order.get('amount_time', 60 * 60 * 12)
  68. else:
  69. progress.consumes = []
  70. progress.start_time = order['create_time']
  71. progress.finished_time = order['create_time'] + order.get('amount_time', 60 * 60 * 12)
  72. progress.isFinished = False
  73. progress.open_id = consumeRcd.openId
  74. progress.consumes.append(order['id'])
  75. progress.status = 'running'
  76. progress.save()
  77. except Exception as e:
  78. logger.exception(e)
  79. def do(self, **args):
  80. devNo = self.device['devNo']
  81. funCode = self.event_data.get('fun_code')
  82. order = self.event_data.get('order', {})
  83. logger.info('weifule charging event detected, devNo=%s' % (devNo,))
  84. with memcache_lock(key='%s-%s-%s-finished' % (devNo, order.get('id'), funCode), value='1',
  85. expire=120) as acquired:
  86. if acquired:
  87. self._do_ack_order(order)
  88. try:
  89. if funCode == created_order_32:
  90. self._do_created_order_32(order)
  91. elif funCode == exec_order_33:
  92. self._do_exec_order_33(order)
  93. elif funCode == finished_order_34 and order['order_type'] != 'card_charge':
  94. self._do_finished_order_34(order)
  95. elif funCode == finished_order_34 and order['order_type'] == 'card_charge':
  96. self.update_card_recharge_for_success_event(order['id'], RMB(order['balance'] / 100.0))
  97. elif funCode == id_card_request_35:
  98. self.response_id_card()
  99. elif funCode == card_recharge_order_36: # 如果是卡充值,直接回复订单
  100. self.deal_with_ic_charge_event()
  101. except Exception:
  102. import traceback
  103. logger.warn(traceback.format_exc())
  104. logger.info('deal order is finished < funCode: {} order: {} >'.format(funCode, order.get('id')))
  105. else:
  106. logger.info('weifule charging event is doing !!!, devNo=%s' % (devNo,))
  107. def update_balance_for_IC_card(self, card, balance):
  108. card.balance = balance
  109. try:
  110. card.save()
  111. except Exception, e:
  112. pass
  113. def __translate_reason(self, cause, chrmt):
  114. if cause == 1:
  115. if chrmt == 'TIME':
  116. return u'订购时间已经用完。'
  117. else:
  118. return u'订购电量已经用完。'
  119. elif cause == 2:
  120. return u'用户远程停止。'
  121. elif cause == 3:
  122. return u'管理员操作停止。'
  123. elif cause == 4:
  124. return u'经销商远程停止。'
  125. elif cause == 5:
  126. return u'用户拔掉充电器,或者插座脱落。'
  127. elif cause == 6:
  128. return u'端口功率过载,系统为了安全,关闭此充电端口。'
  129. elif cause == 7:
  130. return u'整机电压过载,系统为了安全,关闭所有充电端口。'
  131. elif cause == 8:
  132. return u'端口电流过载,系统为了安全,关闭此充电端口。'
  133. elif cause == 9:
  134. return u'整机功率超限,系统为了安全,关闭所有充电端口。'
  135. elif cause == 10:
  136. return u'检测到温度超限,系统为了安全,关闭所有充电端口。'
  137. elif cause == 11:
  138. return u'充满自停'
  139. elif cause == 20:
  140. return u'端口功率过小。可能是电池已经充满,也可能是所接负载功率太小'
  141. return u'充电结束。'
  142. def record_consume_for_card(self, card, money, orderNo):
  143. group = Group.get_group(self.device['groupId'])
  144. address = group['address']
  145. group_number = self.device['groupNumber']
  146. now = datetime.datetime.now()
  147. new_record = {
  148. 'orderNo': orderNo,
  149. 'time': now.strftime('%Y-%m-%d %H:%M:%S'),
  150. 'dateTimeAdded': now,
  151. 'openId': card.openId,
  152. 'nickname': card.nickName,
  153. 'ownerId': self.device['ownerId'],
  154. 'coin': money.mongo_amount,
  155. 'money': money.mongo_amount,
  156. 'devNo': self.device['devNo'],
  157. 'logicalCode': self.device['logicalCode'],
  158. 'groupId': self.device['groupId'],
  159. 'address': address,
  160. 'groupNumber': group_number,
  161. 'groupName': group['groupName'],
  162. 'devTypeCode': self.device.devTypeCode,
  163. 'devTypeName': self.device.devTypeName,
  164. 'isNormal': True,
  165. 'remarks': u'刷卡消费',
  166. 'errorDesc': '',
  167. 'sequanceNo': '',
  168. 'desc': '',
  169. 'attachParas': {},
  170. 'servicedInfo': {}
  171. }
  172. ConsumeRecord.get_collection().insert_one(new_record)
  173. # 刷卡消费也记录一条数据
  174. new_card_record = {
  175. 'orderNo': orderNo,
  176. 'openId': card.openId,
  177. 'cardId': str(card.id),
  178. 'money': money.mongo_amount,
  179. 'balance': card.balance.mongo_amount,
  180. 'devNo': self.device['devNo'],
  181. 'devType': self.device['devType']['name'],
  182. 'logicalCode': self.device['logicalCode'],
  183. 'groupId': self.device['groupId'],
  184. 'address': address,
  185. 'groupNumber': group_number,
  186. 'groupName': group['groupName'],
  187. 'result': 'success',
  188. 'remarks': u'刷卡消费',
  189. 'sequanceNo': '',
  190. 'dateTimeAdded': datetime.datetime.now(),
  191. 'desc': '',
  192. 'servicedInfo': {},
  193. 'linkedConsumeRcdOrderNo': str(new_record['orderNo'])
  194. }
  195. CardConsumeRecord.get_collection().insert(new_card_record)
  196. return new_record['orderNo'], new_card_record['orderNo']
  197. def record_consume_for_monthly_package(self, card, info):
  198. # type: (Card, dict)-> (ConsumeRecord, CardConsumeRecord)
  199. monthlyPackage = card.monthlyPackage
  200. group = Group.get_group(self.device['groupId'])
  201. address = group['address']
  202. group_number = self.device['groupNumber']
  203. now = datetime.datetime.now()
  204. new_record = {
  205. 'orderNo': info['id'],
  206. 'time': now.strftime('%Y-%m-%d %H:%M:%S'),
  207. 'dateTimeAdded': now,
  208. 'openId': card.openId,
  209. 'nickname': card.nickName,
  210. 'ownerId': self.device['ownerId'],
  211. 'coin': VirtualCoin(0).mongo_amount,
  212. 'money': RMB(0).mongo_amount,
  213. 'devNo': self.device['devNo'],
  214. 'logicalCode': self.device['logicalCode'],
  215. 'groupId': self.device['groupId'],
  216. 'address': address,
  217. 'groupNumber': group_number,
  218. 'groupName': group['groupName'],
  219. 'devTypeCode': self.device.devTypeCode,
  220. 'devTypeName': self.device.devTypeName,
  221. 'isNormal': True,
  222. 'remarks': u'刷卡(包月卡抵扣)',
  223. 'errorDesc': '',
  224. 'sequanceNo': '',
  225. 'desc': '',
  226. 'attachParas': {'monthlyPackageId': str(monthlyPackage.id)},
  227. 'servicedInfo': {'chargeIndex': info['port'], 'cardNo': info['card_no']}
  228. }
  229. consumeRcd = ConsumeRecord.objects.create(**new_record)
  230. # 刷卡消费也记录一条数据
  231. new_card_record = {
  232. 'orderNo': info['id'],
  233. 'openId': card.openId,
  234. 'cardId': str(card.id),
  235. 'money': RMB(0).mongo_amount,
  236. 'balance': card.balance.mongo_amount,
  237. 'devNo': self.device['devNo'],
  238. 'devType': self.device['devType']['name'],
  239. 'logicalCode': self.device['logicalCode'],
  240. 'groupId': self.device['groupId'],
  241. 'address': address,
  242. 'groupNumber': group_number,
  243. 'groupName': group['groupName'],
  244. 'result': 'success',
  245. 'remarks': u'刷卡(包月卡抵扣)',
  246. 'sequanceNo': '',
  247. 'dateTimeAdded': datetime.datetime.now(),
  248. 'desc': '',
  249. 'servicedInfo': {'chargeIndex': info['port'], 'cardNo': info['card_no']},
  250. 'linkedConsumeRcdOrderNo': str(new_record['orderNo'])
  251. }
  252. CardConsumeRecord.objects.create(**new_card_record)
  253. return consumeRcd
  254. def _do_ack_order(self, order):
  255. funCode = self.event_data['fun_code']
  256. if funCode in [created_order_32, finished_order_34]:
  257. try:
  258. self.deviceAdapter.ack_event(order['id'], funCode)
  259. except Exception, e:
  260. logger.info('ack event devNo=%s err=%s' % (self.device.devNo, e))
  261. pass
  262. def _do_created_order_32(self, order):
  263. if order['order_type'] == 'apps_start': # 扫码
  264. self.pay_apps_start_by_32(order)
  265. consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id']).first()
  266. if consumeRcd is None: #远程上分的时候,没有consumeRcd
  267. return None
  268. self.create_progress_for_socket_order(consumeRcd, order)
  269. elif order['order_type'] == 'card_start':
  270. cardNo = order['card_no']
  271. # 登记下卡相关信息
  272. if order['card_type'] == 'IC':
  273. card = self.update_card_dealer_and_type(cardNo, 'IC')
  274. if card:
  275. self.update_balance_for_IC_card(card, RMB(order['balance'] / 100.0))
  276. else:
  277. return
  278. # 如果卡冻结了,马上把端口关闭
  279. if card.frozen:
  280. logger.info('this card=%s is frozen,so shut down the port which opened by the card' % cardNo)
  281. self.deviceAdapter.stop_charging_port(order['port'])
  282. else:
  283. card = self.update_card_dealer_and_type(cardNo, 'ID')
  284. if card.monthlyPackage:
  285. return self.start_by_monthly_package(card, order)
  286. balance = card.balance - RMB(order['amount'] / 100.0)
  287. card.balance = balance
  288. # 卡的显示余额同步下
  289. card.showBalance = balance
  290. card.save()
  291. fee = RMB(order['amount'] / 100.0)
  292. # 记录卡消费记录以及消费记录
  293. orderNo, cardOrderNo = self.record_consume_for_card(card, fee, order['id'])
  294. consumeRcd = ConsumeRecord.objects.filter(orderNo=orderNo).first()
  295. if consumeRcd is None:
  296. return
  297. self.create_progress_for_socket_order(consumeRcd, order)
  298. # 通知用户,已经扣费
  299. title = make_title_from_dict([
  300. {u'设备地址': u'{}'.format(self.device.group.address)},
  301. {u'设备编号': u'{}'.format(self.device['logicalCode'])},
  302. {u'实体卡': u'{}--No:{}'.format(card.cardName or card.nickName, card.cardNo)},
  303. {u'本次消费': u'{} 元'.format(fee)},
  304. {u'卡余额': u'{} 元'.format(RMB(order['balance'] / 100.0))},
  305. ])
  306. start_time_stamp = order.get('create_time')
  307. start_time = datetime.datetime.fromtimestamp(start_time_stamp)
  308. self.notify_user(
  309. card.managerialOpenId,
  310. 'dev_start',
  311. **{
  312. 'title': title,
  313. 'things': u'刷卡消费',
  314. 'remark': u'感谢您的支持!',
  315. 'time': start_time.strftime(Const.DATETIME_FMT)
  316. }
  317. )
  318. # 缓存切换
  319. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  320. lineInfo = ctrInfo.get(str(order['port']), {})
  321. if not lineInfo or lineInfo.get('status') == Const.DEV_WORK_STATUS_IDLE:
  322. lineInfo = {
  323. 'port': str(order['port']),
  324. 'status': Const.DEV_WORK_STATUS_WORKING,
  325. 'order_type': 'card_start',
  326. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  327. 'orderNo': orderNo,
  328. }
  329. Device.update_port_control_cache(self.device.devNo, lineInfo)
  330. else:
  331. pass
  332. def _do_exec_order_33(self, order):
  333. now = datetime.datetime.fromtimestamp(order['exec_time'])
  334. consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id']).first()
  335. if not consumeRcd:
  336. logger.info('no this order <{}> '.format(order['id']))
  337. return
  338. consumeRcd.startTime = now
  339. consumeRcd.save()
  340. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  341. lineInfo = ctrInfo.get(str(order['port']), {})
  342. if lineInfo.get('status') == Const.DEV_WORK_STATUS_WORKING and lineInfo.get('orderNo') == order['id']:
  343. lineInfo.update({'chrmt': order['chrmt']})
  344. if 'card_no' in order:
  345. lineInfo.update({'cardType': order.get('card_type'), 'cardNo': order.get('card_no')})
  346. Device.update_port_control_cache(self.device.devNo, lineInfo)
  347. logger.info('now to exec order <{}>'.format(lineInfo.get('orderNo')))
  348. return
  349. consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id']).first()
  350. if consumeRcd is None:
  351. return
  352. lineInfo = {
  353. 'port': str(order['port']),
  354. 'status': Const.DEV_WORK_STATUS_WORKING,
  355. 'order_type': order['order_type'],
  356. 'startTime': now.strftime('%Y-%m-%d %H:%M:%S'),
  357. 'orderNo': consumeRcd.orderNo,
  358. 'chrmt': order['chrmt']
  359. }
  360. if 'card_no' in order:
  361. lineInfo.update({'cardType': order.get('card_type'), 'cardNo': order.get('card_no')})
  362. Device.update_port_control_cache(self.device.devNo, lineInfo)
  363. logger.info('now to exec next order <{}>'.format(lineInfo.get('orderNo')))
  364. def _do_finished_order_34(self, order):
  365. # 如果是离线卡的余额回收,修改下余额,然后直接返回即可
  366. if order['order_type'] == 'card_refund':
  367. return self.end_for_card_refund(order)
  368. self.consumeRcd = self.common_verify_order(order) # type: ConsumeRecord
  369. if not self.consumeRcd:
  370. return
  371. try:
  372. self._init_common_info(order)
  373. if self.is_postpaid:
  374. return self.end_of_auto_stop(order)
  375. elif self.consumeRcd.monthlyPackageId:
  376. return self.end_for_monthly_package(order)
  377. else:
  378. self._analyze_order_info(order)
  379. self._analyze_notify_info(order)
  380. self._analyze_refund_info(order)
  381. self._calc_refund_coins(order)
  382. self.refundDict.update({'backCount': u'金币:%s' % self.backCoins})
  383. # 虚拟卡
  384. if u'虚拟卡' in self.consumeRcd.remarks:
  385. self.end_for_vCard_start(order)
  386. # 刷卡的方式
  387. elif order['order_type'] == 'card_start' and order['card_no']:
  388. self.end_for_card_start(order)
  389. # 扫码的
  390. else:
  391. self.end_for_app_start(order)
  392. self.consumeRcd.update_service_info(self.consumeDict)
  393. except Exception as e:
  394. logger.exception('some exception happed,devNo=%s,e=%s' % (self.device.devNo, e))
  395. finally:
  396. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  397. lineInfo = ctrInfo.get(str(order['port']), {})
  398. # 如果缓存中要结束的端口是本单的 就清空缓存 否则不处
  399. if order['id'] == lineInfo.get('orderNo'):
  400. Device.clear_port_control_cache(self.device.devNo, order['port'])
  401. # 这里采用更新端口 不操作缓存
  402. self.deviceAdapter.get_port_status_from_dev()
  403. def common_verify_order(self, order):
  404. consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id'],
  405. status__ne='finished').first() # type:ConsumeRecord
  406. if not consumeRcd:
  407. logger.info('Repeat processing!! orderNo<{}>'.format(order['id']))
  408. return
  409. else:
  410. consumeRcd.status = 'finished'
  411. consumeRcd.finishedTime = datetime.datetime.now()
  412. consumeRcd.servicedInfo['source'] = json.dumps(order)
  413. consumeRcd.save()
  414. progress = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=int(order['port']),
  415. consumes__contains=order['id']).first()
  416. if progress is None:
  417. pass
  418. else:
  419. progress.consumes.remove(order['id'])
  420. if len(progress.consumes) > 0: # 还有其他的单未处理完成
  421. progress.save()
  422. else:
  423. progress.status = 'finished' # 此时为本次服务的最后一单
  424. progress.isFinished = True
  425. progress.save()
  426. return consumeRcd
  427. def end_for_card_refund(self, order):
  428. return self.update_card_dealer_and_type(cardNo=order['card_no'], cardType='IC',
  429. balance=RMB(order['balance'] / 100.0))
  430. def deal_with_ic_charge_event(self):
  431. cardNo = self.event_data['card_no']
  432. card = self.update_card_dealer_and_type(cardNo, 'IC')
  433. if not card:
  434. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_not_in_db)
  435. elif card.frozen:
  436. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_is_forzen)
  437. preBalance = card.balance
  438. rechargeOrder = CardRechargeOrder.get_last_to_do_one(str(card.id))
  439. if rechargeOrder:
  440. self.recharge_ic_card(card=card,
  441. preBalance=preBalance,
  442. rechargeType='append',
  443. order=rechargeOrder,
  444. need_verify=False)
  445. else:
  446. return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_has_not_order)
  447. def recharge_ic_card(self, card, preBalance, rechargeType, order, need_verify=True):
  448. # type:(Card, RMB, str, CardRechargeOrder, bool)->bool
  449. """
  450. # rechargeType有两种,一种是用直接覆写overwrite的方式,一种是append追加钱的方式。
  451. # 不同的的设备,充值的方式还不一样.注意:money是实际用户付的钱,coins是给用户充值的钱,比如付10块(money),充15(coins)。
  452. :param card:
  453. :param preBalance:
  454. :param rechargeType:
  455. :param order:
  456. :return:
  457. """
  458. if not order or order.coins == RMB(0):
  459. return False
  460. status = Card.get_card_status(str(card.id))
  461. if status == 'busy':
  462. return False
  463. Card.set_card_status(str(card.id), 'busy')
  464. try:
  465. # IC卡需要下发到设备,设备写卡,把余额打入卡中
  466. if rechargeType == 'overwrite':
  467. sendMoney = preBalance + order.coins
  468. else:
  469. sendMoney = order.coins
  470. # 先判断order最近一次充值是否OK. 满足三个条件才认为上次充值成功:
  471. # 1、操作时间已经超过三天
  472. # 2、操作结果是串口超时, 即result == 1
  473. # 3、当前余额大于最后一次充值操作的充值前余额
  474. if need_verify and len(order.operationLog) > 0:
  475. log = order.operationLog[-1]
  476. result = log['result']
  477. time_delta = (datetime.datetime.now() - log['time']).total_seconds()
  478. last_pre_balance = RMB(log['preBalance'])
  479. if (result == ErrorCode.DEVICE_CONN_FAIL or result == ErrorCode.BOARD_UART_TIMEOUT) \
  480. and (time_delta > 3 * 24 * 3600 or preBalance > last_pre_balance):
  481. logger.debug('{} recharge verify result is finished.'.format(repr(card)))
  482. order.update_after_recharge_ic_card(device=self.device,
  483. sendMoney=sendMoney,
  484. preBalance=preBalance,
  485. result=ErrorCode.SUCCESS,
  486. description=u'充值校验结束')
  487. CardRechargeRecord.add_record(
  488. card=card,
  489. group=Group.get_group(order.groupId),
  490. order=order,
  491. device=self.device)
  492. return False
  493. try:
  494. operation_result, balance = self.deviceAdapter.recharge_card(card.cardNo, sendMoney,
  495. orderNo=str(order.id))
  496. order.update_after_recharge_ic_card(device=self.device,
  497. sendMoney=sendMoney,
  498. preBalance=preBalance,
  499. syncBalance=balance,
  500. result=operation_result['result'],
  501. description=operation_result['description'])
  502. if operation_result['result'] != ErrorCode.SUCCESS:
  503. return False
  504. if not balance:
  505. balance = preBalance + order.coins
  506. CardRechargeRecord.add_record(
  507. card=card,
  508. group=Group.get_group(order.groupId),
  509. order=order,
  510. device=self.device)
  511. # 刷新卡里面的余额
  512. card.balance = balance
  513. card.lastMaxBalance = balance
  514. card.save()
  515. return True
  516. except Exception as e:
  517. order.update_after_recharge_ic_card(device=self.device,
  518. sendMoney=sendMoney,
  519. preBalance=preBalance,
  520. syncBalance=balance,
  521. result=ErrorCode.EXCEPTION,
  522. description=e.message)
  523. return False
  524. except Exception as e:
  525. logger.exception(e)
  526. return False
  527. finally:
  528. Card.set_card_status(str(card.id), 'idle')
  529. def response_id_card(self):
  530. cardNo = self.event_data['card_no']
  531. Card.record_dev_card_no(self.device['devNo'], cardNo)
  532. card = Card.objects.filter(cardNo=cardNo, agentId=self.device.owner.agentId).first()
  533. # 如果没有卡,直接返回
  534. if card is None:
  535. return self.deviceAdapter.response_card_balance(cardNo=cardNo, balance=0, result=card_not_in_db, amount=0)
  536. if card.cardType == '':
  537. card.update(cardType='ID')
  538. elif card.cardType != 'ID': # 如果以前是离线卡,只能用于离线卡,需要提醒用户
  539. return self.deviceAdapter.response_card_balance(cardNo=cardNo, balance=0, result=card_type_is_ic, amount=0)
  540. if card.frozen:
  541. return self.deviceAdapter.response_card_balance(cardNo=cardNo, balance=0, result=card_is_forzen, amount=0)
  542. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  543. if card_recharge_order:
  544. result = self.recharge_id_card(card=card,
  545. rechargeType='append',
  546. order=card_recharge_order)
  547. card.reload()
  548. oper = self.event_data.get('reduce')
  549. fee = RMB(self.device['otherConf'].get('id_card_oncefee', 1))
  550. if card.monthlyPackage:
  551. dayLeft = card.monthlyPackage.to_dict().get('dayLeft')
  552. if dayLeft > 0:
  553. result = card_is_normal
  554. if oper:
  555. balance = fee * dayLeft - fee
  556. else:
  557. balance = fee * dayLeft
  558. return self.deviceAdapter.response_card_balance(cardNo, fee, balance, result)
  559. if oper:
  560. if card.balance >= fee:
  561. result = card_is_normal
  562. balance = card.balance - fee
  563. # balance = card.showBalance * 100
  564. else:
  565. result = card_less_balance
  566. # balance = card.showBalance * 100
  567. balance = card.balance
  568. self.deviceAdapter.response_card_balance(cardNo, fee, balance, result) # 返回的cardNo为16进制
  569. else:
  570. self.deviceAdapter.response_card_balance(cardNo, fee, card.balance, card_is_normal)
  571. def _init_common_info(self, order):
  572. """
  573. 初始化结束要用到的数据
  574. """
  575. order['reason'] = self.__translate_reason(order['cause'], order['chrmt'])
  576. self.consumeDict = {
  577. 'reason': order['reason'],
  578. 'chargeIndex': order['port'],
  579. 'duration': round(order['time'] / 60.0, 1),
  580. 'elec': round(order['elec'] / 1000000.0, 2)
  581. }
  582. self.notifyDict = {
  583. 'title': make_title_from_dict([
  584. {u'设备编号': self.device['logicalCode']},
  585. {u'端口': order['port']},
  586. {u'地址': self.device.group['address']},
  587. {u'结束原因': order['reason']},
  588. {u'充电时间': u'%s分钟' % self.consumeDict['duration']},
  589. ]),
  590. 'service': u'充电服务完成',
  591. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  592. 'remark': u'谢谢您的支持'
  593. }
  594. self.refundDict = {
  595. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  596. }
  597. self.refundProtection = self.device['otherConf'].get('refundProtection', 5)
  598. def _calc_refund_coins(self, order):
  599. coins = self.consumeRcd.coin
  600. self.backCoins = RMB(0)
  601. usedTime = round(order['time'] / 60.0, 1)
  602. if usedTime <= self.refundProtection:
  603. self.backCoins = coins
  604. else:
  605. if self.device.is_auto_refund:
  606. self.backCoins = coins * (float(order['left_money']) / float(order['amount']))
  607. logger.info(
  608. 'REFUND STATUS orderNo=<{}>, refundSwitch={}, refundProtectionTime=<{}>, backCoins=<{}>'.format(
  609. self.consumeRcd.orderNo, self.device.is_auto_refund, self.refundProtection, self.backCoins.mongo_amount
  610. ))
  611. def _analyze_elec_params(self, order):
  612. needElec = round(order['amount_elec'] / 1000000.0, 2)
  613. usedTime = round(order['time'] / 60.0, 1)
  614. usedElec = round(order['elec'] / 1000000.0, 2)
  615. leftElec = round(needElec - usedElec if needElec > usedElec else 0.0, 2)
  616. return leftElec, needElec, usedElec, usedTime
  617. def _analyze_time_params(self, order):
  618. needTime = round(order['amount_time'] / 60.0, 1)
  619. usedTime = round(order['time'] / 60.0, 1)
  620. leftTime = round(order['left_time'] / 60 if order['left_time'] > 0 else 0, 1)
  621. actualNeedTime = round(usedTime + leftTime, 1)
  622. return actualNeedTime, leftTime, needTime, usedTime
  623. def _analyze_order_info(self, order):
  624. if order['chrmt'] == 'TIME':
  625. actualNeedTime, leftTime, needTime, usedTime = self._analyze_time_params(order)
  626. self.consumeDict.update({
  627. 'needTime': needTime,
  628. 'leftTime': leftTime,
  629. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  630. })
  631. else:
  632. leftElec, needElec, usedElec, usedTime = self._analyze_elec_params(order)
  633. self.consumeDict.update({
  634. 'needElec': needElec,
  635. 'leftElec': leftElec,
  636. })
  637. def _analyze_notify_info(self, order):
  638. if order['chrmt'] == 'TIME':
  639. actualNeedTime, leftTime, needTime, usedTime = self._analyze_time_params(order)
  640. self.notifyDict.update({'title': make_title_from_dict([
  641. {u'设备编号': self.device['logicalCode']},
  642. {u'端口': order['port']},
  643. {u'地址': self.device.group['address']},
  644. {u'结束原因': order['reason']},
  645. {u'订购时间': u'%s分钟' % needTime},
  646. {u'应充时间': u'%s分钟' % actualNeedTime},
  647. {u'充电时间': u'%s分钟' % usedTime},
  648. {u'剩余时间': u'%s分钟' % leftTime}
  649. ])})
  650. else:
  651. leftElec, needElec, usedElec, usedTime = self._analyze_elec_params(order)
  652. self.notifyDict.update({'title': make_title_from_dict([
  653. {u'设备编号': self.device['logicalCode']},
  654. {u'端口': order['port']},
  655. {u'结束原因': order['reason']},
  656. {u'充电时间': u'%s分钟' % usedTime},
  657. {u'订购电量': u'%s度' % needElec},
  658. {u'消耗电量': u'%s度' % usedElec},
  659. {u'剩余电量': u'%s度' % leftElec},
  660. ])})
  661. def _analyze_refund_info(self, order):
  662. if order['chrmt'] == 'TIME':
  663. actualNeedTime, leftTime, needTime, usedTime = self._analyze_time_params(order)
  664. refundTitleDictList = [
  665. {u'设备编号': self.device['logicalCode']},
  666. {u'端口': order['port']},
  667. {u'结束原因': order['reason']},
  668. {u'预定时间': u'%s分钟' % needTime},
  669. {u'应充时间': u'%s分钟' % actualNeedTime},
  670. {u'充电时间': u'%s分钟' % usedTime},
  671. {u'剩余时间': u'%s分钟' % leftTime},
  672. ]
  673. else:
  674. leftElec, needElec, usedElec, usedTime = self._analyze_elec_params(order)
  675. refundTitleDictList = [
  676. {u'设备编号': self.device['logicalCode']},
  677. {u'端口': order['port']},
  678. {u'结束原因': order['reason']},
  679. {u'充电时间': u'%s分钟' % usedTime},
  680. {u'订购电量': u'%s度' % needElec},
  681. {u'消耗电量': u'%s度' % usedElec},
  682. {u'剩余电量': u'%s度' % leftElec},
  683. ]
  684. self.refundDict.update({'title': make_title_from_dict(refundTitleDictList), })
  685. def end_for_monthly_package(self, order):
  686. """
  687. 包月卡的流程 单独走
  688. """
  689. self._init_common_info(order)
  690. usedTime = round(order['time'] / 60.0, 1)
  691. if usedTime <= self.refundProtection:
  692. monthlyPackage = MonthlyPackage.objects.filter(id=self.consumeRcd.monthlyPackageId).first()
  693. if not monthlyPackage:
  694. return
  695. monthlyPackage.rollback(self.consumeRcd)
  696. else:
  697. pass
  698. # 通知服务结束
  699. self.consumeRcd.update_service_info(self.consumeDict)
  700. notifyOpenId = self.consumeRcd.user.managerialOpenId
  701. self.notify_user(notifyOpenId, 'service_complete', **self.notifyDict)
  702. def end_of_auto_stop(self, order):
  703. self._init_common_info(order)
  704. usedFee = VirtualCoin(order['money'] * 0.01)
  705. usedTime = order['time'] / 60
  706. if usedTime <= self.refundProtection:
  707. usedFee = VirtualCoin(0)
  708. self.consumeDict.update({
  709. DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: usedFee.mongo_amount
  710. })
  711. user = MyUser.objects(openId=self.consumeRcd.openId, groupId=self.device['groupId']).first()
  712. if not user:
  713. return
  714. try:
  715. user.pay(usedFee)
  716. self.consumeRcd.update(coin=usedFee.mongo_amount, status='finished')
  717. except Exception:
  718. pass
  719. self.notifyDict.update(
  720. {'title': make_title_from_dict([
  721. {u'设备编号': self.device['logicalCode']},
  722. {u'端口': order['port']},
  723. {u'地址': self.device.group['address']},
  724. {u'结束原因': order['reason']},
  725. {u'充电时间': u'%s分钟' % round(usedTime, 1)},
  726. {u'本次服务费用': u'%s币' % usedFee},
  727. ])})
  728. # 通知服务结束
  729. notifyOpenId = user.managerialOpenId if user else ''
  730. self.notify_user(notifyOpenId, 'service_complete', **self.notifyDict)
  731. self.consumeRcd.update_service_info(self.consumeDict)
  732. logger.info('orderNo<{}> finished!!'.format(self.consumeRcd.orderNo))
  733. def end_for_vCard_start(self, order):
  734. try:
  735. vRcd = VCardConsumeRecord.objects.get(orderNo=order['id'])
  736. vCard = UserVirtualCard.objects.get(id=vRcd.cardId)
  737. except DoesNotExist, e:
  738. logger.info('can not find the vCard id = %s' % vRcd.cardId)
  739. return
  740. # 通知服务结束
  741. notifyOpenId = self.get_managerialOpenId_by_openId(vRcd.openId)
  742. self.notify_user(notifyOpenId, 'service_complete', **self.notifyDict)
  743. # 不需要退款,直接返回,不通知
  744. if self.device.is_auto_refund:
  745. if order['chrmt'] == 'TIME':
  746. vCard.refund_quota(vRcd, self.consumeDict['duration'], 0.0, 0.0)
  747. else:
  748. vCard.refund_quota(vRcd, 0.0, self.consumeDict['usedElec'], 0.0)
  749. def end_for_card_start(self, order):
  750. card = Card.objects.filter(agentId=self.device.owner.agentId, cardNo=order['card_no']).first()
  751. if card is None: # 离线卡没有绑定或者在线卡被解绑了
  752. return
  753. if self.consumeRcd.monthlyPackageId:
  754. return self.end_for_monthly_package(order)
  755. # 先通知
  756. notifyOpenId = card.managerialOpenId if card else ''
  757. self.notify_user(notifyOpenId, 'service_complete', **self.notifyDict)
  758. # 不需要退款,直接返回.在线卡需要退费,离线卡只登记使用记录就OK
  759. if self.backCoins > RMB(0) and card.cardType == 'ID':
  760. card = self.refund_money_for_card(self.backCoins, card.id)
  761. card.showBalance = card.balance
  762. card.save()
  763. self.consumeDict.update({'refundedMoney': self.backCoins.mongo_amount})
  764. self.notify_user(notifyOpenId, 'refund_coins', **self.refundDict)
  765. def end_for_app_start(self, order):
  766. self.notify_user(self.consumeRcd.user.managerialOpenId, 'service_complete', **self.notifyDict)
  767. # 如果需要退款,计算退款数据.
  768. if self.backCoins > RMB(0):
  769. openId = self.consumeRcd.user.openId
  770. lineInfo = {'openId': openId}
  771. refundRMB = RMB(0)
  772. refundCash = 'refundRMB_device_event' in self.device.owner.features
  773. if refundCash and self.consumeRcd.recharge_record_id:
  774. rechargeRcd = RechargeRecord.objects.filter(id=self.consumeRcd.recharge_record_id,
  775. openId=openId,
  776. devNo=self.device.devNo,
  777. isQuickPay=True,
  778. groupId=self.device.groupId).first()
  779. refundRMB = rechargeRcd.money * (self.backCoins.amount / self.consumeRcd.coin.amount)
  780. lineInfo.update({'rechargeRcdId': self.consumeRcd.recharge_record_id})
  781. self.refundDict.update({'backCount': u'金额:%s' % refundRMB})
  782. self.refund_net_pay(self.consumeRcd.user, lineInfo,
  783. refundRMB, self.backCoins, self.consumeDict, refundCash)
  784. self.notify_user(self.consumeRcd.user.managerialOpenId, 'refund_coins', **self.refundDict)
  785. @property
  786. def is_postpaid(self):
  787. return self.consumeRcd.package.get('name') == '充满自停' and self.consumeRcd.package.get('coins') == 0 and self.consumeRcd.package.get('price') == 0
  788. def start_by_monthly_package(self, card, order):
  789. monthlyPackage = card.monthlyPackage
  790. consumeRcd = self.record_consume_for_monthly_package(card, order)
  791. monthlyPackage.deduct(consumeRcd)
  792. self.create_progress_for_socket_order(consumeRcd, order)
  793. # 通知用户,已经扣费
  794. title = make_title_from_dict([
  795. {u'设备地址': u'{}'.format(self.device.group.address)},
  796. {u'设备编号': u'{}'.format(self.device['logicalCode'])},
  797. {u'实体卡': u'{}--No:{}'.format(card.cardName or card.nickName, card.cardNo)},
  798. {u'本次消费': u'包月卡抵扣'.format(0)},
  799. ])
  800. start_time_stamp = order.get('create_time')
  801. start_time = datetime.datetime.fromtimestamp(start_time_stamp)
  802. self.notify_user(
  803. card.managerialOpenId,
  804. 'dev_start',
  805. **{
  806. 'title': title,
  807. 'things': u'刷卡消费',
  808. 'remark': u'感谢您的支持!',
  809. 'time': start_time.strftime(Const.DATETIME_FMT)
  810. }
  811. )
  812. # 缓存切换
  813. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  814. lineInfo = ctrInfo.get(str(order['port']), {})
  815. if not lineInfo or lineInfo.get('status') == Const.DEV_WORK_STATUS_IDLE:
  816. lineInfo = {
  817. 'port': str(order['port']),
  818. 'status': Const.DEV_WORK_STATUS_WORKING,
  819. 'order_type': 'card_start',
  820. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  821. 'orderNo': consumeRcd.orderNo,
  822. }
  823. Device.update_port_control_cache(self.device.devNo, lineInfo)