gaoborui.py 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import random
  6. import time
  7. from arrow import Arrow
  8. from django.conf import settings
  9. from typing import TYPE_CHECKING, List
  10. from apilib.monetary import sum_rmb, RMB, VirtualCoin, Ratio
  11. from apilib.utils_datetime import to_datetime
  12. from apps.web.south_intf.liangxi_fire import LiangXiXiaoFang
  13. from apps.web.south_intf.yuhuan_fire import YuhuanNorther
  14. from apps.web.common.models import District
  15. from apps.web.constant import Const, FAULT_CODE, FAULT_LEVEL, APP_TYPE, DEALER_CONSUMPTION_AGG_KIND
  16. from apps.web.core.helpers import ActionDeviceBuilder
  17. from apps.web.core.accounting import Accounting
  18. from apps.web.core.device_define.dianchuan import FINISHED_CHARGE_REASON_MAP
  19. from apps.web.dealer.models import Dealer
  20. from apps.web.device.models import PortReport, OfflineCoinStatistics, Part, Group, Device
  21. from apps.web.eventer.base import FaultEvent, WorkEvent, ComNetPayAckEvent, IcStartAckEvent, \
  22. AckEventProcessorIntf, IcRechargeAckEvent, CardRefundAckEvent
  23. from apps.web.eventer import EventBuilder
  24. from apps.web.helpers import get_wechat_auth_bridge
  25. from apps.web.south_intf.platform import notify_event_to_north, notify_event_to_north_v2
  26. from apps.web.south_intf.zhejiang_fire import send_event_to_zhejiang
  27. from apps.web.user.models import VCardConsumeRecord, ServiceProgress, UserVirtualCard, CardRechargeOrder, MyUser, \
  28. ConsumeRecord, RechargeRecord
  29. if TYPE_CHECKING:
  30. from apps.web.user.models import Card
  31. from apps.web.device.models import GroupDict
  32. from apps.web.device.models import DeviceDict
  33. logger = logging.getLogger(__name__)
  34. class builder(EventBuilder):
  35. def __getEvent__(self, device_event):
  36. # 订单机制事件
  37. if 'order_id' in device_event:
  38. if device_event['order_type'] == 'com_start':
  39. return MyComNetPayAckEvent(self.deviceAdapter, device_event)
  40. if device_event['order_type'] == 'ic_recharge':
  41. return MyIcRechargeAckEvent(self.deviceAdapter, device_event)
  42. if device_event['order_type'] == 'ic_start':
  43. return MyIcStartAckEvent(self.deviceAdapter, device_event)
  44. if device_event['order_type'] == 'card_refund':
  45. return MyCardRefundAckEvent(self.deviceAdapter, device_event)
  46. else:
  47. if 'data' not in device_event:
  48. return None
  49. # 100228 互感器事件处理
  50. if 'type' in device_event:
  51. if device_event['type'] == 'alert':
  52. return InteroperatorAlertEvent(self.deviceAdapter, device_event)
  53. if device_event['type'] == 'report':
  54. return InteroperatorReport(self.deviceAdapter, device_event)
  55. else:
  56. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  57. if event_data is None or 'cmdCode' not in event_data:
  58. return None
  59. if 'duration' in device_event:
  60. event_data.update({'duration': device_event['duration']})
  61. if 'elec' in device_event:
  62. event_data.update({'elec': device_event['elec']})
  63. if 'v' in device_event:
  64. event_data.update({'v': device_event['v']})
  65. if event_data.get('cmdCode') in ['03', '05', '11', '12', '17', '22']:
  66. return ChargingZHIXIA2WorkEvent(self.deviceAdapter, event_data)
  67. if event_data.get('cmdCode') == '0D':
  68. return ZHIXIA2FaultEvent(self.deviceAdapter, event_data)
  69. if event_data.get('cmdCode') == '35' or event_data.get('cmdCode') == '41':
  70. return ZHIXIA2InductorEvent(self.deviceAdapter, event_data)
  71. return None
  72. class ZHIXIA2FaultEvent(FaultEvent):
  73. LX_FAULE_CODE_MAP = {
  74. "01": "07",
  75. "02": "03",
  76. "03": "05"
  77. }
  78. def do_norther(self):
  79. """
  80. 上报其他平台的,都在这个地方处理 可迁移至异步任务
  81. :return:
  82. """
  83. # 玉环的消防对接
  84. YuhuanNorther.send_dev_event(self.device, self.event_data['FaultCode'], self.event_data['port'])
  85. # 梁溪消防局的对接
  86. faultContent = self.event_data["statusInfo"]
  87. faultCode = self.LX_FAULE_CODE_MAP.get(self.event_data["FaultCode"], "")
  88. districtInfo = District.get_district(self.device.group["districtId"])
  89. self.device.update({"districtInfo": districtInfo, "groupAddr": self.device.group["address"]})
  90. LiangXiXiaoFang.send_to_xf_fault(self.device, faultCode, faultContent, self.event_data["port"])
  91. def do(self, **args):
  92. # 将告警的消息打入相应的缓存
  93. port = self.event_data["port"]
  94. # 0 表示整机
  95. if port == 0xFF:
  96. part = str(0)
  97. else:
  98. part = str(port)
  99. warningData = {
  100. "warningStatus": 2,
  101. "warningDesc": self.event_data["statusInfo"],
  102. "warningTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  103. "warningUart": self.event_data["uart"]
  104. }
  105. Device.update_dev_warning_cache(self.device.devNo, {part: warningData})
  106. super(ZHIXIA2FaultEvent, self).do()
  107. class ChargingZHIXIA2WorkEvent(WorkEvent):
  108. def __parse_device_finished_data(self, event_data):
  109. duration = event_data.get('duration', -1)
  110. if duration != -1:
  111. if 'v' in event_data:
  112. duration = ((duration + 59) / 60)
  113. elec = event_data.get('elec', -1)
  114. if elec != -1:
  115. if 'v' in event_data:
  116. elec = round(elec / (10000.0 * 3600.0), 3)
  117. else:
  118. elec = round(elec / 3600.0, 3)
  119. logger.debug('device duration is {}, device elec is {}'.format(duration, elec))
  120. return duration, elec
  121. def do(self, **args):
  122. logger.info('zhixiakeji2 charging event detected, devNo=%s,info=%s' % (self.device.devNo, self.event_data))
  123. devNo = self.device.devNo
  124. if self.event_data['cmdCode'] == '03': # 电川的无法记录投币的端口数据
  125. Accounting.recordOfflineCoin(device=self.device,
  126. report_ts=int(time.time()),
  127. coins=int(self.event_data['coins']),
  128. port=self.event_data.get('port', None))
  129. if self.device.ownerId is not None and self.device.ownerId != '':
  130. dealer = Dealer.objects(id = self.device.ownerId).first()
  131. if dealer is not None and 'show_device_offline_coins' in dealer.features:
  132. OfflineCoinStatistics.recordCoinEvent(
  133. self.device['logicalCode'],
  134. self.device.devNo,
  135. int(self.event_data.get('coins', 1)),
  136. self.device['groupId']
  137. )
  138. else:
  139. logger.error('undefined dealer id=%s' % self.device.ownerId)
  140. # 如果是投币,直接把端口状态刷新下
  141. try:
  142. self.deviceAdapter.get_port_status_from_dev()
  143. except Exception, e:
  144. logger.info('some err=%s' % e)
  145. YuhuanNorther.send_dev_status(self.device, self.event_data['port'], 1)
  146. elif self.event_data['cmdCode'] == '22': # ID在线卡刷卡查询余额
  147. cardNo = self.event_data['cardNo']
  148. fee = RMB(self.event_data['fee'])
  149. cardType = self.event_data['cardType']
  150. card = self.update_card_dealer_and_type(cardNo)
  151. # 首先检查订单,并进行充值
  152. # 不存在卡的情况下 直接
  153. if not card:
  154. res = "03"
  155. elif not card.openId:
  156. res = "03"
  157. elif card.frozen:
  158. res = "04"
  159. # 有绑定的卡 并且卡没被冻结的情况下
  160. else:
  161. # 刷新卡的金额
  162. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  163. result = self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order)
  164. card.reload()
  165. logger.info('cardNo=%s,openId=%s,result=%s,fee=%s, info=%s' % (cardNo, card.openId, result, fee, self.event_data))
  166. res = "01" if result["balance"] >= fee else "02"
  167. balance = RMB(0) if not card else card.balance
  168. try:
  169. logger.info("card is <{}> fee is <{}> response res is <{}>".format(cardNo, fee, res))
  170. result = self.deviceAdapter.response_card_status(cardNo, balance, res)
  171. except Exception, e:
  172. logger.info('resp back error=%s' % e)
  173. return
  174. # 设备回复扣款成功,服务器就需要正式扣掉钱
  175. if result['status'] == '01' and res == '01':
  176. virtual_card = card.bound_virtual_card
  177. if virtual_card is not None:
  178. group = Group.get_group(self.device['groupId'])
  179. VCardConsumeRecord(
  180. orderNo = VCardConsumeRecord.make_no(self.device.logicalCode),
  181. openId = card.openId,
  182. cardId = str(virtual_card.id),
  183. dealerId = card.dealerId,
  184. devNo = self.device.devNo,
  185. devTypeCode = self.device.devTypeCode,
  186. devTypeName = self.device.devTypeName,
  187. logicalCode = self.device['logicalCode'],
  188. groupId = group['groupId'],
  189. address = group['address'],
  190. groupNumber = self.device['groupNumber'],
  191. groupName = group['groupName'],
  192. ).save()
  193. else:
  194. self.consume_money_for_card(card, fee)
  195. # 记录卡消费记录以及消费记录
  196. orderNo, cardOrderNo = self.record_consume_for_card(card, fee)
  197. # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
  198. ServiceProgress.register_card_service(
  199. self.device, -1, card,
  200. {
  201. 'orderNo': orderNo,
  202. 'money': self.event_data['fee'],
  203. 'coin': self.event_data['fee'],
  204. 'needTime': 0,
  205. 'cardOrderNo': cardOrderNo
  206. }
  207. )
  208. # 通知微信,已经扣费
  209. self.notify_balance_has_consume_for_card(card, fee)
  210. elif self.event_data['cmdCode'] == '11' and self.event_data['status'] == '01': # 开始启动某个端口
  211. # 按下端口,开始使用。IC卡和ID卡都会上报这条信息。IC卡只记录消费记录信息,ID卡主要是上报了具体的某一个端口.ID卡和劲能的类似,主要是表示开始某一个端口以及回收余额
  212. cardType = self.event_data['cardType']
  213. card = self.update_card_dealer_and_type(self.event_data['cardNo'], cardType)
  214. if not card:
  215. logger.info('no find card<{}>'.format(self.event_data['cardNo']))
  216. return
  217. # 这个地方将计费方式更新到 portDict 刷卡退费的时候会将刷卡的退费金额上报过来 结束事件需要这个字段 主要的是要更新consumeDict的字段
  218. # 0 按时间收费
  219. # 1 按度计费
  220. consumeModule = self.device.get("otherConf", dict()).get("consumeModule", 0)
  221. if consumeModule == 0:
  222. self.event_data["billingType"] = "time"
  223. else:
  224. self.event_data["billingType"] = "elec"
  225. if cardType == 'ID':
  226. consumeDict = {'chargeIndex': self.event_data['port']}
  227. queryDict = {'device_imei': self.device.devNo,
  228. 'port': -1, 'isFinished': False,
  229. 'cardId': str(card.id), 'start_time': {'$gte': int(time.time()) - 3600}}
  230. progressDict = {'port': self.event_data['port']}
  231. ServiceProgress.update_progress_and_consume_rcd(ownerId = self.device.ownerId,
  232. queryDict = queryDict, consumeDict = consumeDict,
  233. updateConsume = True, progressDict = progressDict)
  234. # 找出对应的卡的ID记录到端口内存数据
  235. queryDict.update(progressDict)
  236. rcds = ServiceProgress.get_collection().find(queryDict, {'consumeOrder': 1},
  237. sort = [('start_time', -1)])
  238. allCoins = sum_rmb([rcd['consumeOrder']['coin'] for rcd in rcds])
  239. try:
  240. d = Device.objects(devNo=self.device.devNo).first()
  241. billingType = d.otherConf.get('billingType', 'time')
  242. actionBox = ActionDeviceBuilder.create_action_device(Device.get_dev(self.device.devNo))
  243. cardTime = actionBox.get_freemode_volume_andsoon_config()['card1Time']
  244. icMoney = int(actionBox.get_IC_coin_power_config()['icMoney']) / 10
  245. allCardTime = int(int(allCoins) / icMoney) * int(cardTime)
  246. except Exception as e:
  247. logger.error('allCardTime error: %s' % e)
  248. allCardTime = 0
  249. billingType = 'time'
  250. self.event_data.update({'cardOrderTime': str(allCardTime)})
  251. self.event_data.update({'cardId': str(card.id)})
  252. self.event_data.update({'openId': card.openId})
  253. self.event_data.update({'coins': str(allCoins)})
  254. self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  255. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  256. self.event_data.update({'billingType': billingType})
  257. Device.update_port_control_cache(self.device.devNo, self.event_data) # 记录该端口累计需要的时间和钱,cardId
  258. else: # IC卡,需要记录消费记录
  259. fee = RMB(self.event_data['fee'])
  260. card.balance = RMB(self.event_data['balance'])
  261. try:
  262. card.save()
  263. except Exception, e:
  264. logger.exception(e)
  265. orderNo, cardOrderNo = self.record_consume_for_card(card, fee)
  266. ServiceProgress.register_card_service(self.device, self.event_data['port'], card,
  267. {'orderNo': orderNo, 'money': self.event_data['fee'],
  268. 'coin': self.event_data['fee'], 'cardOrderNo': cardOrderNo})
  269. # 通知微信,已经扣费
  270. self.notify_balance_has_consume_for_card(card, fee)
  271. self.event_data.update({'cardId': str(card.id)})
  272. self.event_data.update({'openId': card.openId})
  273. self.event_data.update({'coins': self.event_data['fee']})
  274. self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  275. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  276. Device.update_port_control_cache(self.device.devNo, self.event_data) # 记录该端口累计需要的时间和钱,cardId
  277. YuhuanNorther.send_dev_status(self.device, self.event_data['port'], 1)
  278. elif self.event_data['cmdCode'] == '17': # 余额回收
  279. card = self.update_card_dealer_and_type(self.event_data['cardNo'], 'IC') # type: Card
  280. self.refund_money_for_card(RMB(self.event_data['backMoney']), card.id)
  281. elif self.event_data['cmdCode'] == '12':
  282. cardNo = self.event_data['cardNo']
  283. preBalance = RMB(self.event_data['balance'])
  284. card = self.update_card_dealer_and_type(cardNo, 'IC', balance = preBalance) # type: Card
  285. if not card:
  286. return
  287. if card.frozen:
  288. logger.debug('{} has been frozen.'.format(repr(card)))
  289. return
  290. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder
  291. if not card_recharge_order:
  292. logger.debug('{} has no recharge order.'.format(repr(card)))
  293. return
  294. if self.device.support_reliable:
  295. self.recharge_ic_card_realiable(card = card,
  296. preBalance = preBalance,
  297. rechargeType = 'overwrite',
  298. order = card_recharge_order)
  299. else:
  300. self.recharge_ic_card(card = card,
  301. preBalance = preBalance,
  302. rechargeType = 'overwrite',
  303. order = card_recharge_order)
  304. elif self.event_data['cmdCode'] == '05':
  305. # 新版本的结束事件,比就版本多刷卡ID卡的在线退费
  306. devNo = self.device.devNo
  307. port = str(self.event_data['port'])
  308. try:
  309. # 获取充电的模式
  310. ctrInfo = Device.get_dev_control_cache(devNo)
  311. lineInfo = ctrInfo.get(port)
  312. if not lineInfo:
  313. logger.debug('get null control cache from {}'.format(repr(self.device)))
  314. return
  315. else:
  316. logger.debug('port cache is: {}'.format(str(lineInfo)))
  317. billingType = lineInfo.get("billingType", "time")
  318. if billingType == "elec":
  319. return self.do_elec_finish(devNo, port, lineInfo, self.event_data)
  320. else:
  321. return self.do_time_finish(devNo, port, lineInfo, self.event_data)
  322. finally:
  323. Device.clear_port_control_cache(devNo, str(port))
  324. notify_event_to_north_v2(self.device["devNo"], self.event_data)
  325. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  326. desc = self.event_data['reason'])
  327. send_event_to_zhejiang(self.dealer, self.device, self.event_data)
  328. if self.event_data['reasonCode'] == '04': # 功率过载导致的断电,一条告警,一条恢复告警
  329. YuhuanNorther.send_dev_event(self.device, '97', port)
  330. YuhuanNorther.send_dev_event(self.device, '98', port)
  331. # 发送一条端口使用结束的告警
  332. YuhuanNorther.send_dev_status(self.device, port, 2)
  333. def do_elec_finish(self, devNo, port, lineInfo, msgDict):
  334. """
  335. 电川的板子 按电量退费
  336. :return:
  337. """
  338. dealer = self.device.owner
  339. if not dealer:
  340. logger.error('dealer is not found, dealerId=%s' % self.device['ownerId'])
  341. return
  342. leftElec = self.event_data.get("leftTime", 0) / 100.0
  343. reasonCode = self.event_data.get("endType")
  344. reasonStr = self.event_data.get("reason")
  345. cardNo = str(self.event_data.get("cardNo")) if self.event_data.get("cardNo") else None
  346. cardType = self.event_data.get("cardType")
  347. price = RMB(lineInfo.get('price', 0))
  348. startTime = lineInfo.get("startTime")
  349. # 投币事件
  350. if not startTime:
  351. return
  352. startTime = to_datetime(startTime)
  353. nowTime = datetime.datetime.now()
  354. deviceDuration, deviceElec = self.__parse_device_finished_data(self.event_data)
  355. try:
  356. consumeDict = {
  357. "reason": reasonStr,
  358. "chargeIndex": port,
  359. "uartData": self.event_data.get('uartData', '')
  360. }
  361. # 计算充电的时间
  362. if deviceDuration and deviceDuration > 0:
  363. usedTime = deviceDuration
  364. else:
  365. if startTime > nowTime:
  366. usedTime = 0
  367. else:
  368. usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
  369. consumeDict.update({"duration": usedTime})
  370. # 获取组信息
  371. group = Group.get_group(self.device["groupId"])
  372. # 扫码的结束
  373. if not cardNo:
  374. needElec = lineInfo.get("needElec")
  375. if leftElec == int("FFFF", 16):
  376. leftElec = needElec
  377. elif leftElec > needElec:
  378. logger.error('left elec is bigger than need elec. something is wrong')
  379. leftElec = 0
  380. spendElec = needElec - leftElec
  381. coins = VirtualCoin(lineInfo.get("coins"))
  382. refundCoins = VirtualCoin(0)
  383. refundedMoney = RMB(0)
  384. consumeDict.update({
  385. "reason": reasonStr,
  386. "chargeIndex": port
  387. })
  388. refundSwitch = self.device.is_auto_refund
  389. if refundSwitch:
  390. refundCoins = VirtualCoin(coins) * Ratio(leftElec / needElec)
  391. refundedMoney = RMB(price) * Ratio(leftElec / needElec)
  392. if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']:
  393. # 虚拟卡的结束
  394. consumeRcdId = lineInfo['consumeRcdId']
  395. vCardId = lineInfo.get("vCardId", "")
  396. vCard = UserVirtualCard.objects(id = vCardId).first()
  397. if not vCard:
  398. logger.info('can not find the vCard id = %s' % vCardId)
  399. return
  400. try:
  401. ServiceProgress.update_progress_and_consume_rcd(
  402. self.device.ownerId,
  403. {
  404. 'open_id': lineInfo['openId'],
  405. 'port': int(port),
  406. 'device_imei': self.device.devNo,
  407. 'isFinished': False
  408. },
  409. consumeDict
  410. )
  411. if refundCoins > VirtualCoin(0):
  412. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  413. vCard.refund_quota(vCardConsumeRcd, needElec - spendElec, spendElec,
  414. refundCoins.mongo_amount)
  415. finally:
  416. user = MyUser.objects(openId = lineInfo['openId'],
  417. groupId = self.device.groupId).first()
  418. self.notify_user_service_complete(
  419. service_name = u'充电',
  420. openid = user.managerialOpenId if user else '',
  421. port = port,
  422. address = group['address'],
  423. reason = self.event_data['reason'],
  424. finished_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  425. extra = [
  426. {u'虚拟卡号': vCard.cardNo}
  427. ]
  428. )
  429. elif 'openId' in lineInfo and lineInfo['openId']:
  430. # 扫码使用金币启动
  431. user = MyUser.objects(openId = lineInfo['openId'],
  432. groupId = self.device.groupId).first()
  433. try:
  434. is_cash = False
  435. if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0):
  436. is_cash = True
  437. consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: VirtualCoin(coins).mongo_amount})
  438. if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0):
  439. consumeDict.update(
  440. {DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(coins) - refundCoins).mongo_amount})
  441. self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash)
  442. ServiceProgress.update_progress_and_consume_rcd(
  443. self.device.ownerId,
  444. {
  445. 'open_id': lineInfo['openId'],
  446. 'port': int(port),
  447. 'device_imei': self.device.devNo,
  448. 'isFinished': False
  449. },
  450. consumeDict)
  451. finally:
  452. extra = []
  453. billAsService = self.device.bill_as_service_feature
  454. billAsServiceSwitch = billAsService.on
  455. if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
  456. real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH])
  457. if real_refund > RMB(0):
  458. extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)})
  459. extra.append({u'退款金额': '{}(元)'.format(real_refund)})
  460. if billAsServiceSwitch:
  461. elecExpense = round(billAsService.elec_charge * spendElec, 2)
  462. serviceExpense = round(billAsService.service_charge * spendElec, 2)
  463. extra.append({u'电费': '{}(元)'.format(elecExpense)})
  464. extra.append({u'服务费': '{}(元)'.format(serviceExpense)})
  465. extra.append({u'说明': '目前只能按电量充电,不能按时间充电'})
  466. else:
  467. extra.append({u'消费金额': '{}(元)'.format(price)})
  468. if billAsServiceSwitch:
  469. elecExpense = round(billAsService.elec_charge * spendElec, 2)
  470. serviceExpense = round(billAsService.service_charge * spendElec, 2)
  471. extra.append({u'电费': '{}(元)'.format(elecExpense)})
  472. extra.append({u'服务费': '{}(元)'.format(serviceExpense)})
  473. extra.append({u'说明': '目前只能按电量充电,不能按时间充电'})
  474. elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
  475. real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS])
  476. if real_refund > VirtualCoin(0):
  477. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)})
  478. extra.append({u'退款金额': '{}(金币)'.format(real_refund)})
  479. if billAsServiceSwitch:
  480. elecExpense = round(billAsService.elec_charge * spendElec, 2)
  481. serviceExpense = round(billAsService.service_charge * spendElec, 2)
  482. extra.append({u'电费': '{}(金币)'.format(elecExpense)})
  483. extra.append({u'服务费': '{}(金币)'.format(serviceExpense)})
  484. extra.append({u'说明': '目前只能按电量充电,不能按时间充电'})
  485. else:
  486. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  487. if billAsServiceSwitch:
  488. elecExpense = round(billAsService.elec_charge * spendElec, 2)
  489. serviceExpense = round(billAsService.service_charge * spendElec, 2)
  490. extra.append({u'电费': '{}(金币)'.format(elecExpense)})
  491. extra.append({u'服务费': '{}(金币)'.format(serviceExpense)})
  492. extra.append({u'说明': '目前只能按电量充电,不能按时间充电'})
  493. else:
  494. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  495. if billAsServiceSwitch:
  496. elecExpense = round(billAsService.elec_charge * spendElec, 2)
  497. serviceExpense = round(billAsService.service_charge * spendElec, 2)
  498. extra.append({u'电费': '{}(金币)'.format(elecExpense)})
  499. extra.append({u'服务费': '{}(金币)'.format(serviceExpense)})
  500. extra.append({u'说明': '目前只能按电量充电,不能按时间充电'})
  501. self.notify_user_service_complete(
  502. service_name = u'充电',
  503. openid = user.managerialOpenId if user else '',
  504. port = port,
  505. address = group['address'],
  506. reason = self.event_data['reason'],
  507. finished_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  508. extra = extra)
  509. else:
  510. logger.error('not net pay rather user virtual card pay. something is wrong.')
  511. else:
  512. backMoney = self.event_data.get("backMoney")
  513. # 刷卡的结束 如果没有开启刷卡退费 则结束上报过来的backMoney = 0
  514. if cardType == "IC":
  515. # IC卡结束 只有刷卡结束的IC卡才能够刷新IC卡余额
  516. card = self.update_card_dealer_and_type(cardNo, "IC")
  517. if reasonCode == "05" and backMoney > 0:
  518. # 原因为05表示刷卡结束充电,会把退费金额报上来. 否则只能通过11指令报上来
  519. self.refund_money_for_card(VirtualCoin(backMoney), card.id)
  520. consumeDict.update({'balance': str(card.balance + VirtualCoin(backMoney))})
  521. else:
  522. consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来
  523. elif cardType == "ID":
  524. # ID卡结束 直接退费就行了
  525. card = self.update_card_dealer_and_type(cardNo, "ID")
  526. if backMoney > 0:
  527. self.refund_money_for_card(RMB(backMoney), str(card.id))
  528. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  529. else:
  530. logger.error("invalid card type event data is <{}>".format(self.event_data))
  531. ServiceProgress.update_progress_and_consume_rcd(
  532. self.device.ownerId,
  533. {
  534. 'open_id': lineInfo['openId'],
  535. 'port': int(port),
  536. 'device_imei': self.device.devNo,
  537. 'isFinished': False
  538. },
  539. consumeDict
  540. )
  541. extra = [{u'实体卡号': cardNo}]
  542. if backMoney > 0:
  543. extra.append({
  544. u'退款金额': u'{}(金币)'.format(backMoney)
  545. })
  546. self.notify_user_service_complete(
  547. service_name = u'充电',
  548. openid = self.get_managerialOpenId_by_openId(lineInfo['openId']),
  549. port = port,
  550. address = group['address'],
  551. reason = self.event_data['reason'],
  552. finished_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  553. extra = extra
  554. )
  555. except Exception as e:
  556. logger.exception(e)
  557. def do_time_finish(self, devNo, port, lineInfo, msgDict):
  558. try:
  559. dealer = Dealer.objects(id=self.device['ownerId']).first()
  560. if not dealer:
  561. logger.error('dealer is not found, dealerId=%s' % self.device['ownerId'])
  562. return
  563. price = RMB(lineInfo.get('price', 0))
  564. refundProtectionTime = lineInfo.get('refundProtectionTime', 5)
  565. deviceDuration, deviceElec = self.__parse_device_finished_data(self.event_data)
  566. if lineInfo is not None and 'startTime' in lineInfo:
  567. startTime = to_datetime(lineInfo['startTime'])
  568. nowTime = datetime.datetime.now()
  569. if startTime > nowTime:
  570. logger.error('start time is bigger than now time,devNo={}'.format(devNo))
  571. serverDuration = -1
  572. else:
  573. serverDuration = int(round((((nowTime - startTime).total_seconds() + 59) / 60.0)))
  574. else:
  575. logger.info('lineinfo has not startTime,devNo=%s' % devNo)
  576. serverDuration = -1
  577. if deviceDuration > 0:
  578. usedTime = deviceDuration
  579. elif serverDuration >= 0:
  580. usedTime = serverDuration
  581. else:
  582. usedTime = -1
  583. leftTime = self.event_data['leftTime']
  584. if leftTime != 65535:
  585. leftTimeStr = leftTime
  586. if usedTime == -1:
  587. actualNeedTime = -1
  588. else:
  589. actualNeedTime = usedTime + leftTime
  590. else:
  591. leftTimeStr = u'端口未使用'
  592. actualNeedTime = 0
  593. group = self.device.group # type: GroupDict
  594. if actualNeedTime == -1:
  595. if 'cardNo' in self.event_data and self.event_data['cardNo']:
  596. card = Card.objects(cardNo = str(self.event_data['cardNo']), agentId = self.dealer.agentId).first()
  597. if card is not None:
  598. # todo 生成模板所需要的所有参数, 后续有客户自定义的话, 直接在这个字典里面添加, 不需要删掉之前的.
  599. # todo 这个变量仅仅用于下面generate_service_complete_title_by_devType()函数的参. 做成配置项更好, 下次不用改代码.
  600. templateMap = {
  601. 'cardCoins': 0,
  602. 'cardOrderTime': 0,
  603. 'actualNeedTime': 0,
  604. 'usedTime': 0,
  605. 'backCoins': 0,
  606. 'reason': u'没有实际预定时间, 忽略此次消费事件'
  607. }
  608. # 先去获取devType上面的模板, 如果没有就走正常的流程
  609. title = self.generate_service_complete_title_by_devType(self.device['devType']['id'], templateMap)
  610. if title != '':
  611. self.notify_user(
  612. card.managerialOpenId if card else '',
  613. 'service_complete',
  614. **{
  615. 'title': title,
  616. 'service': u'充电服务',
  617. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  618. 'remark': u'动态功率计算时间是指按照你的电动车功率大小进行折算出来的实际充电时间。'
  619. })
  620. else:
  621. self.notify_user_service_complete(
  622. service_name=u'充电',
  623. openid=card.managerialOpenId if card else '',
  624. port=port,
  625. address=group['address'],
  626. reason=self.event_data['reason'],
  627. finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  628. extra=[{
  629. u'实体卡号': self.event_data['cardNo']
  630. }]
  631. )
  632. logger.debug('has no actual need time. ignore this event.')
  633. return
  634. consumeDict = {
  635. 'reason': self.event_data['reason'],
  636. 'leftTime': leftTimeStr,
  637. 'chargeIndex': port,
  638. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  639. 'duration': usedTime,
  640. 'deviceDuration': deviceDuration,
  641. 'serverDuration': serverDuration,
  642. 'uartData': self.event_data.get('uartData', '')
  643. }
  644. if deviceElec != -1:
  645. consumeDict.update({'elec': deviceElec})
  646. else:
  647. # deviceObj = Device.objects(devNo = self.device.devNo).first()
  648. groupObj = Group.objects(id=self.device.groupId).first()
  649. if groupObj.otherConf.get('zhuxing', None) is not None:
  650. spendElec = round((float(random.randint(15, 19)) / 100) * (float(usedTime) / 60), 3)
  651. consumeDict.update({'elec': spendElec})
  652. consumeDict.update({'elecFee': self.deviceAdapter.calc_elec_fee(spendElec)})
  653. else:
  654. spendElec = 0.0
  655. consumeDict.update({'elec': 0.0})
  656. consumeDict.update({'elecFee': RMB(0.0).mongo_amount})
  657. # 涉及到卡的退费 不要以缓存为准 以设备上报的为准
  658. cardNo = self.event_data.get("cardNo")
  659. if cardNo:
  660. # 如果是刷卡的,直接更新消费记录,发通知消息,支持ID卡的退费。
  661. # IC卡的退费, 如果结束原因是刷卡退费(05), 则会把退费信息返回;
  662. # 否则不会把退费信息传过来,会通过11号命令返回
  663. cardType = self.event_data.get("cardType")
  664. if cardType == 'ID':
  665. card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="ID")
  666. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  667. if self.event_data.has_key('backMoney') and self.event_data['backMoney'] > 0:
  668. self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id)
  669. # 通知微信,已经退费
  670. self.notify_user(card.managerialOpenId, 'refund_coins', **{
  671. 'title': u'退币完成!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
  672. 'backCount': u'金币:%s' % VirtualCoin(self.event_data['backMoney']),
  673. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  674. })
  675. elif cardType == "IC":
  676. card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="IC")
  677. # IC 并且结束code是05 表示卡贴上去了
  678. if not card:
  679. logger.info('no found card=<{}>'.format(cardNo))
  680. return
  681. if self.event_data['endType'] == '05': # 刷卡退费结束的时候,才能够刷新IC卡的余额
  682. self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id)
  683. consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  684. else:
  685. consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来
  686. else:
  687. logger.error("invalid card type event data is <{}>".format(self.event_data))
  688. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  689. {'open_id': lineInfo['openId'], 'port': int(port),
  690. 'device_imei': self.device.devNo,
  691. 'isFinished': False}, consumeDict)
  692. extra = [{
  693. u'实体卡号': lineInfo['cardNo']
  694. }]
  695. if VirtualCoin(self.event_data['backMoney']) > VirtualCoin(0):
  696. extra.append({
  697. u'退费金额': u'{}(金币)'.format(self.event_data['backMoney'])
  698. })
  699. templateMap = {
  700. 'cardCoins': lineInfo.get('coins', 0),
  701. 'cardOrderTime': lineInfo.get('cardOrderTime', 0),
  702. 'actualNeedTime': actualNeedTime,
  703. 'usedTime': usedTime,
  704. 'backCoins': self.event_data['backMoney'],
  705. 'reason': self.event_data['reason']
  706. }
  707. title = self.generate_service_complete_title_by_devType(self.device['devType']['id'], templateMap)
  708. if title != '':
  709. # u"\\n\\n刷卡扣费金额:\\t\\t{cardCoins}\\n\\n刷卡订购时间:\\t\\t{cardOrderTime}\\n\\n动态功率计算时间:\\t\\t{actualNeedTime}\\n\\n使用时间:\\t\\t{usedTime}\\n\\n退款金额:\\t\\t{backCoins}\\n\\n结束原因:\\t\\t{reason}",
  710. self.notify_user(
  711. card.managerialOpenId if card else '',
  712. 'service_complete',
  713. **{
  714. 'title': title,
  715. 'service': u'充电服务',
  716. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  717. 'remark': u'动态功率计算时间是指按照你的电动车功率大小进行折算出来的实际充电时间。'
  718. })
  719. else:
  720. self.notify_user_service_complete(
  721. service_name = u'充电',
  722. openid = card.managerialOpenId if card else '',
  723. port = port,
  724. address = group['address'],
  725. reason = self.event_data['reason'],
  726. finished_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  727. extra = extra)
  728. else:
  729. if 'coins' not in lineInfo:
  730. logger.warning('line info<devNo={}> has no coins.'.format(self.device.devNo))
  731. return
  732. # 计算退费信息
  733. coins = VirtualCoin(lineInfo['coins'])
  734. refundCoins = VirtualCoin(0)
  735. refundedMoney = RMB(0)
  736. if self.device.is_auto_refund:
  737. if leftTime != 65535:
  738. refundCoins = coins * (float(leftTime) / float(actualNeedTime))
  739. refundedMoney = RMB(price * (float(leftTime) / float(actualNeedTime)))
  740. else:
  741. refundCoins = coins
  742. refundedMoney = RMB(price)
  743. if usedTime < refundProtectionTime and refundCoins != VirtualCoin(0):
  744. refundCoins = coins
  745. refundedMoney = RMB(price)
  746. if refundCoins > coins:
  747. refundCoins = coins
  748. if refundedMoney > RMB(price):
  749. refundedMoney = RMB(price)
  750. # 退费保护不受金币退款开关影响, 照样退费
  751. elif usedTime < refundProtectionTime:
  752. refundCoins = coins
  753. refundedMoney = RMB(price)
  754. if refundCoins > coins:
  755. refundCoins = coins
  756. if refundedMoney > RMB(price):
  757. refundedMoney = RMB(price)
  758. else:
  759. pass
  760. logger.debug(
  761. 'lefttime = {}, usedTime = {}, need time = {}, back coins = {}'.format(leftTime, usedTime,
  762. actualNeedTime,
  763. refundCoins))
  764. if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']:
  765. vCardId = lineInfo['vCardId']
  766. vCard = UserVirtualCard.objects(id = vCardId).first() # type: UserVirtualCard
  767. if not vCard:
  768. logger.info('can not find the vCard id = %s' % vCardId)
  769. return
  770. try:
  771. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  772. {'open_id': lineInfo['openId'],
  773. 'port': int(port),
  774. 'device_imei': self.device.devNo,
  775. 'isFinished': False}, consumeDict)
  776. if refundCoins > VirtualCoin(0):
  777. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = lineInfo['consumeRcdId'])
  778. vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, refundCoins.mongo_amount)
  779. finally:
  780. user = MyUser.objects(openId = lineInfo['openId'],
  781. groupId = self.device.groupId).first()
  782. self.notify_user_service_complete(
  783. service_name = u'充电',
  784. openid = user.managerialOpenId if user else '',
  785. port = port,
  786. address = group['address'],
  787. reason = self.event_data['reason'],
  788. finished_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  789. extra = [
  790. {u'虚拟卡号': vCard.cardNo}
  791. ]
  792. )
  793. elif 'openId' in lineInfo and lineInfo['openId']:
  794. user = MyUser.objects(openId = lineInfo['openId'],
  795. groupId = self.device.groupId).first()
  796. try:
  797. is_cash = False
  798. if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0):
  799. is_cash = True
  800. consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: VirtualCoin(coins).mongo_amount})
  801. if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0):
  802. consumeDict.update(
  803. {DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(coins) - refundCoins).mongo_amount})
  804. self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash)
  805. ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId,
  806. {'open_id': lineInfo['openId'],
  807. 'port': int(port),
  808. 'device_imei': self.device.devNo,
  809. 'isFinished': False}, consumeDict)
  810. finally:
  811. extra = []
  812. if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
  813. real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH])
  814. if real_refund > RMB(0):
  815. extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)})
  816. extra.append({u'退款金额': '{}(元)'.format(real_refund)})
  817. else:
  818. extra.append({u'消费金额': '{}(元)'.format(price)})
  819. elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
  820. real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS])
  821. if real_refund > VirtualCoin(0):
  822. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)})
  823. extra.append({u'退款金额': '{}(金币)'.format(real_refund)})
  824. else:
  825. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  826. else:
  827. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))})
  828. self.notify_user_service_complete(
  829. service_name = u'充电',
  830. openid = user.managerialOpenId if user else '',
  831. port = port,
  832. address = group['address'],
  833. reason = self.event_data['reason'],
  834. finished_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  835. extra = extra)
  836. else:
  837. logger.error('not net pay rather user virtual card pay. something is wrong.')
  838. except Exception as e:
  839. logger.exception(e)
  840. class ZHIXIA2InductorEvent(FaultEvent):
  841. def do(self, **args):
  842. # 处理数据
  843. voltage = self.event_data.get('voltage', -1)
  844. temperature = self.event_data.get('temperature', -1)
  845. smokeWarning = self.event_data.get('smokeWarning', False)
  846. try:
  847. otherConf = Device.objects.get(devNo = self.device.devNo).otherConf
  848. maxVoltage = otherConf.get('voltageThre', 230)
  849. if voltage >= maxVoltage:
  850. desc = u'当前电压%s伏超过了门限值:%s伏' % (voltage, maxVoltage)
  851. self.record(faultCode = FAULT_CODE.OVER_VOLTAGE, description = desc, title = u'主机电压过高', detail = None,
  852. level = FAULT_LEVEL.CRITICAL)
  853. maxTemperature = otherConf.get('temThre', 60)
  854. if temperature > maxTemperature:
  855. desc = u'当前主机温度%s度超过了门限值:%s度' % (temperature, maxTemperature)
  856. self.record(faultCode = FAULT_CODE.OVER_TEMPERATURE, description = desc, title = u'主机温度过高',
  857. detail = None, level = FAULT_LEVEL.CRITICAL)
  858. if smokeWarning:
  859. desc = u'当前主机出现冒烟,请第一时间确定是否有起火。此告警十万火急,请迅速联系物业、消防相关部门!'
  860. self.record(faultCode = FAULT_CODE.SMOKE, description = desc, title = u'主机出现冒烟', detail = None,
  861. level = FAULT_LEVEL.FATAL)
  862. except Exception, e:
  863. logger.error('some error=%s' % e)
  864. return
  865. class InteroperatorAlertEvent(FaultEvent):
  866. def __Analyze_alert_data(self, data):
  867. alertInfo = {'cmdCode': data['cmd'], 'logicalCode': self.device['logicalCode']}
  868. address = Group.get_group(self.device['groupId'])['address']
  869. # 这里判断数据格式
  870. if 'status' not in data:
  871. logger.error('Data arrays have no keywords status')
  872. return
  873. # 这里做漏电告警处理
  874. if '5' in data['status']:
  875. electricityNum = str(int(data['values'][0:4], 16)) + 'mA'
  876. alertInfo['electricity'] = {'electricityNum': electricityNum,
  877. 'address': address,
  878. 'reasonCode': '12',
  879. 'reason': u'在{}编号为{}发生漏电,漏电量为{}'
  880. .format(address, self.device['logicalCode'], electricityNum)}
  881. # 这里做高温告警处理
  882. if '6' in data['status']:
  883. temperatureAccess = [index for index, acces in enumerate(data['status'], 1) if acces == '6']
  884. temperatureAlertList = []
  885. for i in temperatureAccess:
  886. temperatureValue = str(int(data['values'][(i - 1) * 4:(i - 1) * 4 + 4], 16))
  887. temperatureAlertList.append(
  888. {'temperatureValue': temperatureValue,
  889. 'address': address,
  890. 'reasonCode': '11',
  891. 'reason': u'在{}编号为{}的设备有高温预警,当前温度为{}摄氏度'
  892. .format(address, self.device['logicalCode'], temperatureValue)})
  893. alertInfo['temperature'] = temperatureAlertList
  894. return alertInfo
  895. def do(self, **args):
  896. # 判断不存在的设备网上报
  897. if not self.device.ownerId:
  898. logger.error('This device cant find a dealer')
  899. return
  900. # 是否存在温感和电感
  901. temperaturePart = Part.objects(logicalCode = self.device['logicalCode'], partType = '3001')
  902. electricityPart = Part.objects(logicalCode = self.device['logicalCode'], partType = '3002')
  903. if not temperaturePart.count() or not electricityPart.count():
  904. logger.error(
  905. 'There are no transformers in the locigalcode {} equipment'.format(self.device['logicalCode']))
  906. return
  907. # 处理数据
  908. eventInfo = self.__Analyze_alert_data(self.event_data['data'])
  909. try:
  910. # 先处理高温情况
  911. if 'temperature' in eventInfo:
  912. for InfoDetail in eventInfo['temperature']:
  913. send_event_to_zhejiang(self.dealer, self.device, InfoDetail, partId = temperaturePart[0].id)
  914. # 提示用户
  915. group = Group.get_group(self.device['groupId'])
  916. self.notify_dealer('device_fault', **{
  917. 'title': u'注意!注意!您的设备发生故障',
  918. 'device': u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']),
  919. 'location': u'组名称:%s, 地址:%s' % (group['groupName'], group['address']),
  920. 'fault': InfoDetail['reason'],
  921. 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  922. })
  923. # 上报高温至消防
  924. # if self.device["ownerId"] in ("5b4ed32e8732d67bd0626528", "5b6c29388732d669f3ae6f94"):
  925. group = Group.get_group(self.device['groupId'])
  926. districtInfo = District.get_district(group["districtId"])
  927. self.device.update({"districtInfo": districtInfo, "groupAddr": group["address"]})
  928. LiangXiXiaoFang.send_to_xf_fault(self.device, "01", u"设备温度过高")
  929. # 处理漏电情况
  930. elif 'electricity' in eventInfo:
  931. # 获取漏电告警插件
  932. send_event_to_zhejiang(self.dealer, self.device, eventInfo['electricity'],
  933. partId = electricityPart[0].id)
  934. # 提示用户
  935. group = Group.get_group(self.device['groupId'])
  936. self.notify_dealer('device_fault', **{
  937. 'title': u'注意!注意!您的设备发生故障',
  938. 'device': u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']),
  939. 'location': u'组名称:%s, 地址:%s' % (group['groupName'], group['address']),
  940. 'fault': eventInfo['electricity']['reason'],
  941. 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  942. })
  943. # 上报漏电至消防
  944. # if self.device["ownerId"] in ("5b4ed32e8732d67bd0626528", "5b6c29388732d669f3ae6f94"):
  945. group = Group.get_group(self.device['groupId'])
  946. districtInfo = District.get_district(group["districtId"])
  947. self.device.update({"districtInfo": districtInfo, "groupAddr": group["address"]})
  948. LiangXiXiaoFang.send_to_xf_fault(self.device, "04", u"设备发生漏电")
  949. except:
  950. logger.error('Array {} nonspecification'.format(eventInfo))
  951. return
  952. self.record(detail = eventInfo)
  953. class InteroperatorReport(WorkEvent):
  954. def do(self, **args):
  955. if 'type' not in self.event_data:
  956. logger.error('Array {} is not format,lose a key named "type"'.format(self.event_data))
  957. if self.event_data.get('type') == 'report':
  958. devReportDict = {'logicalCode': 'logicalCode', 'time': self.event_data['time_stamp'], 'portInfo': {}}
  959. temperature = ''
  960. voltage = 220
  961. try:
  962. # 拿到个数判断是不是第一次
  963. reportNum = PortReport.get_collection().find({
  964. 'logicalCode': self.device['logicalCode']
  965. }).sort('time', -1).count()
  966. if reportNum:
  967. # 获取上一次存储的信息
  968. reportLast = PortReport.get_collection().find({
  969. 'logicalCode': self.device['logicalCode']
  970. }).sort('time', -1)[0]
  971. for ii in range(10):
  972. power = self.__saveDate(1, msgDict = self.event_data, ii = ii)
  973. if power:
  974. electricity = float(power) / voltage / 10
  975. else:
  976. electricity = reportLast['portInfo'][str(ii + 1)]['electricity']
  977. temperatureR = self.__saveDate(2, msgDict = self.event_data, ii = ii, electricity = electricity,
  978. devReportDict = devReportDict)
  979. if temperatureR:
  980. temperature = temperatureR
  981. devReportDict.update({'temperature': temperature})
  982. # 查看现在的跟以前差距多少
  983. timeInterval = devReportDict['time'] - reportLast['time']
  984. if timeInterval > 2:
  985. PortReportNewList = [
  986. {"logicalCode": self.device['logicalCode'], "temperature": reportLast['temperature'],
  987. 'portInfo': reportLast['portInfo'],
  988. 'time': reportLast['time'] + (v + 1) * 2}
  989. for v in range(int(timeInterval / 2) - 1)]
  990. PortReport.get_collection().insert_many(PortReportNewList)
  991. # 首存的情况
  992. else:
  993. for ii in range(10):
  994. power = self.__saveDate(1, msgDict = self.event_data, ii = ii)
  995. electricity = float(power) / voltage / 10
  996. temperatureR = self.__saveDate(2, msgDict = self.event_data, ii = ii, electricity = electricity,
  997. devReportDict = devReportDict)
  998. if temperatureR:
  999. temperature = temperatureR
  1000. devReportDict.update({'temperature': temperature})
  1001. except Exception, e:
  1002. logger.error('solve dev=%s device report has an error e=%s' % (self.device.devNo, e))
  1003. finally:
  1004. newInfo = PortReport(
  1005. logicalCode = self.device['logicalCode'],
  1006. temperature = devReportDict['temperature'],
  1007. time = devReportDict['time'],
  1008. portInfo = devReportDict['portInfo']
  1009. )
  1010. newInfo.save()
  1011. def __saveDate(self, data, msgDict, ii, electricity = None, devReportDict = None):
  1012. # 存储数据库
  1013. if data == 1:
  1014. powerData = msgDict['data']['power_data'][0 + 4 * ii:4 + 4 * ii]
  1015. power = int(powerData, 16)
  1016. return power
  1017. if data == 2:
  1018. temperature = ''
  1019. status = 'idle' if electricity == 0 else 'busy'
  1020. devReportDict['portInfo'].update(
  1021. {str(ii + 1): {'electricity': round(electricity, 3), 'status': status}})
  1022. if ii < 4 and msgDict['data']['temp_data'][0 + 4 * ii:4 + 4 * ii] != '0000':
  1023. temperatureNum = msgDict['data']['temp_data'][0 + 4 * ii:4 + 4 * ii]
  1024. temperature = int(temperatureNum, 16)
  1025. return temperature
  1026. class StartAckEventPreProcessor(AckEventProcessorIntf):
  1027. def analysis_reason(self, reason):
  1028. return FINISHED_CHARGE_REASON_MAP.get(reason, reason)
  1029. def pre_processing(self, device, event_data):
  1030. # type:(DeviceDict, dict)->dict
  1031. if 'duration' in event_data:
  1032. duration = event_data.get('duration')
  1033. event_data['duration'] = ((duration + 59) / 60)
  1034. if 'elec' in event_data:
  1035. elec = event_data.get('elec')
  1036. event_data['elec'] = round(elec / (10000.0 * 3600.0), 3)
  1037. if 'cardType' in event_data:
  1038. if event_data['cardType'] == 'AA33':
  1039. event_data['cardType'] = 'ID'
  1040. else:
  1041. event_data['cardType'] = 'IC'
  1042. if 'cardNo' in event_data:
  1043. event_data['cardNo'] = str(event_data['cardNo'])
  1044. if 'reason' in event_data:
  1045. event_data['reasonDesc'] = self.analysis_reason(event_data['reason'])
  1046. if 'fee' in event_data:
  1047. event_data['fee'] = (RMB(event_data['fee']) * Ratio("0.1"))
  1048. if 'balance' in event_data:
  1049. event_data['balance'] = (RMB(event_data['balance']) * Ratio("0.1"))
  1050. if 'backMoney' in event_data:
  1051. event_data['backMoney'] = (RMB(event_data['backMoney']) * Ratio("0.1"))
  1052. if 'sub' in event_data:
  1053. subs = event_data.get('sub', [])
  1054. for item in subs:
  1055. if 'fee' in item:
  1056. item['fee'] = (RMB(item['fee']) * Ratio('0.1'))
  1057. if 'balance' in item:
  1058. item['balance'] = (RMB(item['balance']) * Ratio('0.1'))
  1059. if 'left' in event_data:
  1060. event_data['left'] = event_data.pop('left')
  1061. else:
  1062. event_data['left'] = 0
  1063. return event_data
  1064. class CardRefundAckEventPreProcessor(AckEventProcessorIntf):
  1065. def pre_processing(self, device, event_data):
  1066. # type:(DeviceDict, dict)->dict
  1067. if 'cardType' in event_data:
  1068. if event_data['cardType'] == 'AA33':
  1069. event_data['cardType'] = 'ID'
  1070. else:
  1071. event_data['cardType'] = 'IC'
  1072. if 'cardNo' in event_data:
  1073. event_data['cardNo'] = str(event_data['cardNo'])
  1074. event_data['backMoney'] = (int(event_data['backMoney']) / 10.0)
  1075. return event_data
  1076. class MyComNetPayAckEvent(ComNetPayAckEvent):
  1077. def __init__(self, smartBox, event_data):
  1078. super(MyComNetPayAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1079. def post_after_start(self, order = None):
  1080. port = order.used_port
  1081. YuhuanNorther.send_dev_status(self.device, int(port), 1)
  1082. def post_after_finish(self, order = None):
  1083. port = order.used_port
  1084. if self.event_data['reason'] < 0:
  1085. logger.debug('reason<{}> is not to report.'.format(self.event_data['reason']))
  1086. return
  1087. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  1088. desc = self.event_data.get('reasonDesc', ''))
  1089. send_event_to_zhejiang(self.dealer, self.device, self.event_data)
  1090. if self.event_data['reason'] == '04':
  1091. YuhuanNorther.send_dev_event(self.device, '97', port)
  1092. YuhuanNorther.send_dev_event(self.device, '98', port)
  1093. # 发送一条端口使用结束的告警
  1094. YuhuanNorther.send_dev_status(self.device, port, 2)
  1095. def merge_order(self, master_order, sub_orders):
  1096. # type:(ConsumeRecord, list)->dict
  1097. order_value, unit, billingType = self.deviceAdapter._check_package(master_order.package)
  1098. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo = settings.TIME_ZONE)
  1099. portDict = {
  1100. 'billingType': billingType
  1101. }
  1102. if master_order.paymentInfo['via'] == 'virtualCard':
  1103. portDict.update({
  1104. 'vCardId': master_order.paymentInfo['itemId']
  1105. })
  1106. all_coins = master_order.package['coins']
  1107. all_price = master_order.package['price']
  1108. all_consume_value = order_value
  1109. for sub_order in sub_orders:
  1110. all_coins += sub_order.package['coins']
  1111. all_price += sub_order.package['price']
  1112. sub_consume_value, _, _ = self.deviceAdapter._check_package(sub_order.package)
  1113. all_consume_value += sub_consume_value
  1114. portDict['coins'] = str(all_coins)
  1115. portDict['price'] = str(all_price)
  1116. if billingType == 'time':
  1117. portDict['needKind'] = 'needTime'
  1118. portDict['needValue'] = all_consume_value
  1119. portDict['unit'] = u'分钟'
  1120. portDict['estimatedTs'] = int(start_time.timestamp + all_consume_value * 60)
  1121. else:
  1122. portDict['needKind'] = 'needElec'
  1123. portDict['needValue'] = all_consume_value / 100.0
  1124. portDict['unit'] = u'度'
  1125. portDict['estimatedTs'] = int(start_time.timestamp + 12 * 60 * 60)
  1126. return portDict
  1127. def do_time_finished(self, master_order, sub_orders, merge_order_info):
  1128. # type: (ConsumeRecord, List[ConsumeRecord], dict)->(dict)
  1129. user = MyUser.objects(openId = master_order.openId,
  1130. groupId = master_order.groupId).first() # type: MyUser
  1131. if not user:
  1132. logger.error(
  1133. 'user is not exist. openId = {}, groupId = {}'.format(master_order.openId, master_order.groupId))
  1134. return
  1135. coins = VirtualCoin(merge_order_info['coins'])
  1136. left = self.event_data['left']
  1137. if left == 65535:
  1138. consumeDict = {
  1139. 'reason': self.event_data['reason'],
  1140. 'leftTime': '端口故障',
  1141. 'chargeIndex': str(master_order.used_port),
  1142. 'actualNeedTime': u'动态功率计算为0分钟',
  1143. 'duration': 0,
  1144. 'elec': 0,
  1145. 'elecFee': 0
  1146. }
  1147. real_back_coins = coins
  1148. back_coins = coins
  1149. else:
  1150. duration, elec = self.event_data['duration'], self.event_data['elec']
  1151. actual_time = duration + left
  1152. if (actual_time == 0) or (actual_time > merge_order_info['needValue'] * 60):
  1153. actual_time = merge_order_info['needValue'] * 60
  1154. real_back_coins = coins * (float(left) / float(actual_time))
  1155. consumeDict = {
  1156. 'reason': self.event_data['reason'],
  1157. 'leftTime': str(left),
  1158. 'chargeIndex': str(master_order.used_port),
  1159. 'actualNeedTime': u'动态功率计算为%s分钟' % actual_time,
  1160. 'duration': duration,
  1161. 'elec': elec,
  1162. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1163. }
  1164. if master_order.paymentInfo['via'] == 'free':
  1165. back_coins = VirtualCoin(0)
  1166. else:
  1167. refundProtection = self.device.get('otherConf', {}).get('refundProtection', 0)
  1168. refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
  1169. auto_refund = self.device.is_auto_refund
  1170. logger.debug('{} auto refund enable switch is {}. refund protect = {}, refund protect time = {}'.format(
  1171. repr(self.device), str(auto_refund), refundProtection, refundProtectionTime))
  1172. if auto_refund:
  1173. if (refundProtection == 1 and duration < refundProtectionTime):
  1174. back_coins = coins
  1175. else:
  1176. back_coins = real_back_coins
  1177. else:
  1178. back_coins = VirtualCoin(0)
  1179. if back_coins > coins:
  1180. back_coins = coins
  1181. logger.debug(
  1182. 'lefttime = {}, usedTime = {}, need time = {}, real back coins = {}, back coins = {}'.format(
  1183. left, duration, actual_time, real_back_coins, back_coins))
  1184. extra = []
  1185. if master_order.paymentInfo['via'] == 'free':
  1186. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(0))})
  1187. elif master_order.paymentInfo['via'] == 'virtualCard':
  1188. vCard = UserVirtualCard.objects(id = master_order.virtual_card_id).first() # type: UserVirtualCard
  1189. if not vCard:
  1190. logger.info('can not find the vCard id = {}'.format(master_order.virtual_card_id))
  1191. return
  1192. if back_coins > VirtualCoin(0):
  1193. success, consumeTotal, consumeDay = vCard.clear_frozen_quota(str(master_order.id), duration, 0.0,
  1194. back_coins.mongo_amount)
  1195. try:
  1196. if success and consumeDay['count'] > 0:
  1197. record = VCardConsumeRecord(
  1198. orderNo = VCardConsumeRecord.make_no(master_order.logicalCode),
  1199. openId = master_order.openId,
  1200. nickname = master_order.nickname,
  1201. cardId = str(vCard.id),
  1202. dealerId = vCard.dealerId,
  1203. devNo = master_order.devNo,
  1204. devTypeCode = master_order.devTypeCode,
  1205. devTypeName = master_order.dev_type_name,
  1206. logicalCode = master_order.logicalCode,
  1207. groupId = master_order.groupId,
  1208. address = master_order.address,
  1209. groupNumber = master_order.groupNumber,
  1210. groupName = master_order.groupName,
  1211. attachParas = master_order.attachParas,
  1212. consumeData = consumeTotal,
  1213. consumeDayData = consumeDay
  1214. )
  1215. record.save()
  1216. except Exception, e:
  1217. logger.exception(e)
  1218. extra.append({u'虚拟卡号': vCard.cardNo})
  1219. elif master_order.paymentInfo['via'] in ['netPay', 'coins', 'cash', 'coin']:
  1220. user.clear_frozen_balance(str(master_order.id), master_order.paymentInfo['deduct'], back_coins,
  1221. (coins - back_coins))
  1222. for sub_order in sub_orders:
  1223. user.clear_frozen_balance(str(sub_order.id), sub_order.paymentInfo['deduct'], VirtualCoin(0),
  1224. VirtualCoin(0))
  1225. if back_coins > VirtualCoin(0):
  1226. consumeDict['refundedMoney'] = str(back_coins)
  1227. extra.append({u'消费金额': '{}(金币)'.format(coins - back_coins)})
  1228. extra.append({u'退款金额': '{}(金币)'.format(back_coins)})
  1229. else:
  1230. extra.append({u'消费金额': '{}(金币)'.format(coins)})
  1231. else:
  1232. logger.error('not net pay rather user virtual card pay. something is wrong.')
  1233. return
  1234. master_order.update_service_info(consumeDict)
  1235. auth_bridge = get_wechat_auth_bridge(source = self.device,
  1236. app_type = APP_TYPE.WECHAT_USER_MANAGER)
  1237. self.notify_user_service_complete(
  1238. service_name = u'充电',
  1239. openid = user.get_bound_pay_openid(auth_bridge.bound_openid_key),
  1240. port = str(master_order.used_port),
  1241. address = master_order.address,
  1242. reason = self.event_data.get('reasonDesc'),
  1243. finished_time = master_order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1244. extra = extra)
  1245. def do_elec_finished(self, master_order, sub_orders, merge_order_info):
  1246. # type: (ConsumeRecord, List[ConsumeRecord], dict)->(dict)
  1247. """
  1248. 电川的板子 按电量退费
  1249. :return:
  1250. """
  1251. user = MyUser.objects(openId = master_order.openId,
  1252. groupId = self.device.groupId).first() # type: MyUser
  1253. if not user:
  1254. logger.error('not find user<openId={}, groupId={}>'.format(master_order.openId, self.device.groupId))
  1255. return
  1256. leftElec = self.event_data.get("left", 0) / 100.0
  1257. duration, elec = self.event_data['duration'], self.event_data['elec']
  1258. try:
  1259. consumeDict = {
  1260. "reason": self.event_data['reasonDesc'],
  1261. "chargeIndex": master_order.used_port,
  1262. "duration": self.event_data['duration']
  1263. }
  1264. # 获取组信息
  1265. group = Group.get_group(self.device.groupId) # type: GroupDict
  1266. # 扫码的结束
  1267. needElec = merge_order_info['needValue']
  1268. if leftElec == int("FFFF", 16):
  1269. # 端口故障
  1270. left = needElec
  1271. elif leftElec > needElec:
  1272. logger.error('left elec is bigger than need elec. something is wrong')
  1273. left = 0
  1274. spendElec = needElec - leftElec
  1275. coins = VirtualCoin(merge_order_info['coins'])
  1276. back_coins = VirtualCoin(0)
  1277. if master_order.paymentInfo['via'] != 'free':
  1278. auto_refund = self.device.is_auto_refund
  1279. if auto_refund:
  1280. back_coins = VirtualCoin(coins) * Ratio(leftElec / needElec)
  1281. logger.debug(
  1282. 'leftElec = {}, spendElec = {}, usedTime = {}, back coins = {}, auto refund = {}'.format(
  1283. left, spendElec, duration, back_coins, auto_refund))
  1284. else:
  1285. logger.debug(
  1286. 'leftElec = {}, spendElec = {}, usedTime = {}, back coins = {}, free = True'.format(
  1287. left, spendElec, duration, back_coins))
  1288. extra = []
  1289. if master_order.paymentInfo['via'] == 'free':
  1290. extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(0))})
  1291. elif master_order.paymentInfo['via'] == 'virtualCard':
  1292. vCard = UserVirtualCard.objects(id = master_order.virtual_card_id).first()
  1293. if not vCard:
  1294. logger.info('can not find the vCard id = %s' % master_order.virtual_card_id)
  1295. return
  1296. extra.append({u'虚拟卡号': vCard.cardNo})
  1297. if back_coins > VirtualCoin(0):
  1298. success, consumeTotal, consumeDay = vCard.clear_frozen_quota(str(master_order.id),
  1299. needElec - spendElec,
  1300. spendElec, back_coins)
  1301. try:
  1302. if success and consumeDay['count'] > 0:
  1303. record = VCardConsumeRecord(
  1304. orderNo = VCardConsumeRecord.make_no(master_order.logicalCode),
  1305. openId = master_order.openId,
  1306. nickname = master_order.nickname,
  1307. cardId = str(vCard.id),
  1308. dealerId = vCard.dealerId,
  1309. devNo = master_order.devNo,
  1310. devTypeCode = master_order.devTypeCode,
  1311. devTypeName = master_order.dev_type_name,
  1312. logicalCode = master_order.logicalCode,
  1313. groupId = master_order.groupId,
  1314. address = master_order.address,
  1315. groupNumber = master_order.groupNumber,
  1316. groupName = master_order.groupName,
  1317. attachParas = master_order.attachParas,
  1318. consumeData = consumeTotal,
  1319. consumeDayData = consumeDay
  1320. )
  1321. record.save()
  1322. except Exception, e:
  1323. logger.exception(e)
  1324. elif master_order.paymentInfo['via'] in ['netPay', 'coins', 'cash', 'coin']:
  1325. user.clear_frozen_balance(str(master_order.id), master_order.paymentInfo['deduct'], back_coins,
  1326. (coins - back_coins))
  1327. for sub_order in sub_orders:
  1328. user.clear_frozen_balance(str(sub_order.id), sub_order.paymentInfo['deduct'], VirtualCoin(0),
  1329. VirtualCoin(0))
  1330. if back_coins > VirtualCoin(0):
  1331. consumeDict.update({"refundedMoney": str(back_coins)})
  1332. extra.append({u'消费金额': '{}(金币)'.format(coins - back_coins)})
  1333. extra.append({u'退款金额': '{}(金币)'.format(back_coins)})
  1334. else:
  1335. extra.append({u'消费金额': '{}(金币)'.format(coins)})
  1336. else:
  1337. logger.error('not net pay rather user virtual card pay. something is wrong.')
  1338. return
  1339. for order in [master_order].extend(sub_orders):
  1340. order.update_service_info(consumeDict)
  1341. auth_bridge = get_wechat_auth_bridge(source = self.device,
  1342. app_type = APP_TYPE.WECHAT_USER_MANAGER)
  1343. self.notify_user_service_complete(
  1344. service_name = u'充电',
  1345. openid = user.get_bound_pay_openid(auth_bridge.bound_openid_key),
  1346. port = str(master_order.used_port),
  1347. address = master_order.address,
  1348. reason = self.event_data.get('reasonDesc'),
  1349. finished_time = master_order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1350. extra = extra)
  1351. except Exception as e:
  1352. logger.exception(e)
  1353. def do_finished_event(self, master_order, sub_orders, merge_order_info):
  1354. # type: (ConsumeRecord, List[ConsumeRecord], dict)->None
  1355. billing_type = merge_order_info['billingType']
  1356. if billing_type == 'time':
  1357. self.do_time_finished(master_order, sub_orders, merge_order_info)
  1358. else:
  1359. self.do_elec_finished(master_order, sub_orders, merge_order_info)
  1360. class MyIcStartAckEvent(IcStartAckEvent):
  1361. def __init__(self, smartBox, event_data):
  1362. super(MyIcStartAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1363. def post_after_start(self, order = None):
  1364. port = order.used_port
  1365. YuhuanNorther.send_dev_status(self.device, int(port), 1)
  1366. def post_after_finish(self, order = None):
  1367. port = order.used_port
  1368. if self.event_data['reason'] < 0:
  1369. logger.debug('reason<{}> is not to report.'.format(self.event_data['reason']))
  1370. return
  1371. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  1372. desc = self.event_data.get('reasonDesc', ''))
  1373. send_event_to_zhejiang(self.dealer, self.device, self.event_data)
  1374. if self.event_data['reason'] == '04':
  1375. YuhuanNorther.send_dev_event(self.device, '97', port)
  1376. YuhuanNorther.send_dev_event(self.device, '98', port)
  1377. # 发送一条端口使用结束的告警
  1378. YuhuanNorther.send_dev_status(self.device, port, 2)
  1379. def merge_order(self, master_order, sub_orders):
  1380. # type:(ConsumeRecord, list)->dict
  1381. consumeModule = self.device.get("otherConf", dict()).get("consumeModule", 0)
  1382. # 按时间计费
  1383. if consumeModule == 0:
  1384. billingType = 'time'
  1385. else:
  1386. billingType = 'elec'
  1387. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo = settings.TIME_ZONE)
  1388. portDict = {
  1389. 'billingType': billingType
  1390. }
  1391. if master_order.paymentInfo['via'] == 'virtualCard':
  1392. portDict.update({
  1393. 'vCardId': master_order.paymentInfo['itemId']
  1394. })
  1395. all_coins = master_order.coin
  1396. all_money = master_order.money
  1397. for sub_order in sub_orders:
  1398. all_coins += master_order.coin
  1399. all_money += master_order.money
  1400. portDict['coins'] = str(all_coins)
  1401. portDict['money'] = str(all_money)
  1402. portDict['estimatedTs'] = int(start_time.timestamp + 12 * 60 * 60)
  1403. return portDict
  1404. def do_time_finished(self, card, order, merge_order_info):
  1405. # type: (Card, ConsumeRecord, dict)->(dict)
  1406. duration, elec = self.event_data['duration'], self.event_data['elec']
  1407. coins = VirtualCoin(merge_order_info['coins'])
  1408. left = self.event_data['left']
  1409. consumeDict = {
  1410. 'reason': self.event_data['reason'],
  1411. 'chargeIndex': str(order.used_port),
  1412. 'duration': duration,
  1413. 'elec': elec,
  1414. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1415. }
  1416. # backMoney = VirtualCoin(self.event_data['backMoney'])
  1417. group = self.device.group # type: GroupDict
  1418. extra = [{
  1419. u'实体卡号': self.event_data['cardNo']
  1420. }]
  1421. consumeDict.update({'balance': str(card.balance)})
  1422. order.update_service_info(consumeDict)
  1423. self.notify_user_service_complete(
  1424. service_name = u'充电',
  1425. openid = card.managerialOpenId if card else '',
  1426. port = order.used_port,
  1427. address = group.address,
  1428. reason = self.event_data['reason'],
  1429. finished_time = order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1430. extra = extra)
  1431. def do_elec_finished(self, card, order, merge_order_info):
  1432. # type:(Card, ConsumeRecord, dict)->None
  1433. """
  1434. 电川的板子 按电量退费
  1435. :return:
  1436. """
  1437. leftElec = self.event_data.get('left', 0) / 100.0
  1438. duration, elec = self.event_data['duration'], self.event_data['elec']
  1439. try:
  1440. consumeDict = {
  1441. 'reason': self.event_data['reasonDesc'],
  1442. 'chargeIndex': order.used_port,
  1443. 'duration': duration,
  1444. 'elec': elec,
  1445. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1446. }
  1447. # backMoney = self.event_data.get("backMoney")
  1448. extra = [{u'实体卡号': self.event_data['cardNo']}]
  1449. # if self.event_data['cardType'] == 'ID':
  1450. # if backMoney > 0:
  1451. # self.refund_money_for_card(RMB(backMoney), card.id)
  1452. # extra.append({
  1453. # u'退款金额': u'{}(金币)'.format(backMoney)
  1454. # })
  1455. #
  1456. # consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  1457. # else:
  1458. consumeDict.update({'balance': str(card.balance)})
  1459. order.update_service_info(consumeDict)
  1460. self.notify_user_service_complete(
  1461. service_name = u'充电',
  1462. openid = self.get_managerialOpenId_by_openId(order.openId),
  1463. port = order.used_port,
  1464. address = self.device.group.address,
  1465. reason = self.event_data['reason'],
  1466. finished_time = order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1467. extra = extra)
  1468. except Exception as e:
  1469. logger.exception(e)
  1470. def do_finished_event(self, card, order, merge_order_info):
  1471. # type:(Card, ConsumeRecord, dict)->None
  1472. if 'backMoney' in self.event_data and self.event_data['backMoney'] > RMB(0):
  1473. refund_order = RechargeRecord.objects(orderNo = self.event_data['order_id']).first()
  1474. if not refund_order:
  1475. self.refund_money_for_card(RMB(self.event_data['backMoney']), card.id, self.event_data['order_id'])
  1476. billing_type = merge_order_info['billingType']
  1477. if billing_type == 'time':
  1478. self.do_time_finished(card, order, merge_order_info)
  1479. else:
  1480. self.do_elec_finished(card, order, merge_order_info)
  1481. class MyIcRechargeAckEvent(IcRechargeAckEvent):
  1482. def __init__(self, smartBox, event_data):
  1483. super(MyIcRechargeAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1484. class MyCardRefundAckEvent(CardRefundAckEvent):
  1485. def __init__(self, smartBox, event_data):
  1486. super(MyCardRefundAckEvent, self).__init__(smartBox, event_data, CardRefundAckEventPreProcessor())