bolai.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  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
  11. from apps.web.core.adapter.base import calc_signal_from_rssi
  12. from apps.web.device.models import Group, Device, GroupDict
  13. from apps.web.eventer import EventBuilder
  14. from apps.web.eventer.base import WorkEvent
  15. from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, \
  16. ConsumeRecord, Card, CardRechargeOrder, MyUser, CardConsumeRecord
  17. from apps.web.user.transaction_deprecated import refund_money
  18. logger = logging.getLogger(__name__)
  19. card_is_normal = 1
  20. card_not_in_db = 2
  21. card_is_forzen = 3
  22. card_has_not_order = 4 # IC卡适用
  23. card_less_balance = 5 # ID卡适用
  24. card_type_is_ic = 6 # IC卡不允许当做ID卡使用
  25. class builder(EventBuilder):
  26. def __getEvent__(self, device_event):
  27. return bolaiWorkEvent(self.deviceAdapter, device_event)
  28. class bolaiWorkEvent(WorkEvent):
  29. # 微付乐的板子:根据设备上报上来的订单,创建正在服务的信息
  30. def create_progress_for_card(self, dev, consumeRcd):
  31. try:
  32. progress = ServiceProgress.objects.filter(weifuleOrderNo = consumeRcd.orderNo).first()
  33. if progress:
  34. return
  35. consumeOrder = consumeRcd.servicedInfo
  36. new_service_progress = ServiceProgress(
  37. open_id = consumeRcd.openId,
  38. device_imei = consumeRcd.devNo,
  39. devTypeCode = dev['devType']['code'],
  40. port = consumeRcd.servicedInfo['portIndex'],
  41. attachParas = {},
  42. start_time = int(time.time()),
  43. finished_time = 24 * 60 * 60,
  44. consumeOrder = consumeOrder,
  45. weifuleOrderNo = consumeRcd.orderNo,
  46. expireAt = datetime.datetime.now() + datetime.timedelta(days = 91)
  47. )
  48. new_service_progress.save()
  49. except Exception as e:
  50. logger.exception(e)
  51. def consume_money_for_ID_card(self, agentId, cardNo, balance, money):
  52. card = Card.objects.get(agentId = agentId, cardNo = cardNo)
  53. if card.balance < money:
  54. card.balance = RMB(0)
  55. else:
  56. card.balance = (card.balance - money)
  57. try:
  58. card.save()
  59. except Exception as e:
  60. logger.exception(e)
  61. return card
  62. def update_balance_for_IC_card(self, card, balance):
  63. card.balance = balance
  64. try:
  65. card.save()
  66. except Exception, e:
  67. pass
  68. def new_card_consume_record(self, card, money, sid, servicedInfo):
  69. group = self.device.group # type: GroupDict
  70. address = group.address
  71. group_number = self.device.groupNumber
  72. now = datetime.datetime.now()
  73. orderNo = ConsumeRecord.make_no()
  74. new_record = {
  75. 'orderNo': orderNo,
  76. 'time': now.strftime("%Y-%m-%d %H:%M:%S"),
  77. 'dateTimeAdded': now,
  78. 'openId': card.openId,
  79. 'ownerId': self.device.ownerId,
  80. 'coin': money.mongo_amount,
  81. 'money': money.mongo_amount,
  82. 'devNo': self.device.devNo,
  83. 'logicalCode': self.device.logicalCode,
  84. 'groupId': self.device.groupId,
  85. 'address': address,
  86. 'groupNumber': group_number,
  87. 'groupName': group.groupName,
  88. 'devTypeCode': self.device.devTypeCode,
  89. 'devTypeName': self.device.devTypeName,
  90. 'isNormal': True,
  91. 'status': ConsumeRecord.Status.RUNNING,
  92. 'remarks': u'刷卡消费',
  93. 'errorDesc': '',
  94. 'sequanceNo': sid,
  95. 'desc': '',
  96. 'attachParas': {},
  97. 'servicedInfo': servicedInfo
  98. }
  99. order = ConsumeRecord(**new_record)
  100. order.save()
  101. # 刷卡消费也记录一条数据
  102. new_card_record = {
  103. 'orderNo': orderNo,
  104. 'openId': card.openId,
  105. 'cardId': str(card.id),
  106. 'money': money.mongo_amount,
  107. 'balance': card.balance.mongo_amount,
  108. 'devNo': self.device.devNo,
  109. 'devType': self.device.devTypeName,
  110. 'logicalCode': self.device.logicalCode,
  111. 'groupId': self.device.groupId,
  112. 'address': address,
  113. 'groupNumber': group_number,
  114. 'groupName': group.groupName,
  115. 'result': 'success',
  116. 'remarks': u'刷卡消费',
  117. 'sid': sid,
  118. 'dateTimeAdded': datetime.datetime.now(),
  119. 'desc': '',
  120. 'servicedInfo': servicedInfo,
  121. 'linkedConsumeRcdOrderNo': str(order.orderNo)
  122. }
  123. card_order = CardConsumeRecord(**new_card_record)
  124. card_order.save()
  125. return order, card_order
  126. def __translate_reason(self, cause):
  127. if cause == 0:
  128. return u'结束充电。'
  129. elif cause == 1:
  130. return u'正在充电的时候,结束了,可能是用户拔掉充电器,或者插座脱落,或者没有接入充电器'
  131. elif cause == 2:
  132. return u'充满自停。'
  133. elif cause == 3:
  134. return u'金额已经用完。'
  135. elif cause == 4:
  136. return u'平台下发停止充电'
  137. return u'充电结束。'
  138. def response_id_card(self, msgDict):
  139. data = msgDict['data']
  140. rawCardNo = data['card_no']
  141. cardNo = str(int(data['card_no'], 16))
  142. nodeDev = self.device
  143. Card.record_dev_card_no(nodeDev['devNo'], cardNo)
  144. card = self.find_card_by_card_no(cardNo)
  145. # 如果没有卡,直接返回
  146. if card is None:
  147. # cardNo,nodeIndex,portIndex,balance
  148. return self.deviceAdapter.response_card_balance(rawCardNo, data['node_index'], data['port_index'], 0)
  149. elif card.frozen:
  150. return self.deviceAdapter.response_card_balance(rawCardNo, data['node_index'], data['port_index'], 0)
  151. if card.cardType == 'IC': # 如果以前是离线卡,只能用于离线卡,需要提醒用户
  152. return self.deviceAdapter.response_card_balance(rawCardNo, data['node_index'], data['port_index'], 0)
  153. card = self.update_card_dealer_and_type(cardNo, 'ID')
  154. #: 首先检查订单,并进行充值
  155. #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来
  156. # 防止重复报文过来,导致重复充值
  157. with memcache_lock(key = '%s-%s-finished' % (nodeDev['devNo'], cardNo), value = '1', expire = 120) as acquired:
  158. if acquired:
  159. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  160. if card_recharge_order:
  161. self.recharge_id_card(card = card, rechargeType = 'append', order = card_recharge_order)
  162. card.reload()
  163. self.deviceAdapter.response_card_balance(rawCardNo, data['node_index'], data['port_index'], card.balance)
  164. # 确定发送成功了,然后再保存到数据库中
  165. card.save()
  166. def analyse_need_from_package(self, order):
  167. needKind, needValue, unit = 'needElec', 0, u'度'
  168. if order['chrmt'] == 'TIME':
  169. needKind = 'needTime'
  170. needValue = order['amount_time'] / 60
  171. unit = u'分钟'
  172. else:
  173. needValue = order['amount_elec'] / 1000000.0
  174. return needKind, needValue, unit
  175. # 根据推送的事件,更新端口状态(其实可以不需要处理,既然收到了,就顺手刷新下吧)
  176. def update_port_from_event(self, gatewayDevNo, nodeIndex, portIndex, portInfo):
  177. # 先刷网关的
  178. nodeIndex = str(nodeIndex)
  179. portIndex = str(portIndex)
  180. value = {
  181. 'ampere': portInfo['current'] / 1000.0,
  182. 'power': portInfo['power'],
  183. 'voltage': portInfo['voltage'],
  184. 'elec': portInfo['energy_consumed']*0.001,
  185. 'spendTime': portInfo['time_consumed'],
  186. 'sequanceNo': portInfo['transaction_id'],
  187. 'online': portInfo['online'],
  188. 'status': Const.DEV_WORK_STATUS_WORKING if portInfo['charge_status'] == 1 else Const.DEV_WORK_STATUS_IDLE
  189. }
  190. info = Device.get_dev_control_cache(self.device.devNo)
  191. info.update({str(portIndex): value})
  192. Device.update_dev_control_cache(self.device.devNo, info)
  193. def charge_end_by_time(self, data):
  194. reason = self.__translate_reason(data['data']['charge_status'])
  195. orderNo = data['data']['transaction_id']
  196. nodeDev = self.device
  197. devNo = nodeDev['devNo']
  198. consumeRcd = ConsumeRecord.objects.filter(sequanceNo = orderNo).first()
  199. if not consumeRcd: # 投币的不会生成订单
  200. return
  201. port = consumeRcd.attachParas['chargeIndex']
  202. progress = ServiceProgress.objects.filter(weifuleOrderNo = consumeRcd.orderNo).first() # type: ServiceProgress
  203. # if progress is None or progress.status == 'finished':
  204. # return
  205. progress.status = 'finished'
  206. progress.isFinished = True
  207. progress.expireAt = datetime.datetime.now()
  208. progress.save()
  209. try:
  210. group = Group.get_group(nodeDev['groupId'])
  211. servicedInfo = consumeRcd.servicedInfo
  212. billingType = servicedInfo['billingType']
  213. usedTime = data['data']['time_consumed']
  214. usedElec = data['data']['energy_consumed'] * 0.001
  215. consumeDict = {
  216. 'reason': reason,
  217. 'chargeIndex': port,
  218. 'duration': usedTime,
  219. 'elec': usedElec
  220. }
  221. consumeDict.update(servicedInfo)
  222. notifyDict = {
  223. 'service': u'充电服务完成',
  224. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  225. 'remark': u'谢谢您的支持'
  226. }
  227. refundDict = {
  228. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  229. }
  230. coins = consumeRcd.coin
  231. if billingType == 'time': # 按照时间计费
  232. needTime = servicedInfo['needTime']
  233. leftTime = needTime - usedTime if needTime > usedTime else 0
  234. leftTimeStr = leftTime
  235. consumeDict.update({
  236. 'needTime': needTime,
  237. 'leftTime': leftTimeStr,
  238. })
  239. titleDictList = [
  240. {u'设备编号': nodeDev['logicalCode']},
  241. {u'端口': 'A' if port == 0 else 'B'},
  242. {u'地址': group['address']},
  243. {u'结束原因': reason},
  244. {u'订购时间': u'%s分钟' % needTime},
  245. {u'充电时间': u'%s分钟' % usedTime},
  246. {u'剩余时间': u'%s分钟' % leftTimeStr}
  247. ]
  248. notifyDict.update(
  249. {
  250. 'title': make_title_from_dict(titleDictList)
  251. }
  252. )
  253. backCoins = coins * (float(leftTime) / float(needTime))
  254. titleDictList = [
  255. {u'设备编号': nodeDev['logicalCode']},
  256. {u'端口': 'A' if port == 0 else 'B'},
  257. {u'付款': u'%s元' % coins},
  258. {u'预定时间': u'%s分钟' % needTime},
  259. {u'充电时间': u'%s分钟' % usedTime},
  260. {u'剩余时间': u'%s分钟' % leftTimeStr},
  261. ]
  262. refundDict.update(
  263. {
  264. 'title': make_title_from_dict(titleDictList),
  265. 'backCount': u'金币:%s' % backCoins
  266. }
  267. )
  268. else: # 按电量付费的
  269. needElec = servicedInfo['needElec']
  270. leftElec = needElec - usedElec if needElec > usedElec else 0.0
  271. consumeDict.update({
  272. 'needElec': needElec,
  273. 'leftElec': leftElec
  274. })
  275. titleDictList = [
  276. {u'设备编号': nodeDev['logicalCode']},
  277. {u'端口': 'A' if port == 0 else 'B'},
  278. {u'结束原因': reason},
  279. {u'订购电量': u'%s度' % needElec},
  280. {u'消耗电量': u'%s度' % usedElec},
  281. {u'剩余电量': u'%s分钟' % leftElec},
  282. ]
  283. notifyDict.update(
  284. {
  285. 'title': make_title_from_dict(titleDictList)
  286. }
  287. )
  288. backCoins = coins * (float(leftElec) / float(needElec))
  289. titleDictList = [
  290. {u'设备编号': nodeDev['logicalCode']},
  291. {u'端口': 'A' if port == 0 else 'B'},
  292. {u'结束原因': reason},
  293. {u'订购电量': u'%s度' % needElec},
  294. {u'消耗电量': u'%s度' % usedElec},
  295. {u'剩余电量': u'%s度' % leftElec},
  296. ]
  297. refundDict.update(
  298. {
  299. 'title': make_title_from_dict(titleDictList),
  300. 'backCount': u'金币:%s' % backCoins
  301. }
  302. )
  303. if u'虚拟卡' in consumeRcd.remarks:
  304. # 退额度
  305. try:
  306. vRcd = VCardConsumeRecord.objects.get(orderNo = consumeRcd.orderNo)
  307. vCard = UserVirtualCard.objects.get(id = vRcd.cardId)
  308. except DoesNotExist, e:
  309. logger.info('can not find the vCard id = %s' % vRcd.cardId)
  310. return
  311. # 通知服务结束
  312. notifyOpenId = self.get_managerialOpenId_by_openId(vRcd.openId) if vCard else ''
  313. self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
  314. # 不需要退款,直接返回,不通知
  315. if self.device.is_auto_refund:
  316. if billingType == 'time':
  317. vCard.refund_quota(vRcd, usedTime, 0.0, backCoins.mongo_amount)
  318. else:
  319. vCard.refund_quota(vRcd, 0.0, usedElec, backCoins.mongo_amount)
  320. else: # 扫码的
  321. user = MyUser.objects(openId = consumeRcd.openId, groupId = nodeDev['groupId']).first()
  322. if not user:
  323. return
  324. # 通知服务结束
  325. notifyOpenId = user.managerialOpenId if user else ''
  326. self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
  327. # 如果需要退款,计算退款数据.
  328. if self.device.is_auto_refund:
  329. consumeDict.update({'refundedMoney': str(backCoins)})
  330. refund_money(nodeDev, backCoins, consumeRcd.openId)
  331. self.notify_user(notifyOpenId, 'refund_coins', **refundDict)
  332. ServiceProgress.update_progress_and_consume_rcd(nodeDev['ownerId'], {'weifuleOrderNo': consumeRcd.orderNo},
  333. consumeDict)
  334. except Exception, e:
  335. logger.exception('some exception happed,devNo=%s,e=%s' % (devNo, e))
  336. finally:
  337. self.deviceAdapter.get_port_status_from_dev()
  338. # 功率计费模式下,根据返回的数据,计算消耗的钱
  339. def calc_spend_money(self,data):
  340. settle_power = data['data']['settle_power']
  341. usedTime = data['data']['time_consumed']
  342. config_list = self.device.my_obj.otherConf.get('config_list', [])
  343. powerList = []
  344. configDict = {}
  345. for _ in config_list:
  346. configDict[_['power']] = _
  347. powerList.append(_['power'])
  348. powerList.sort()
  349. for power in powerList:
  350. if settle_power < power:
  351. break
  352. else:
  353. continue
  354. pricePower = power
  355. priceConfig = configDict[pricePower]
  356. spendMoney = VirtualCoin(usedTime/priceConfig['time']*100*0.01)
  357. return spendMoney
  358. def charge_end_by_power(self, data):
  359. reason = self.__translate_reason(data['data']['charge_status'])
  360. orderNo = data['data']['transaction_id']
  361. nodeDev = self.device
  362. devNo = nodeDev['devNo']
  363. consumeRcd = ConsumeRecord.objects.filter(sequanceNo = orderNo).first()
  364. if not consumeRcd: # 投币的不会生成订单
  365. return
  366. port = consumeRcd.attachParas['chargeIndex']
  367. progress = ServiceProgress.objects.filter(weifuleOrderNo = consumeRcd.orderNo).first() # type: ServiceProgress
  368. if progress is None or progress.status == 'finished':
  369. return
  370. progress.status = 'finished'
  371. progress.isFinished = True
  372. progress.expireAt = datetime.datetime.now()
  373. progress.save()
  374. try:
  375. group = Group.get_group(nodeDev['groupId'])
  376. spendMoney = self.calc_spend_money(data)
  377. usedTime = data['data']['time_consumed']
  378. usedElec = data['data']['energy_consumed'] * 0.001
  379. consumeDict = {
  380. 'reason': reason,
  381. 'chargeIndex': port,
  382. 'spendMoney': str(spendMoney),
  383. 'power': data['data']['settle_power'],
  384. 'usedTime': usedTime,
  385. 'usedElec': usedElec,
  386. 'power': data['data']['power'],
  387. 'current': data['data']['current']
  388. }
  389. consumeDict.update(consumeRcd.servicedInfo)
  390. notifyDict = {
  391. 'service': u'充电服务完成',
  392. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  393. 'remark': u'谢谢您的支持'
  394. }
  395. refundDict = {
  396. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  397. }
  398. coins = consumeRcd.coin
  399. backCoins = coins - spendMoney if coins > spendMoney else VirtualCoin(0.0)
  400. usedTime = data['data']['time_consumed']
  401. consumeDict.update({
  402. 'duration': usedTime,
  403. })
  404. titleDictList = [
  405. {u'设备编号': nodeDev['logicalCode']},
  406. {u'端口': 'A' if port == 0 else 'B'},
  407. {u'地址': group['address']},
  408. {u'结束原因': reason},
  409. {u'结算功率': u'%s瓦' % data['data']['settle_power']},
  410. {u'使用时间': u'%s分钟' % usedTime}
  411. ]
  412. notifyDict.update(
  413. {
  414. 'title': make_title_from_dict(titleDictList)
  415. }
  416. )
  417. refundDict.update(
  418. {
  419. 'title': make_title_from_dict(titleDictList),
  420. 'backCount': u'金币:%s' % backCoins
  421. }
  422. )
  423. if u'虚拟卡' in consumeRcd.remarks:
  424. # 退额度
  425. try:
  426. vRcd = VCardConsumeRecord.objects.get(orderNo = consumeRcd.orderNo)
  427. vCard = UserVirtualCard.objects.get(id = vRcd.cardId)
  428. except DoesNotExist, e:
  429. logger.info('can not find the vCard id = %s' % vRcd.cardId)
  430. return
  431. # 通知服务结束
  432. notifyOpenId = self.get_managerialOpenId_by_openId(vRcd.openId) if vCard else ''
  433. self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
  434. # 不需要退款,直接返回,不通知
  435. if self.device.is_auto_refund:
  436. vCard.refund_quota(vRcd, 0.0, 0.0, backCoins.mongo_amount)
  437. else: # 扫码的
  438. user = MyUser.objects(openId = consumeRcd.openId, groupId = nodeDev['groupId']).first()
  439. if not user:
  440. return
  441. # 通知服务结束
  442. notifyOpenId = user.managerialOpenId if user else ''
  443. self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
  444. # 如果需要退款,计算退款数据.
  445. if self.device.is_auto_refund:
  446. consumeDict.update({'refundedMoney': str(backCoins)})
  447. refund_money(nodeDev, backCoins, consumeRcd.openId)
  448. self.notify_user(notifyOpenId, 'refund_coins', **refundDict)
  449. ServiceProgress.update_progress_and_consume_rcd(nodeDev['ownerId'], {'weifuleOrderNo': consumeRcd.orderNo},
  450. consumeDict)
  451. except Exception, e:
  452. logger.exception('some exception happed,devNo=%s,e=%s' % (devNo, e))
  453. finally:
  454. self.deviceAdapter.get_port_status_from_dev()
  455. def charge_end_by_card(self, data):
  456. reason = self.__translate_reason(data['data']['charge_status'])
  457. sequanceNo = data['data']['transaction_id']
  458. devNo = self.device.devNo
  459. order = ConsumeRecord.objects.filter(sequanceNo = sequanceNo).first()
  460. if not order: # 投币的不会生成订单
  461. return
  462. progress = ServiceProgress.objects.filter(weifuleOrderNo = order.orderNo).first() # type: ServiceProgress
  463. if progress is None or progress.status == 'finished':
  464. return
  465. progress.status = 'finished'
  466. progress.isFinished = True
  467. progress.expireAt = datetime.datetime.now()
  468. progress.save()
  469. servicedInfo = order.servicedInfo
  470. port = servicedInfo['portIndex']
  471. try:
  472. group = Group.get_group(self.device.groupId)
  473. servicedInfo = order.servicedInfo
  474. billingType = servicedInfo['billingType']
  475. usedTime = data['data']['time_consumed']
  476. usedElec = data['data']['energy_consumed'] * 0.001
  477. consumeDict = {
  478. 'reason': reason,
  479. 'chargeIndex': port,
  480. 'duration': usedTime,
  481. 'elec': usedElec
  482. }
  483. consumeDict.update(servicedInfo)
  484. notifyDict = {
  485. 'service': u'充电服务完成',
  486. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  487. 'remark': u'谢谢您的支持'
  488. }
  489. refundDict = {
  490. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  491. }
  492. coins = order.coin
  493. if billingType == 'time': # 按照时间计费
  494. needTime = servicedInfo['needTime']
  495. leftTime = needTime - usedTime if needTime > usedTime else 0
  496. leftTimeStr = leftTime
  497. consumeDict.update({
  498. 'needTime': needTime,
  499. 'leftTime': leftTimeStr,
  500. })
  501. titleDictList = [
  502. {u'设备编号': self.device.logicalCode},
  503. {u'端口': 'A' if port == 0 else 'B'},
  504. {u'地址': group['address']},
  505. {u'结束原因': reason},
  506. {u'订购时间': u'%s分钟' % needTime},
  507. {u'充电时间': u'%s分钟' % usedTime},
  508. {u'剩余时间': u'%s分钟' % leftTimeStr}
  509. ]
  510. notifyDict.update(
  511. {
  512. 'title': make_title_from_dict(titleDictList)
  513. }
  514. )
  515. backCoins = coins * (float(leftTime) / float(needTime))
  516. titleDictList = [
  517. {u'设备编号': self.device.logicalCode},
  518. {u'端口': 'A' if port == 0 else 'B'},
  519. {u'付款': u'%s元' % coins},
  520. {u'预定时间': u'%s分钟' % needTime},
  521. {u'充电时间': u'%s分钟' % usedTime},
  522. {u'剩余时间': u'%s分钟' % leftTimeStr},
  523. ]
  524. refundDict.update(
  525. {
  526. 'title': make_title_from_dict(titleDictList),
  527. 'backCount': u'金币:%s' % backCoins
  528. }
  529. )
  530. else: # 按电量付费的
  531. needElec = servicedInfo['needElec']
  532. leftElec = needElec - usedElec if needElec > usedElec else 0.0
  533. consumeDict.update({
  534. 'needElec': needElec,
  535. 'leftElec': leftElec
  536. })
  537. titleDictList = [
  538. {u'设备编号': self.device.logicalCode},
  539. {u'端口': 'A' if port == 0 else 'B'},
  540. {u'结束原因': reason},
  541. {u'订购电量': u'%s度' % needElec},
  542. {u'消耗电量': u'%s度' % usedElec},
  543. {u'剩余电量': u'%s分钟' % leftElec},
  544. ]
  545. notifyDict.update(
  546. {
  547. 'title': make_title_from_dict(titleDictList)
  548. }
  549. )
  550. backCoins = coins * (float(leftElec) / float(needElec))
  551. titleDictList = [
  552. {u'设备编号': self.device.logicalCode},
  553. {u'端口': 'A' if port == 0 else 'B'},
  554. {u'结束原因': reason},
  555. {u'订购电量': u'%s度' % needElec},
  556. {u'消耗电量': u'%s度' % usedElec},
  557. {u'剩余电量': u'%s度' % leftElec},
  558. ]
  559. refundDict.update(
  560. {
  561. 'title': make_title_from_dict(titleDictList),
  562. 'backCount': u'金币:%s' % backCoins
  563. }
  564. )
  565. dealer = self.device.owner
  566. card = Card.objects.filter(agentId = dealer.agentId, cardNo = str(servicedInfo['cardNo'])).first()
  567. if card is None: # 离线卡没有绑定或者在线卡被解绑了
  568. return
  569. # 先通知
  570. notifyOpenId = card.managerialOpenId if card else ''
  571. self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
  572. # 不需要退款,直接返回.在线卡需要退费,离线卡只登记使用记录就OK
  573. if self.device.is_auto_refund and card.cardType == 'ID':
  574. card = self.refund_money_for_card(RMB(backCoins), card.id)
  575. card.showBalance = card.balance
  576. card.save()
  577. consumeDict.update({'refundedMoney': str(backCoins)})
  578. self.notify_user(notifyOpenId, 'refund_coins', **refundDict)
  579. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId, {'weifuleOrderNo': order.orderNo},
  580. consumeDict)
  581. except Exception, e:
  582. logger.exception('some exception happed,devNo=%s,e=%s' % (devNo, e))
  583. finally:
  584. self.deviceAdapter.get_port_status_from_dev()
  585. def start_charge_by_card(self, data):
  586. sequanceNo = data['data']['transaction_id']
  587. order = ConsumeRecord.objects.filter(sequanceNo = sequanceNo).first()
  588. if order:
  589. logger.debug('start event of device<devNo={}> has been done. sequanceNo = {}'.format(
  590. self.device.devNo, sequanceNo))
  591. return
  592. cardNo = str(int(data['data']['card']['no'], 16))
  593. nodeIndex = data['data']['node_index']
  594. portIndex = data['data']['port_index']
  595. card = self.find_card_by_card_no(cardNo)
  596. if not card:
  597. return
  598. # 获取卡充电相关配置
  599. otherConf = self.device.my_obj.otherConf
  600. billingType = otherConf.get('billingType', 1) # 0 :电量 1:时间 2:功率
  601. config_list = otherConf.get('config_list', [])
  602. onceCard = otherConf.get('onceCard', 100)
  603. cardTime = otherConf.get('cardTime', 180)
  604. cardElec = otherConf.get('cardElec', 1)
  605. # 检查是否余额够
  606. if card.balance < RMB(onceCard*0.01):
  607. return
  608. jsonPara = {
  609. # 'gateway_id': data['gateway_id'],
  610. 'node_index': nodeIndex,
  611. 'port_index': portIndex,
  612. 'transaction_id': sequanceNo,
  613. 'switch_state': 1,
  614. 'timeout': 15
  615. }
  616. servicedInfo = {}
  617. if billingType == 1:
  618. jsonPara.update({
  619. 'charge_type': 1,
  620. 'charge_time': onceCard * cardTime * 0.01,
  621. 'charge_energy': 0
  622. })
  623. servicedInfo.update(
  624. {'billingType': 'time', 'cardNo': cardNo, 'nodeIndex': nodeIndex, 'portIndex': portIndex,
  625. 'needTime': cardTime * onceCard * 0.01})
  626. elif billingType == 0:
  627. jsonPara.update({
  628. 'charge_type': 2,
  629. 'charge_energy': onceCard * cardElec * 0.01,
  630. 'charge_time': 0
  631. })
  632. servicedInfo.update(
  633. {'billingType': 'elec', 'cardNo': cardNo, 'nodeIndex': nodeIndex, 'portIndex': portIndex,
  634. 'needElec': cardElec * onceCard * 0.01})
  635. else: # 按照功率充电
  636. jsonPara.update({
  637. 'charge_type': 3,
  638. 'charge_power': {'money': onceCard, 'config_list': config_list}
  639. })
  640. servicedInfo.update(
  641. {'billingType': 'power', 'cardNo': cardNo, 'nodeIndex': nodeIndex, 'portIndex': portIndex,
  642. 'configList': config_list})
  643. devInfo = self.deviceAdapter.send_request('cmd/control-nfc-charge', jsonPara)
  644. if devInfo['data']['code'] != 0:
  645. logger.info('start device by card failed,devNo=%s', self.device.devNo)
  646. return
  647. order, _ = self.new_card_consume_record(card = card,
  648. money = RMB(onceCard * 0.01),
  649. sid = sequanceNo,
  650. servicedInfo = servicedInfo)
  651. self.create_progress_for_card(self.device, order)
  652. self.consume_money_for_card(card, RMB(onceCard * 0.01))
  653. def do_gateway(self, data):
  654. if data['type'] == 'EVENT_GATEWAY_HEARTBEAT':
  655. logger.info('receive EVENT_GATEWAY_HEARTBEAT')
  656. Device.update_online_cache(self.device.devNo, True, data['data']['rssi'],(long(time.time() * 1000) - 600000 ))
  657. # 如果是独立机的网关心跳,里面有插座的状态
  658. if 'port_0' in data['data']:
  659. self.update_port_from_event(data['gateway_id'], 0, 0, data['data']['port_0'])
  660. if 'port_1' in data['data']:
  661. self.update_port_from_event(data['gateway_id'], 0, 1, data['data']['port_1'])
  662. def do_node(self, data):
  663. if data['type'] == 'EVENT_PLUG_HEARTBEAT': # 
  664. logger.info('receive EVENT_PLUG_HEARTBEAT')
  665. self.update_port_from_event(data['gateway_id'], data['data']['node_index'], data['data']['port_index'],
  666. data['data'])
  667. Device.update_online_cache(self.device.devNo, True)
  668. elif data['type'] == 'EVENT_PLUG_MP_HEARTBEAT':# 插座心跳
  669. logger.info('receive EVENT_PLUG_MP_HEARTBEAT')
  670. self.update_port_from_event(data['gateway_id'], data['data']['node_index'], 0, data['data']['port_0'])
  671. self.update_port_from_event(data['gateway_id'], data['data']['node_index'], 1, data['data']['port_1'])
  672. online = bool(data['data']['port_0']['online'] | data['data']['port_0']['online'])
  673. signal = calc_signal_from_rssi(data['data']['rssi'])# 将插座和网关的信号值,转为0-32的信号强弱数据
  674. if online:
  675. Device.update_online_cache(self.device.devNo, True,signal,(long(time.time() * 1000) + 3600000 ))
  676. else:
  677. Device.update_online_cache(self.device.devNo, False,0)
  678. Device.update_field(dev_no = self.device.devNo, update = True, rssi = data['data']['rssi'])
  679. elif data['type'] == 'EVENT_CHARGE_FINISHED':
  680. self.charge_end_by_time(data)
  681. elif data['type'] == 'EVENT_CHARGE_FINISHED_3':
  682. self.charge_end_by_power(data)
  683. elif data['type'] == 'EVENT_NFC_BALANCE_QUERY': # 刷卡查询余额
  684. self.response_id_card(data)
  685. elif data['type'] == 'EVENT_NFC_CHARGE_STARTED': # 开始刷卡,然后启动刷卡
  686. self.start_charge_by_card(data)
  687. elif data['type'] == 'EVENT_NFC_CHARGE_FINISHED':
  688. self.charge_end_by_card(data)
  689. def do(self, **args):
  690. data = self.event_data
  691. if data['nodeType'] == 'node':
  692. self.do_node(data)
  693. else:
  694. self.do_gateway(data)