weifule2.py 42 KB

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