hedong.py 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import json
  5. import logging
  6. import time
  7. from arrow import Arrow
  8. from django.conf import settings
  9. from mongoengine import DoesNotExist
  10. from apilib.monetary import RMB, VirtualCoin, Ratio
  11. from apilib.systypes import StrEnum
  12. from apilib.utils_datetime import to_datetime
  13. from apilib.utils_string import make_title_from_dict
  14. from apps.web.agent.models import Agent
  15. from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND, APP_TYPE, DeviceCmdCode
  16. from apps.web.core.accounting import Accounting
  17. from apps.web.core.adapter.base import SmartBox
  18. from apps.web.core.adapter.hedong import ChargingHDBox
  19. from apps.web.core.device_define.jndz import CMD_CODE, SWIPE_CARD_PARAM_OP, SWIPE_CARD_RES
  20. from apps.web.core.exceptions import ServiceException
  21. from apps.web.core.networking import MessageSender
  22. from apps.web.dealer.models import Dealer
  23. from apps.web.device.models import Group, Device, DeviceDict, GroupDict
  24. from apps.web.eventer import EventBuilder
  25. from apps.web.eventer.base import FaultEvent, WorkEvent, ComNetPayAckEvent, AckEventProcessorIntf, \
  26. IcStartAckEvent, IcRechargeAckEvent, CardRefundAckEvent, IdStartAckEvent, VirtualCardStartAckEvent
  27. from apps.web.eventer.errors import InvalidOption, NoCommandHandlerAvailable
  28. from apps.web.helpers import get_wechat_auth_bridge
  29. from apps.web.report.utils import record_consumption_stats
  30. from apps.web.south_intf.platform import notify_event_to_north
  31. from apps.web.south_intf.zhejiang_fire import send_event_to_zhejiang
  32. from apps.web.south_intf.zhongtian import report_zhongtian_service_complete, report_zhongtian_refund
  33. from apps.web.user.models import VCardConsumeRecord, ServiceProgress, CardRechargeOrder, MyUser, \
  34. UserVirtualCard, Card, ConsumeRecord, RechargeRecord
  35. from apps.web.api.models import APIStartDeviceRecord
  36. from apps.web.user.utils import freeze_user_balance
  37. logger = logging.getLogger(__name__)
  38. class Cmd:
  39. # 刷卡类
  40. SUCCESS_00 = 0
  41. BALANCE_NOT_ENOUGH_01 = 1
  42. INVALID_CARD_02 = 2
  43. class CARD_TYPE(StrEnum):
  44. OFFLINE_CARD = "00"
  45. ONLINE_CARD = "01"
  46. MONTHLY_CARD = "02"
  47. FULL_CARD = "04"
  48. def is_server_refund(billingType, dev, dealer, agent):
  49. # type:(str, DeviceDict, Dealer, Agent)->bool
  50. if billingType != 'time':
  51. if 'jhCardElecRefund' in dealer.features:
  52. return False
  53. if dev.is_auto_refund:
  54. return True
  55. else:
  56. return False
  57. else:
  58. if 'huopo_card_time_refund' in agent.features:
  59. return True
  60. else:
  61. support_server_refund = dev.devType.get('features', {}).get(
  62. 'support_server_refund', False)
  63. if not support_server_refund:
  64. return False
  65. if dev.is_auto_refund:
  66. return True
  67. else:
  68. return False
  69. class builder(EventBuilder):
  70. def __getEvent__(self, device_event):
  71. if 'order_id' in device_event:
  72. if device_event['order_type'] == 'com_start':
  73. return MyComNetPayAckEvent(self.deviceAdapter, device_event)
  74. elif device_event['order_type'] == 'ic_recharge':
  75. return MyIcRechargeAckEvent(self.deviceAdapter, device_event)
  76. elif device_event['order_type'] == 'ic_start':
  77. return MyIcStartAckEvent(self.deviceAdapter, device_event)
  78. elif device_event['order_type'] == 'id_start':
  79. return MyIdStartAckEvent(self.deviceAdapter, device_event)
  80. elif device_event['order_type'] == 'vir_start':
  81. return MyVirtualCardStartAckEvent(self.deviceAdapter, device_event)
  82. elif device_event['order_type'] == 'card_refund':
  83. return MyCardRefundAckEvent(self.deviceAdapter, device_event)
  84. else:
  85. pass
  86. elif 'event_type' in device_event:
  87. if device_event['event_type'] == 'card':
  88. return CardEvent(self.deviceAdapter, device_event)
  89. else:
  90. return None
  91. event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
  92. if event_data is None or 'cmdCode' not in event_data:
  93. return None
  94. if 'duration' in device_event:
  95. event_data.update({'duration': device_event['duration']})
  96. if event_data['cmdCode'] in ['06', '16', '20', '2D', '2C']:
  97. return ChargingJNDZWorkEvent(self.deviceAdapter, event_data)
  98. if event_data['cmdCode'] in [
  99. CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A,
  100. CMD_CODE.DEVICE_FAULT_TEMPERATURE,
  101. CMD_CODE.DEVICE_FAULT_POWER,
  102. CMD_CODE.DEVICE_FAULT_SMOKE,
  103. CMD_CODE.DEVICE_ELEC,
  104. CMD_CODE.DEVICE_FAULT_ALTER
  105. ]:
  106. return JNDZEventerFailure(self.deviceAdapter, event_data)
  107. #if event_data['cmdCode'] == '21':
  108. # return ChargingJNDZReportEvent(self.deviceAdapter, event_data)
  109. class CardEvent(WorkEvent):
  110. def do(self):
  111. if not self.deviceAdapter.get_device_configs(): # type:ChargingHDBox.get_device_configs()
  112. self.deviceAdapter.get_dev_setting()
  113. if self.event_data['funCode'] == '10':
  114. self._do_get_balance()
  115. def _do_get_balance(self):
  116. cardNo = str(int(self.event_data["cardNo"], 16))
  117. logger.info('[_do_get_balance] receive cardNo = {}'.format(cardNo))
  118. card = self.update_card_dealer_and_type(cardNo)
  119. if not card or not card.openId or card.frozen:
  120. logger.info('[_do_get_balance] receive cardNo = {}, card invalid!'.format(cardNo))
  121. data = {
  122. 'funCode': '10',
  123. 'cardNo': self.event_data.get('cardNo'),
  124. 'result': Cmd.INVALID_CARD_02,
  125. 'balance': 0,
  126. }
  127. else:
  128. # 是否存在没有到账的余额 进行充值
  129. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  130. self.recharge_id_card(
  131. card=card,
  132. rechargeType='append',
  133. order=card_recharge_order
  134. )
  135. card.reload()
  136. device_configs = self.deviceAdapter.get_device_configs()
  137. cst = RMB(device_configs.get('cst', 30) / 10.0)
  138. if card.balance >= RMB(0.1):
  139. pay = int(min(cst, card.balance) * 10) * 0.1 # 采用向下取整
  140. rule = self.get_account_rule(pay) # 下发对应的额度
  141. data = {
  142. 'funCode': '10',
  143. 'cardNo': self.event_data.get('cardNo'),
  144. 'result': Cmd.SUCCESS_00,
  145. 'balance': int(card.balance * 10.0),
  146. }
  147. data.update(rule)
  148. else:
  149. data = {
  150. 'funCode': '10',
  151. 'cardNo': self.event_data.get('cardNo'),
  152. 'result': Cmd.BALANCE_NOT_ENOUGH_01,
  153. 'balance': 0,
  154. }
  155. self.send_mqtt(data=data)
  156. def send_mqtt(self, data=None, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, otherData=None):
  157. '''
  158. 发送mqtt 指令默认210 返回data
  159. '''
  160. result = MessageSender.send(self.device, cmd,
  161. data)
  162. if 'rst' in result and result['rst'] != 0:
  163. if result['rst'] == -1:
  164. raise ServiceException(
  165. {'result': 2, 'description': u'该设备正在玩命找网络,请您稍候再试', 'rst': -1})
  166. elif result['rst'] == 1:
  167. raise ServiceException(
  168. {'result': 2, 'description': u'该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  169. else:
  170. if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]:
  171. return
  172. return result.get('data', 'ok')
  173. def get_account_rule(self, coins):
  174. device_configs = self.deviceAdapter.get_device_configs()
  175. cardMin = device_configs.get('cardMin', 240)
  176. cardElec = device_configs.get('cardElec', 10)
  177. # 秒
  178. timeMax = int(coins * 60 * cardMin)
  179. # 度 > 瓦
  180. elecMax = int(coins * 0.1 * 3600000 * cardElec)
  181. powerMax1 = device_configs.get('powerMax1', 200)
  182. power1Ti = device_configs.get('power1Ti', 100)
  183. powerMax2 = device_configs.get('powerMax2', 300)
  184. power2Ti = device_configs.get('power2Ti', 75)
  185. powerMax3 = device_configs.get('powerMax3', 400)
  186. power3Ti = device_configs.get('power3Ti', 50)
  187. powerMax4 = device_configs.get('powerMax4', 500)
  188. power4Ti = device_configs.get('power4Ti', 25)
  189. return {
  190. 'timeMax': timeMax,
  191. 'elecMax': elecMax,
  192. 'accountRule': {
  193. 'powerStep': [
  194. {'max': powerMax1,
  195. 'ratio': power1Ti},
  196. {'max': powerMax2,
  197. 'ratio': power2Ti},
  198. {'max': powerMax3,
  199. 'ratio': power3Ti},
  200. {'max': powerMax4,
  201. 'ratio': power4Ti},
  202. ]
  203. }
  204. }
  205. class JNDZEventerFailure(FaultEvent):
  206. def do(self, **args):
  207. cmdCode = self.event_data.get('cmdCode')
  208. faultType = self.event_data.get(u'fault')
  209. desc = self.event_data.get('desc', '')
  210. # 保证原有的故障处理逻辑不变
  211. if cmdCode == CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A:
  212. if self.event_data.get('FaultCode') == 1: # 不准确的继电器粘连上报
  213. pass
  214. else:
  215. super(JNDZEventerFailure, self).do()
  216. group = Group.get_group(self.device.groupId)
  217. titleList = [
  218. {u'告警名称': faultType},
  219. {u'地址名称': group['groupName']}
  220. ]
  221. title = make_title_from_dict(titleList)
  222. # 接下来的都是整机告警,这个地方需要通知到经销商
  223. # TODO zjl 需要知道 这个告警标志位是否有具体含义
  224. self.notify_dealer(
  225. 'device_fault',
  226. title = title,
  227. device = u' 号设备'.format(self.device.logicalCode),
  228. faultType = faultType,
  229. notifyTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  230. fault = ''
  231. )
  232. # 记录错误故障
  233. self.record(
  234. faultCode = cmdCode,
  235. description = desc,
  236. title = faultType,
  237. detail ={'faultType':faultType}
  238. )
  239. class ChargingJNDZWorkEvent(WorkEvent):
  240. def do(self, **args):
  241. devNo = self.device['devNo']
  242. logger.info('JingNengDianZi charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
  243. cmdCode = self.event_data['cmdCode']
  244. #: 刷卡消费的,分为扣费和退费两种
  245. if cmdCode == CMD_CODE.SWIPE_CARD_10:
  246. if self.device.support_reliable:
  247. return self.do_id_response_support_reliable(**args)
  248. cardNo = self.event_data['cardNo']
  249. preFee = RMB(self.event_data['preFee'])
  250. #: 操作符,是充值还是减少 <- (00, 01)
  251. oper = self.event_data['oper']
  252. card = self.update_card_dealer_and_type(cardNo)
  253. #: 经销商限制ID卡, 如果满足直接return
  254. if not card:
  255. self.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
  256. return
  257. self.event_data['openId'] = card.openId
  258. self.event_data['cardId'] = str(card.id)
  259. self.event_data['startTime'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  260. Device.update_dev_control_cache(devNo, self.event_data)
  261. #: 首先检查订单,并进行充值
  262. #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来
  263. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  264. result = self.recharge_id_card(card = card,
  265. rechargeType = 'append',
  266. order = card_recharge_order)
  267. card.reload()
  268. logger.info('JingNengDianZi cmdNo(10) - cardNo=%s, openId=%s, result=%s, preFee=%s, curinfo=%s' % (
  269. cardNo, card.openId, result, preFee, self.event_data))
  270. # TODO 这个地方为了同时满足劲能电子和霍珀的需求 先使用特性 vCardNeedBind 后续需要统一规则
  271. try:
  272. dealer = Dealer.get_dealer(card.dealerId)
  273. agent = Agent.objects.get(id = dealer.get('agentId'))
  274. features = agent.features
  275. except Exception as e:
  276. features = list()
  277. if 'vCardNeedBind' in features:
  278. virtual_card = card.bound_virtual_card
  279. else:
  280. virtual_card = card.related_virtual_card
  281. # 如果虚拟卡已经绑定,需要检查下今天是否可用,如果可用,有限使用虚拟卡
  282. vCardCanUse = False
  283. package = {'coins': float(preFee), 'unit': u'分钟', 'time': 180}
  284. if virtual_card is not None and card.openId is not None:
  285. devObj = Device.objects.get(devNo = devNo)
  286. cardMin = devObj.otherConf.get('cardMin', None)
  287. if cardMin is not None:
  288. package = {'coins': float(preFee), 'unit': u'分钟', 'time': int(cardMin)}
  289. vCardCanUse = virtual_card.can_use_today(package)
  290. #: 扣费
  291. if oper == SWIPE_CARD_PARAM_OP.DECR_00:
  292. if card.openId == '' or card.frozen:
  293. res = SWIPE_CARD_RES.INVALID_CARD_02
  294. leftBalance = RMB(0)
  295. return self.response_use_card(res, leftBalance)
  296. # 如果虚拟卡可用,卡的费用不要扣掉,仅仅做记录,但是虚拟卡的额度需要扣掉
  297. elif vCardCanUse:
  298. # 记录卡消费记录以及消费记录
  299. orderNo, cardOrderNo = self.record_consume_for_card(card, money = RMB(0.0), desc = u'使用绑定的虚拟卡')
  300. group = Group.get_group(self.device['groupId'])
  301. consumeRcd = virtual_card.consume(openId = card.openId, group = group, dev = self.device,
  302. package = package,
  303. attachParas = {}, nickname = card.cardName)
  304. # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
  305. ServiceProgress.register_card_service(self.device, -1, card,
  306. {
  307. 'orderNo': orderNo,
  308. 'money': self.event_data['preFee'],
  309. 'coin': self.event_data['preFee'], 'needTime': 0,
  310. 'cardOrderNo': cardOrderNo,
  311. 'consumeRcdId': str(consumeRcd.id)
  312. })
  313. self.consume_money_for_card(card, money = RMB(0.0))
  314. if consumeRcd is None: # 如果额度没有扣除成功,就用卡
  315. pass
  316. else:
  317. self.response_use_card(SWIPE_CARD_RES.SUCCESS_00, leftBalance = 0)
  318. # 通知微信,已经扣费
  319. # self.notify_balance_has_consume_for_card(card, preFee, desc = u'使用绑定的虚拟卡')
  320. return
  321. elif result['balance'] < preFee:
  322. res = SWIPE_CARD_RES.BALANCE_NOT_ENOUGH_01
  323. leftBalance = result['balance']
  324. return self.response_use_card(res, leftBalance)
  325. else:
  326. # 记录卡消费记录以及消费记录
  327. orderNo, cardOrderNo = self.record_consume_for_card(card, preFee)
  328. # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
  329. ServiceProgress.register_card_service(self.device, -1, card,
  330. {
  331. 'orderNo': orderNo,
  332. 'money': self.event_data['preFee'],
  333. 'coin': self.event_data['preFee'], 'needTime': 0,
  334. 'cardOrderNo': cardOrderNo
  335. })
  336. res = SWIPE_CARD_RES.SUCCESS_00
  337. leftBalance = result['balance']
  338. self.consume_money_for_card(card, preFee)
  339. leftBalance -= preFee
  340. self.response_use_card(res, leftBalance)
  341. # 通知微信,已经扣费
  342. self.notify_balance_has_consume_for_card(card, preFee)
  343. # 退费.卡的退费比较特殊:如果需要按照电量进行扣费退费,需要在设备管理后台,设置成按电量方式计费。然后把卡的余额回收关闭掉。
  344. # 充电结束后,上报事件,然后把钱退到卡里。如果是按照时间计费(霍柏的特殊),完全由设备决定,设备告诉我退费,我就退。针对霍柏
  345. # 绑定虚拟卡的情况下,按照时间退费,需要直接取消掉余额回收,靠结束事件触发结束
  346. elif oper == SWIPE_CARD_PARAM_OP.INCR_01:
  347. if virtual_card:
  348. logger.debug('virtual card is not do device refund.')
  349. return
  350. dev = Device.objects.get(devNo = self.device['devNo'])
  351. dealer = self.device.owner
  352. if not dealer:
  353. logger.error('dealer is not found, dealerId=%s' % self.device.ownerId)
  354. return
  355. agent = Agent.objects(id = dealer.agentId).first()
  356. if not agent:
  357. logger.error('agent is not found, agentId=%s' % dealer.agentId)
  358. return
  359. res = SWIPE_CARD_RES.SUCCESS_00
  360. device_refund = False
  361. billingType = dev.otherConf.get('billingType', 'time')
  362. if is_server_refund(billingType, self.device, dealer, agent):
  363. logger.debug('{} in {} has card refund by server refund.'.format(repr(card), repr(self.device)))
  364. return
  365. logger.debug('{} card refund by {}.'.format(repr(card), repr(self.device)))
  366. self.response_use_card(res, card.balance + preFee)
  367. self.refund_money_for_card(preFee, str(card.id))
  368. self.notify_user(card.managerialOpenId, 'refund_coins', **{
  369. 'title': u'退币完成!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
  370. 'backCount': u'金币:%s' % preFee,
  371. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  372. })
  373. else:
  374. raise InvalidOption('oper has be to 00 or 01, %s was given' % (oper,))
  375. #: 结束的命令
  376. elif cmdCode in [CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06, CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16]:
  377. lineInfo = Device.update_port_control_cache(devNo, self.event_data)
  378. group = Group.get_group(self.device['groupId'])
  379. dealer = Dealer.objects(id = group['ownerId']).first()
  380. if not dealer:
  381. logger.error('dealer is not found, dealerId=%s' % group['ownerId'])
  382. return
  383. agent = Agent.objects(id = dealer.agentId).first()
  384. if not agent:
  385. logger.error('agent is not found, agentId=%s' % dealer.agentId)
  386. return
  387. if not lineInfo.has_key('coins'):
  388. logger.debug('port cache has no coins. no order in port {}'.format(lineInfo.get('port')))
  389. return
  390. if 'duration' in self.event_data and self.event_data['duration'] > 0:
  391. usedTime = self.event_data['duration']
  392. else:
  393. if (not lineInfo) or (not lineInfo.has_key('startTime')):
  394. return
  395. startTime = to_datetime(lineInfo['startTime'])
  396. nowTime = datetime.datetime.now()
  397. if startTime > nowTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
  398. usedTime = 0
  399. else:
  400. usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
  401. cardId = lineInfo.get('cardId', '')
  402. vCardId = lineInfo.get('vCardId', None)
  403. money = VirtualCoin(lineInfo['coins'])
  404. backCoins = VirtualCoin(0.0)
  405. price = RMB(lineInfo.get('price', 0.0))
  406. refundRMB = RMB('0.0')
  407. leftTime = self.event_data['leftTime']
  408. billingType = lineInfo.get('billingType', 'time')
  409. consumeType = lineInfo.get('consumeType', '')
  410. refundProtectionTime = lineInfo.get('refundProtectionTime', 5)
  411. isTempPackage = lineInfo.get('isTempPackage', False)
  412. needTime = 0
  413. leftTimeStr = ''
  414. try:
  415. #: 刷卡或者万一缓存重启了,出现needElec为空的,作为1000度电吧,就会一定使用设备上报的电量
  416. if lineInfo.get('elec', 0.0) < lineInfo.get('needElec', 0.0):
  417. spendElec = round(lineInfo['needElec'] - lineInfo['elec'], 2)
  418. backCoins_by_elec = round(self.event_data.get('elec',0) / lineInfo['needElec'] * float(money), 2)
  419. else:
  420. spendElec = 0.0
  421. backCoins_by_elec = money
  422. if leftTime == 65535:
  423. actualNeedTime = 0
  424. backCoins = money
  425. refundRMB = price
  426. usedTime = 0
  427. spendElec = 0.0
  428. else:
  429. actualNeedTime = usedTime + leftTime
  430. leftTimeStr = leftTime
  431. if 'alt_tech_refund_mode' in agent.features and billingType == 'time':
  432. needTime = lineInfo['needTime']
  433. # 剩余时间不满 60 按照 0 算, 不满 120 按照 60 算...
  434. calcleftTime = (int(leftTime) // 60) * 60
  435. backCoins = money * (float(calcleftTime) / float(actualNeedTime))
  436. else:
  437. # TODO 整改退费 哪个时间电量取小的
  438. needTime = lineInfo['needTime']
  439. backCoins = money * (float(leftTime) / float(actualNeedTime))
  440. # elif billingType == 'time':
  441. # needTime = lineInfo['needTime']
  442. # backCoins = money * (float(leftTime) / float(actualNeedTime))
  443. # else:
  444. # needElec, elec = Decimal(lineInfo.get('needElec', 1000)), Decimal(str(lineInfo.get('elec')))
  445. # ratio = (needElec - elec) / needElec
  446. # backCoins = VirtualCoin(money.amount - money.amount * ratio)
  447. backCoins = VirtualCoin(min(float(backCoins), float(backCoins_by_elec)))
  448. isRefundProtection = False
  449. if usedTime < refundProtectionTime:
  450. backCoins = money
  451. isRefundProtection = True
  452. if backCoins > money:
  453. backCoins = money
  454. refundRMB = price * (float(backCoins) / float(money))
  455. logger.debug(
  456. 'refund money is: {}; refund rmb is: {}'.format(str(backCoins.amount), str(refundRMB.amount)))
  457. #: 扫码的方式
  458. if cardId == '' and vCardId is None and consumeType != 'coin':
  459. logger.info('finished with netPay')
  460. #: 这里需要考虑API调用的和普通使用场景
  461. if 'extOrderNo' in lineInfo:
  462. record = APIStartDeviceRecord.get_api_record(self.device['logicalCode'], lineInfo['extOrderNo'])
  463. if not record:
  464. logger.debug('cannot find api start device record')
  465. return
  466. if record.postActionTriggered:
  467. logger.debug('api({}) post action has done.'.format(lineInfo['extOrderNo']))
  468. return
  469. # 中天的结束状态匹配
  470. reasonCode = self.event_data['reasonCode']
  471. if reasonCode == '0B':
  472. reasonCode = '03'
  473. elif reasonCode == '03':
  474. reasonCode = '04'
  475. else:
  476. pass
  477. # 中天空载需要这样写
  478. if leftTime == 65535:
  479. leftTime = lineInfo['needTime']
  480. report_zhongtian_service_complete(
  481. event_code = '16',
  482. record = record,
  483. orderNo = lineInfo['extOrderNo'],
  484. deviceCode = self.device['logicalCode'],
  485. groupName = group['groupName'],
  486. address = group['address'],
  487. actualNeedTime = lineInfo['needTime'],
  488. leftTime = leftTime,
  489. finishedState = reasonCode
  490. )
  491. record.update(servicedInfo = {'spendElec': str(spendElec), 'backCoins': '0'})
  492. if self.device.is_auto_refund:
  493. coins = VirtualCoin(lineInfo['coins'])
  494. money = RMB(lineInfo['price'])
  495. backCoins = self.get_backCoins(coins = coins, leftTime = leftTime,
  496. actualNeedTime = lineInfo['needTime'])
  497. backMoney = self.get_backMoney(money = money, leftTime = leftTime,
  498. actualNeedTime = lineInfo['needTime'])
  499. report_zhongtian_refund(
  500. eventCode = '16',
  501. record = record,
  502. orderNo = lineInfo['extOrderNo'],
  503. deviceCode = self.device['logicalCode'],
  504. groupName = group['groupName'],
  505. address = group['address'],
  506. backMoney = str(backMoney),
  507. backCoins = str(backCoins),
  508. actualNeedTime = lineInfo['needTime'],
  509. leftTime = leftTime,
  510. finishedState = reasonCode
  511. )
  512. record.update(servicedInfo = {'spendElec': str(spendElec), 'backCoins': str(backCoins)})
  513. else:
  514. openId = lineInfo['openId']
  515. user = MyUser.objects(openId = openId, groupId = self.device['groupId']).first()
  516. leftTimeStr = leftTime if leftTime != 65535 else u'空载'
  517. # todo 生成模板所需要的所有参数, 后续有客户自定义的话, 直接在这个字典里面添加, 不需要删掉之前的.
  518. # todo 这个变量仅仅用于下面generate_service_complete_title_by_devType()函数的参. 做成配置项更好, 下次不用改代码.
  519. templateMap = {
  520. 'reason': self.event_data['reason'],
  521. 'logicalCode': self.device['logicalCode'],
  522. 'port': self.event_data['port'],
  523. 'address': group['address'],
  524. 'actualNeedTime': actualNeedTime,
  525. 'leftTimeStr': leftTimeStr
  526. }
  527. # 先去获取devType上面的模板, 如果没有就走正常的流程
  528. title = self.generate_service_complete_title_by_devType(self.device['devType']['id'], templateMap)
  529. if title == '':
  530. billingType = lineInfo.get('billingType', 'time')
  531. if billingType == 'time':
  532. title = u'\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n设备地址:\\t\\t{address}\\n\\n消费时间:\\t\\t动态功率计算{actualNeedTime}分钟\\n\\n剩余时间:\\t\\t{leftTimeStr}分钟'.format(
  533. reason = self.event_data['reason'],
  534. logicalCode = self.device['logicalCode'],
  535. port = self.event_data['port'],
  536. address = group['address'],
  537. actualNeedTime = actualNeedTime,
  538. leftTimeStr = leftTimeStr
  539. )
  540. else:
  541. title = u'\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n设备地址:\\t\\t{address}\\n\\n购买电量:\\t\\t{needElec}\\n\\n消耗电量:\\t\\t{spendElec}'.format(
  542. reason = self.event_data['reason'],
  543. logicalCode = self.device['logicalCode'],
  544. port = self.event_data['port'],
  545. address = group['address'],
  546. needElec = lineInfo.get('needElec', 1000),
  547. spendElec = spendElec)
  548. self.notify_user(
  549. managerialOpenId = user.managerialOpenId if user else '',
  550. templateName = 'service_complete',
  551. title = title,
  552. service = u'充电服务',
  553. finishTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  554. remark = u'谢谢您的支持')
  555. consumeDict = {
  556. 'chargeIndex': lineInfo['port'],
  557. 'reason': lineInfo['reason'],
  558. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  559. 'duration': usedTime
  560. }
  561. if billingType == 'time':
  562. leftTimeStr = leftTime if leftTime != 65535 else lineInfo['needTime']
  563. consumeDict.update(
  564. {'leftTime': leftTimeStr, 'needTime': u'扫码订购%s分钟' % lineInfo['needTime']})
  565. consumeDict.update({'elec': spendElec})
  566. else:
  567. consumeDict.update({'needElec': lineInfo['needElec']})
  568. consumeDict.update({'elec': spendElec})
  569. consumeDict.update({'elecFee': self.calc_elec_fee(spendElec)})
  570. need_refund = False
  571. if not group.get('isFree', False):
  572. if isTempPackage is True:
  573. if isRefundProtection is True:
  574. need_refund = True
  575. else:
  576. pass
  577. elif self.device.is_auto_refund:
  578. need_refund = True
  579. elif isRefundProtection is True:
  580. need_refund = True
  581. else:
  582. pass
  583. if self.event_data['elec'] == 0 or self.event_data['leftTime'] == 0:
  584. need_refund = False
  585. else:
  586. pass
  587. if not need_refund:
  588. ServiceProgress.update_progress_and_consume_rcd(
  589. self.device['ownerId'],
  590. {
  591. 'open_id': openId, 'device_imei': self.device['devNo'],
  592. 'port': lineInfo['port'], 'isFinished': False
  593. },
  594. consumeDict
  595. )
  596. else:
  597. if isTempPackage:
  598. self.refund_net_pay(user, lineInfo, refundRMB, VirtualCoin(0), consumeDict, True)
  599. else:
  600. self.refund_net_pay(user, lineInfo, refundRMB, backCoins, consumeDict,
  601. ('refundRMB_device_event' in dealer.features))
  602. ServiceProgress.update_progress_and_consume_rcd(
  603. self.device['ownerId'],
  604. {
  605. 'open_id': openId, 'device_imei': self.device['devNo'],
  606. 'port': lineInfo['port'], 'isFinished': False
  607. },
  608. consumeDict)
  609. if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
  610. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  611. 'title': u'充电已经完成',
  612. 'backCount': u'%s(金币)' % str(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS]),
  613. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  614. })
  615. elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
  616. self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{
  617. 'title': u'充电已经完成',
  618. 'backCount': u'%s(元)' % str(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH]),
  619. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  620. })
  621. elif vCardId is not None:
  622. # 使用的是虚拟卡
  623. logger.info('finished with vCard!')
  624. billingType = lineInfo.get('billingType', 'time')
  625. if billingType == 'time':
  626. leftTimeStr = leftTime if leftTime != 65535 else lineInfo['needTime']
  627. title = u'\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n设备地址:\\t\\t{address}\\n\\n消费时间:\\t\\t动态功率计算{actualNeedTime}分钟\\n\\n剩余时间:\\t\\t{leftTimeStr}分钟'.format(
  628. reason = self.event_data['reason'],
  629. logicalCode = self.device['logicalCode'],
  630. port = self.event_data['port'],
  631. address = group['address'],
  632. actualNeedTime = actualNeedTime,
  633. leftTimeStr = leftTimeStr
  634. )
  635. else:
  636. title = u'\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n设备地址:\\t\\t{address}\\n\\n购买电量:\\t\\t{needElec}\\n\\n消耗电量:\\t\\t{spendElec}'.format(
  637. reason = self.event_data['reason'],
  638. logicalCode = self.device['logicalCode'],
  639. port = self.event_data['port'],
  640. address = group['address'],
  641. needElec = lineInfo.get('needElec', 1000),
  642. spendElec = spendElec
  643. )
  644. # 通知充电完成
  645. try:
  646. vCard = UserVirtualCard.objects.get(id = vCardId)
  647. except DoesNotExist:
  648. logger.info('can not find the vCard id = %s' % vCardId)
  649. return
  650. self.notify_user(
  651. managerialOpenId = self.get_managerialOpenId_by_openId(lineInfo['openId']),
  652. templateName = 'service_complete',
  653. title = title,
  654. service = u'充电服务',
  655. finishTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  656. remark = u'谢谢您的支持'
  657. )
  658. consumeDict = {'chargeIndex': lineInfo['port'],
  659. 'reason': lineInfo['reason'],
  660. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  661. 'duration': usedTime}
  662. consumeDict.update({'elec': spendElec})
  663. if billingType != 'time':
  664. consumeDict.update({'elec': spendElec})
  665. consumeDict.update({'elecFee': self.calc_elec_fee(spendElec)})
  666. ServiceProgress.update_progress_and_consume_rcd(
  667. self.device['ownerId'],
  668. {'open_id': lineInfo['openId'], 'device_imei': self.device['devNo'],
  669. 'port': lineInfo['port'], 'isFinished': False}, consumeDict
  670. )
  671. consumeRcdId = lineInfo.get('consumeRcdId', None)
  672. if consumeRcdId is None:
  673. logger.info('can not find consume rcd id')
  674. return
  675. # 尝试进行虚拟卡退费
  676. try:
  677. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  678. except DoesNotExist, e:
  679. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  680. else:
  681. vCard.refund_quota(vCardConsumeRcd, usedTime, spendElec, backCoins.mongo_amount)
  682. elif cardId != '':
  683. # 刷的实体卡
  684. logger.info('finished with card')
  685. card = Card.objects.get(id = cardId)
  686. virtual_card = card.bound_virtual_card # type: UserVirtualCard
  687. if billingType == 'time':
  688. logger.info('billingType is time.')
  689. self.notify_user(
  690. managerialOpenId = card.managerialOpenId,
  691. templateName = 'service_complete',
  692. title = u'\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n设备地址:\\t\\t{address}\\n\\n消费卡号:\\t\\t{cardNo}\\n\\n持卡姓名:\\t\\t{cardName}\\n\\n消费时间:\\t\\t动态功率计算{actualNeedTime}分钟\\n\\n剩余时间:\\t\\t{leftTimeStr}分钟'.format(
  693. reason = self.event_data['reason'],
  694. logicalCode = self.device['logicalCode'],
  695. port = self.event_data['port'],
  696. address = group['address'],
  697. cardNo = card.cardNo,
  698. cardName = card.cardName,
  699. actualNeedTime = actualNeedTime,
  700. leftTimeStr = leftTimeStr
  701. ),
  702. service = u'充电服务',
  703. finishTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  704. remark = u'谢谢您的支持')
  705. consumeDict = {
  706. 'chargeIndex': lineInfo['port'],
  707. 'leftTime': leftTimeStr,
  708. 'needTime': u'刷卡订购%s分钟' % needTime if virtual_card is None else u'绑定虚拟卡订购%s分钟' % needTime,
  709. 'reason': lineInfo['reason'],
  710. 'duration': usedTime,
  711. 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
  712. 'elec': spendElec,
  713. 'elecFee': self.calc_elec_fee(spendElec)
  714. }
  715. if virtual_card:
  716. self.refund_virtual_card(backCoins, cardId, consumeDict, lineInfo, spendElec, usedTime,
  717. virtual_card)
  718. elif is_server_refund(billingType, self.device, dealer, agent):
  719. logger.info(
  720. 'ready to server refund money <{}> for user card <{}> in device<{}>'.format(
  721. backCoins,
  722. str(card.id),
  723. self.device.devNo))
  724. consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backCoins.mongo_amount})
  725. ServiceProgress.update_progress_and_consume_rcd(
  726. self.device['ownerId'],
  727. {
  728. 'cardId': cardId,
  729. 'device_imei': self.device['devNo'],
  730. 'port': lineInfo['port'],
  731. 'isFinished': False
  732. },
  733. consumeDict)
  734. self.refund_money_for_card(backCoins, str(card.id))
  735. desc = u'您使用的%s号端口充电,共付款:%s元,充电预定时间为:%s分钟,使用:%s分钟,给您退款:%s元' % (
  736. lineInfo['port'], money, actualNeedTime, usedTime, backCoins)
  737. self.notify_user(card.managerialOpenId if card else '', 'refund_coins', **{
  738. 'title': desc,
  739. 'backCount': u'金币:%s' % backCoins,
  740. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
  741. else:
  742. ServiceProgress.update_progress_and_consume_rcd(
  743. self.device['ownerId'],
  744. {
  745. 'cardId': cardId,
  746. 'device_imei': self.device['devNo'],
  747. 'port': lineInfo['port'],
  748. 'isFinished': False
  749. },
  750. consumeDict)
  751. else:
  752. logger.info('billingType is elec')
  753. self.notify_user(
  754. managerialOpenId = card.managerialOpenId,
  755. templateName = 'service_complete',
  756. title = u'\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n设备地址:\\t\\t{address}\\n\\n消费卡号:\\t\\t{cardNo}\\n\\n持卡姓名:\\t\\t{cardName}\\n\\n购买电量:\\t\\t{needElec}\\n\\n消耗电量:\\t\\t{spendElec}'.format(
  757. reason = self.event_data['reason'],
  758. logicalCode = self.device['logicalCode'],
  759. port = self.event_data['port'],
  760. address = group['address'],
  761. cardNo = card.cardNo,
  762. cardName = card.cardName,
  763. needElec = lineInfo.get('needElec'),
  764. spendElec = spendElec
  765. ),
  766. service = u'充电服务',
  767. finishTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  768. remark = u'谢谢您的支持')
  769. consumeDict = {
  770. 'chargeIndex': lineInfo['port'],
  771. 'leftTime': leftTimeStr,
  772. 'reason': lineInfo['reason'],
  773. 'elec': spendElec,
  774. 'elecFee': self.calc_elec_fee(spendElec),
  775. 'duration': usedTime,
  776. 'needElec': lineInfo['needElec']
  777. }
  778. if virtual_card:
  779. self.refund_virtual_card(backCoins, cardId, consumeDict, lineInfo, spendElec, usedTime,
  780. virtual_card)
  781. elif is_server_refund(billingType, self.device, dealer, agent):
  782. logger.info(
  783. 'ready to server refund money <{}> for user card <{}> in device<{}>'.format(
  784. backCoins,
  785. str(card.id),
  786. self.device.devNo))
  787. self.refund_money_for_card(backCoins, str(card.id))
  788. consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backCoins.mongo_amount})
  789. desc = u'您使用的%s号端口充电,共付款:%s元,充电预定电量为:%s度,使用:%s度,给您退款:%s元' % (
  790. lineInfo['port'], money, lineInfo.get('needElec', 0.0), spendElec, backCoins)
  791. self.notify_user(card.managerialOpenId if card else '', 'refund_coins', **{
  792. 'title': desc,
  793. 'backCount': u'金币:%s' % backCoins,
  794. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  795. })
  796. else:
  797. logger.info('device not open refund switch')
  798. ServiceProgress.update_progress_and_consume_rcd(
  799. self.device['ownerId'],
  800. {'cardId': cardId, 'device_imei': self.device['devNo'],
  801. 'port': lineInfo['port'], 'isFinished': False}, consumeDict
  802. )
  803. elif consumeType == 'coin': #: 消费类型为金币,则
  804. logger.info('finished with coin')
  805. CoinConsumeRcd = ConsumeRecord.objects.get(orderNo = lineInfo['consumeOrderNo']) # type: ConsumeRecord
  806. CoinConsumeRcd.servicedInfo['elec'] = spendElec
  807. CoinConsumeRcd.servicedInfo['actualNeedTime'] = u'动态功率计算为%s分钟' % actualNeedTime
  808. CoinConsumeRcd.servicedInfo['needTime'] = u'投币订购%s分钟' % needTime
  809. CoinConsumeRcd.servicedInfo['reason'] = lineInfo['reason']
  810. CoinConsumeRcd.servicedInfo['chargeIndex'] = lineInfo['port']
  811. CoinConsumeRcd.finishedTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  812. CoinConsumeRcd.save()
  813. valueDict = {'duration': usedTime}
  814. valueDict = {
  815. DEALER_CONSUMPTION_AGG_KIND.ELEC: spendElec,
  816. DEALER_CONSUMPTION_AGG_KIND.ELECFEE: self.calc_elec_fee(spendElec)
  817. }
  818. status = CoinConsumeRcd.update_agg_info(valueDict)
  819. if status:
  820. record_consumption_stats(CoinConsumeRcd)
  821. else:
  822. logger.error(
  823. '[update_progress_and_consume_rcd] failed to update_agg_info record=%r' % (
  824. CoinConsumeRcd,))
  825. except Exception as e:
  826. logger.exception('deal with jingneng devNo=%s event e=%s' % (devNo, e))
  827. finally:
  828. Device.clear_port_control_cache(devNo, str(self.event_data['port']))
  829. dataDict = {'backMoney': str(refundRMB.mongo_amount), 'backCoins': str(backCoins.mongo_amount)}
  830. if lineInfo.has_key('orderNo'):
  831. dataDict.update({'orderNo': lineInfo['orderNo']})
  832. notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL,
  833. desc = self.event_data['reason'], dataDict = dataDict)
  834. send_event_to_zhejiang(self.dealer, self.device, self.event_data)
  835. #: 启动了端口,主要记录下投币数据
  836. elif cmdCode == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20:
  837. consumeType = self.event_data['consumeType']
  838. if consumeType == 'coin':
  839. self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  840. # 记录该端口累计需要的时间和钱,cardId
  841. Device.update_port_control_cache(self.device['devNo'], self.event_data)
  842. Accounting.recordOfflineCoin(self.device,
  843. int(time.time()),
  844. int(self.event_data['coins']))
  845. self.event_data.update({'needElec': self.event_data['elec']})
  846. self.event_data.update({'consumeOrderNo': self.record_consume_for_coin(RMB(self.event_data['coins']))})
  847. Device.update_port_control_cache(self.device['devNo'], self.event_data)
  848. elif consumeType == 'card':
  849. port = self.event_data['port']
  850. consumeDict = {'chargeIndex': port, 'elec': self.event_data['elec'],
  851. 'money': self.event_data['coins'], 'needTime': u'刷卡订购%s分钟' % self.event_data['needTime']}
  852. queryDict = {'device_imei': self.device['devNo'],
  853. 'port': -1, 'isFinished': False,
  854. 'cardId': {'$ne': ''}, 'start_time': {'$gte': int(time.time()) - 3600}}
  855. progressDict = {'port': port}
  856. ServiceProgress.update_progress_and_consume_rcd(ownerId = self.device['ownerId'], queryDict = queryDict,
  857. consumeDict = consumeDict, updateConsume = True,
  858. progressDict = progressDict)
  859. # 找出对应的卡的ID记录到端口内存数据
  860. queryDict.update(progressDict)
  861. rcds = ServiceProgress.get_collection().find(queryDict, {'cardId': 1, 'open_id': 1, 'consumeOrder': 1},
  862. sort = [('start_time', -1)])
  863. if rcds.count() == 0:
  864. return
  865. rcd = rcds[0]
  866. dev = Device.objects.get(devNo = self.device['devNo'])
  867. billingType = dev.otherConf.get('billingType', 'time')
  868. # 刷卡虚拟卡启动的时候,将consumeRcd 写入到缓存 退费的时候使用
  869. consumeRcdId = rcd.get('consumeOrder', dict()).get('consumeRcdId')
  870. if consumeRcdId:
  871. self.event_data.update({'consumeRcdId': consumeRcdId})
  872. self.event_data.update({'billingType': billingType})
  873. self.event_data.update({'cardId': rcd['cardId']})
  874. self.event_data.update({'openId': rcd['open_id']})
  875. cInfo = Device.get_dev_control_cache(devNo)
  876. lastPortInfo = cInfo.get(str(port), {})
  877. # 钱需要累计
  878. lastCoins = lastPortInfo.get('coins', 0.0)
  879. self.event_data.update({'coins': self.event_data['coins'] + lastCoins})
  880. # 电量需要累加
  881. lastNeedElec = lastPortInfo.get('needElec', 0.0)
  882. self.event_data.update({'needElec': self.event_data['elec'] + lastNeedElec})
  883. # 时间需要累加
  884. lastNeedTime = lastPortInfo.get('needTime', 0.0)
  885. self.event_data.update({'needTime': self.event_data['needTime'] + lastNeedTime})
  886. self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  887. self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
  888. #: 记录该端口累计需要的时间和钱,cardId
  889. Device.update_port_control_cache(self.device['devNo'], self.event_data)
  890. elif consumeType == 'server':
  891. port = self.event_data['port']
  892. #: 记录该端口累计需要的时间和钱
  893. Device.update_port_control_cache(self.device['devNo'], self.event_data)
  894. consumeDict = {'chargeIndex': self.event_data['port'], 'elec': self.event_data['elec'],
  895. 'needTime': u'订购%s分钟' % self.event_data['needTime']}
  896. queryDict = {'device_imei': self.device['devNo'],
  897. 'port': port, 'isFinished': False,
  898. 'start_time': {'$gte': int(time.time()) - 3600}}
  899. progressDict = {'port': self.event_data['port']}
  900. ServiceProgress.update_progress_and_consume_rcd(ownerId = self.device['ownerId'],
  901. queryDict = queryDict, consumeDict = consumeDict,
  902. updateConsume = True, progressDict = progressDict)
  903. # todo 功率过低告警还没做完
  904. # openId = self.curDevInfo['openId']
  905. # if openId is not None:
  906. # user = MyUser.objects(openId=openId, groupId = self.device['groupId']).first()
  907. #
  908. # report_to_user_low_power_wechat.delay(self.notify_low_power_to_user(user, 1, 20), 15)
  909. elif cmdCode == '2D':
  910. self._do_charge_consume()
  911. elif cmdCode == '2C':
  912. self._do_coin_finished()
  913. else:
  914. raise NoCommandHandlerAvailable(
  915. '[JNDZ]] no command handler for cmd %s, curDevInfo=%s' % (cmdCode, self.event_data))
  916. def _do_charge_consume(self):
  917. if self.event_data.get("result", '00') == '00':
  918. logger.info("receive failure card charge data <{}>".format(self.event_data.get("sourceData", '')))
  919. return
  920. # 回复主板是正常的2D指令
  921. sessionId = self.event_data.get("sessionId")
  922. self.deviceAdapter._response_to_2D("{:0>10}".format(sessionId))
  923. # 判断是否这个 sessionId 是否已经被执行 判断方式是该端口中是否有这个 sessionId
  924. portStr = self.event_data.get("portStr")
  925. if not portStr:
  926. logger.info("receive card charge data <{}> without port !".format(self.event_data.get("sourceData", '')))
  927. return
  928. portCache = Device.get_dev_control_cache(self.device.devNo).get(portStr, dict())
  929. if portCache.get("status", Const.DEV_WORK_STATUS_WORKING) == Const.DEV_WORK_STATUS_WORKING and portCache.get(
  930. "sessionId") == sessionId:
  931. logger.info(
  932. "receive card charge data <{}> has been handle, <{}>!".format(self.event_data.get("sourceData", ''),
  933. sessionId))
  934. return
  935. # 接下来判断上传成功启动的类别 由硬币/卡类型决定
  936. chargeType = self.event_data.get("chargeType")
  937. if chargeType == "00":
  938. self._charge_with_coin()
  939. elif chargeType == "01":
  940. self._charge_with_card()
  941. elif chargeType == "02":
  942. self._charge_with_remote()
  943. else:
  944. logger.info("card recharge type <{}> undefined! <{}>".format(chargeType, self.event_data.get("sourceData")))
  945. def refund_virtual_card(self, backCoins, cardId, consumeDict, lineInfo, spendElec, usedTime, virtual_card):
  946. logger.debug('server refund for virtual card<{}> in device<{}>'.format(
  947. str(virtual_card.id),
  948. self.device.devNo))
  949. ServiceProgress.update_progress_and_consume_rcd(
  950. self.device['ownerId'],
  951. {
  952. 'cardId': cardId,
  953. 'device_imei': self.device['devNo'],
  954. 'port': lineInfo['port'],
  955. 'isFinished': False
  956. },
  957. consumeDict)
  958. consumeRcdId = lineInfo.get('consumeRcdId', None)
  959. # 不是虚拟卡启动的直接结束掉
  960. if consumeRcdId:
  961. # 尝试进行虚拟卡退费
  962. try:
  963. vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId)
  964. except DoesNotExist, e:
  965. logger.info('can not find the consume rcd id = %s' % consumeRcdId)
  966. else:
  967. virtual_card.refund_quota(vCardConsumeRcd, usedTime, spendElec,
  968. backCoins.mongo_amount)
  969. else:
  970. logger.info('can not find consume rcd id')
  971. def response_use_card(self, res, leftBalance):
  972. # 启动失败需要把金币还回去
  973. try:
  974. self.deviceAdapter.response_use_card(res, leftBalance)
  975. except ServiceException as e:
  976. logger.exception(e)
  977. def do_id_response_support_reliable(self, **args):
  978. # TODO 预扣请求和余额回收,此处进行验证,通过则下发可以开启设备
  979. cardNo = self.event_data['cardNo']
  980. cardHex = self.event_data['sourceData'][8:16]
  981. fee = self.event_data['preFee']
  982. oper = self.event_data['oper']
  983. logger.info('Check card can be used cardNo={} ,cardHex={} fee={} oper={}'.format(cardNo, cardHex, fee, oper))
  984. # 进来的时候检查过卡是否存在这里校验卡的合法型
  985. card = self.update_card_dealer_and_type(cardNo)
  986. if not card or not card.openId or card.frozen:
  987. self.deviceAdapter.response_card(2, 0, fee, oper, cardHex)
  988. return
  989. # 2.检查卡片充值订单是否存在
  990. card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
  991. result = self.recharge_id_card(card=card,
  992. rechargeType='append',
  993. order=card_recharge_order)
  994. card.reload()
  995. logger.info('JingNengDianZi cmdNo(10) - cardNo=%s, openId=%s, result=%s, preFee=%s, curinfo=%s' % (
  996. cardNo, card.openId, result, fee, self.event_data))
  997. virtual_card = self._get_virtual_card_by_card(card)
  998. # 3.检查当前操作为是否为扣费还是余额回收(00:扣费,01:充值)
  999. if oper == SWIPE_CARD_PARAM_OP.DECR_00:
  1000. # 先检查虚拟卡是否能使用
  1001. leftCount = self._check_virtual_card_can_use_today(virtual_card, fee)
  1002. if leftCount:
  1003. return self.deviceAdapter.response_card(0, leftCount, fee, oper, cardHex, isVir=True , virtual_card_id=str(virtual_card.id))
  1004. # 校验实体卡能否使用
  1005. elif self._check_card_balance_can_use_today(card, fee):
  1006. return self.deviceAdapter.response_card(0, card.balance, fee, oper, cardHex)
  1007. else:
  1008. return self.deviceAdapter.response_card(1, card.balance, fee, oper, cardHex)
  1009. elif oper == SWIPE_CARD_PARAM_OP.INCR_01:
  1010. if virtual_card:
  1011. logger.debug('virtual card is not do device refund...')
  1012. return
  1013. dev = Device.objects.get(devNo=self.device['devNo'])
  1014. dealer = self.device.owner
  1015. if not dealer:
  1016. logger.error('dealer is not found, dealerId=%s' % self.device.ownerId)
  1017. return
  1018. agent = Agent.objects(id=dealer.agentId).first()
  1019. if not agent:
  1020. logger.error('agent is not found, agentId=%s' % dealer.agentId)
  1021. return
  1022. res = SWIPE_CARD_RES.SUCCESS_00
  1023. billingType = dev.otherConf.get('billingType', 'time')
  1024. if is_server_refund(billingType, self.device, dealer, agent):
  1025. logger.debug('{} in {} has card refund by server refund.'.format(repr(card), repr(self.device)))
  1026. return
  1027. logger.debug('{} card refund by {}.'.format(repr(card), repr(self.device)))
  1028. self.response_use_card(res, card.balance.mongo_amount + fee)
  1029. self.refund_money_for_card(fee, str(card.id))
  1030. self.notify_user(card.managerialOpenId, 'refund_coins', **{
  1031. 'title': u'退币完成!!!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
  1032. 'backCount': u'金币:%s' % fee,
  1033. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  1034. })
  1035. def _get_virtual_card_by_card(self, card):
  1036. if not card.openId or float(card.balance) != 0:
  1037. return
  1038. try:
  1039. dealer = self.device.owner
  1040. agent = Agent.objects.get(id=dealer.agentId)
  1041. features = agent.features
  1042. except Exception as e:
  1043. features = []
  1044. return card.bound_virtual_card if 'vCardNeedBind' in features else card.related_virtual_card
  1045. def _check_virtual_card_can_use_today(self, virtual_card, fee):
  1046. # 如果虚拟卡已经绑定,需要检查下今天是否可用,如果可用,有限使用虚拟卡
  1047. if virtual_card:
  1048. unit = self.device['washConfig'].get('1', {}).get('unit','分钟')
  1049. if unit == '分钟':
  1050. cardMin = self.device['otherConf'].get('cardMin', 180)
  1051. package = {'coins': float(fee), 'unit': unit, 'time': int(cardMin)}
  1052. elif unit == '度':
  1053. cardMin = self.device['otherConf'].get('cardMin', 180)
  1054. package = {'coins': float(fee), 'unit': unit, 'time': int(cardMin)}
  1055. else:
  1056. return 0
  1057. if virtual_card.can_use_today(package):
  1058. dayKey = datetime.datetime.now().strftime('%Y-%m-%d')
  1059. leftDayQuota = virtual_card.calc_left_day_quota(dayKey)
  1060. left_count = virtual_card.find_match_unit_and_can_use_count(leftDayQuota, package)
  1061. return left_count
  1062. def _check_card_balance_can_use_today(self, card, fee):
  1063. if float(card.balance) >= fee:
  1064. return True
  1065. else:
  1066. return False
  1067. def _charge_with_card(self):
  1068. """
  1069. 充值卡 的充值
  1070. :return:
  1071. """
  1072. cardType = self.event_data.get("cardType")
  1073. if cardType == CARD_TYPE.OFFLINE_CARD:
  1074. self._charge_with_offline_card()
  1075. elif cardType == CARD_TYPE.ONLINE_CARD:
  1076. self._charge_with_online_card()
  1077. elif cardType == CARD_TYPE.MONTHLY_CARD:
  1078. self._charge_with_monthly_card()
  1079. elif cardType == CARD_TYPE.FULL_CARD:
  1080. self._charge_with_full_card()
  1081. else:
  1082. logger.info(
  1083. "card recharge card type <{}> undefined! <{}>".format(cardType, self.event_data.get("sourceData")))
  1084. def _charge_with_coin(self):
  1085. """
  1086. 投币的上报
  1087. :return:
  1088. """
  1089. port = self.event_data.get('portStr')
  1090. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  1091. lineInfo = ctrInfo.get(port, {})
  1092. if lineInfo.get('status', 0) == Const.DEV_WORK_STATUS_WORKING and lineInfo.get('consumeType') == 'coin': #续充
  1093. lineInfo['coins'] += self.event_data.get('coins', 0)
  1094. lineInfo['needTime'] += self.event_data.get('time', 0)
  1095. lineInfo['needElec'] += self.event_data.get('elec', 0)
  1096. if 'sub_orderNo' in lineInfo:
  1097. lineInfo['sub_orderNo'].append( self.record_consume_for_coin(RMB(self.event_data['coins'])))
  1098. else:
  1099. lineInfo['sub_orderNo'] = [self.record_consume_for_coin(RMB(self.event_data['coins'])),]
  1100. else:
  1101. lineInfo = {
  1102. 'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT),
  1103. 'port': port,
  1104. 'coins': self.event_data.get('coins', 0),
  1105. 'needTime': self.event_data.get('time', 0),
  1106. 'needElec': self.event_data.get('elec', 0),
  1107. 'consumeOrderNo': self.record_consume_for_coin(RMB(self.event_data['coins'])),
  1108. 'consumeType': 'coin',
  1109. 'isStart': True,
  1110. 'status': Const.DEV_WORK_STATUS_WORKING,
  1111. 'sessionId': self.event_data.get('sessionId'),
  1112. }
  1113. # 记录该端口累计需要的时间和钱,cardId
  1114. Device.update_port_control_cache(self.device['devNo'], lineInfo)
  1115. Accounting.recordOfflineCoin(self.device,
  1116. int(time.time()),
  1117. int(self.event_data.get('coins', 0)))
  1118. def _charge_with_remote(self):
  1119. logger.info("not supper charge type! {}".format(self.event_data))
  1120. def _charge_with_online_card(self):
  1121. """
  1122. 在线卡启动充值
  1123. :return:
  1124. """
  1125. portStr = self.event_data.get("portStr")
  1126. needElec = self.event_data.get("elec", 0)
  1127. cardNo = self.event_data.get("cardNo")
  1128. cardCst = self.event_data.get("cardCst")
  1129. card = self.update_card_dealer_and_type(cardNo)
  1130. if not card or not card.openId or card.frozen:
  1131. logger.warning("error card, cardNo is {}".format(cardNo))
  1132. return
  1133. res, cardBalance = self.consume_money_for_card(card, RMB(cardCst))
  1134. if res != 1:
  1135. logger.warning("consume error!!!, cardNo is {}".format(cardNo))
  1136. return
  1137. consumeDict = {
  1138. "chargeIndex": portStr,
  1139. "needElec": needElec
  1140. }
  1141. orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(cardCst), servicedInfo=consumeDict)
  1142. portCache = {
  1143. "isStart": True,
  1144. "status": Const.DEV_WORK_STATUS_WORKING,
  1145. "openId": card.openId,
  1146. "price": cardCst,
  1147. "coins": cardCst,
  1148. "needElec": needElec,
  1149. "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  1150. "startTimeStamp": int(time.time()),
  1151. "consumeType": "card",
  1152. }
  1153. Device.update_dev_control_cache(self.device.devNo, {portStr: portCache})
  1154. ServiceProgress.register_card_service(
  1155. self.device,
  1156. int(portStr),
  1157. card,
  1158. consumeOrder={
  1159. "orderNo": orderNo,
  1160. "cardOrderNo": cardOrderNo,
  1161. }
  1162. )
  1163. def _charge_with_offline_card(self):
  1164. """
  1165. 离线卡启动充值
  1166. :return:
  1167. """
  1168. pass
  1169. def _charge_with_monthly_card(self):
  1170. """
  1171. 包月在线卡启动
  1172. :return:
  1173. """
  1174. logger.info("not supper card charge type! {}".format(self.event_data))
  1175. def _charge_with_full_card(self):
  1176. """
  1177. 充满自停卡
  1178. :return:
  1179. """
  1180. logger.info("not supper card charge type! {}".format(self.event_data))
  1181. def _do_coin_finished(self):
  1182. port = str(self.event_data.get('port'))
  1183. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  1184. lineInfo = ctrInfo.get(port, {})
  1185. now = datetime.datetime.now()
  1186. if lineInfo and lineInfo.get('consumeType') == 'coin': # 只处理投币结束
  1187. if 'consumeOrderNo' in lineInfo:
  1188. order = ConsumeRecord.objects.filter(orderNo=lineInfo['consumeOrderNo']).first()
  1189. if 'duration' in self.event_data and self.event_data['duration'] > 0:
  1190. usedTime = self.event_data['duration']
  1191. else:
  1192. startTime = to_datetime(lineInfo['startTime'])
  1193. nowTime = datetime.datetime.now()
  1194. if startTime > nowTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
  1195. usedTime = 0
  1196. else:
  1197. usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
  1198. actualNeedTime = usedTime + self.event_data.get('leftTime', 0)
  1199. consumeDict = {
  1200. 'chargeIndex': port,
  1201. 'reason': self.event_data.get('reasonDesc', ''),
  1202. 'totalCount': lineInfo.get('coins', 0),
  1203. 'needTime': lineInfo.get('needTime', 0),
  1204. 'leftTime': self.event_data.get('leftTime', 0),
  1205. 'leftElec': self.event_data.get('leftElec', 0),
  1206. 'actualNeedTime': actualNeedTime,
  1207. }
  1208. order.update_service_info(consumeDict)
  1209. ConsumeRecord.objects.filter(orderNo=lineInfo['consumeOrderNo']).update(status='finished',
  1210. finishedTime=now)
  1211. if 'sub_orderNo' in lineInfo:
  1212. subConsumeDict = {
  1213. 'desc': '关联主单号:{}'.format(order.orderNo)
  1214. }
  1215. ConsumeRecord.objects.filter(orderNo__in=lineInfo['sub_orderNo']).update(status='finished', finishedTime=now,
  1216. servicedInfo=subConsumeDict)
  1217. Device.clear_port_control_cache(self.device.devNo, port)
  1218. class ChargingJNDZReportEvent(WorkEvent):
  1219. def do(self, **args):
  1220. # if not self.device.get('otherConf', {}).get('need_save_upload_data', None):
  1221. # logger.info('No need to record!!!')
  1222. # return
  1223. portNum = self.event_data.get('portNum')
  1224. portInfo = self.event_data.get('portInfo')
  1225. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  1226. now = datetime.datetime.now()
  1227. for port, one_info in portInfo.items():
  1228. if one_info.get('portStatus') == '02':
  1229. lineInfo = ctrInfo.get(port, {})
  1230. orderNo = lineInfo.get('orderNo')
  1231. if not orderNo:
  1232. continue
  1233. try:
  1234. order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
  1235. if hasattr(order, 'upload_data'):
  1236. upload_data = order.upload_data
  1237. else:
  1238. upload_data = []
  1239. one_info['upload_time'] = now.strftime('%Y-%m-%d %H:%M:%S')
  1240. if not upload_data:
  1241. one_info['duration'] = round((now - order.startTime).total_seconds() / 60.0, 1)
  1242. one_info['total_time'] = one_info['duration']
  1243. else:
  1244. one_info['duration'] = round((now - to_datetime(upload_data[-1]['upload_time'])).total_seconds() / 60.0, 1)
  1245. one_info['total_time'] = round((now - order.startTime).total_seconds() / 60.0, 1)
  1246. upload_data.append(one_info)
  1247. order.upload_data = upload_data
  1248. order.save()
  1249. except Exception as e:
  1250. logger.error(e)
  1251. pass
  1252. class StartAckEventPreProcessor(AckEventProcessorIntf):
  1253. def analysis_reason(self, reason):
  1254. FINISHED_CHARGE_REASON_MAP = {
  1255. '00': u'为了防止过度充电,您的充电已超过最大设定充电时长。',
  1256. '01': u'充电满了或者用户手动停止(拔插头,或是按了停止按钮)',
  1257. '02': u'充电满了,自动停止',
  1258. '03': u'超功率自停',
  1259. '04': u'远程断电',
  1260. '05': u'刷卡断电',
  1261. '0B': u'设备或是端口出现问题,被迫停止',
  1262. # 服务器定义的停止事件
  1263. '90': u'用户手动点击结束按钮结束充电',
  1264. '91': u'检测到设备未在充电工作状态,结束本次充电',
  1265. -2: u'检测到设备未在充电工作状态,结束本次充电',
  1266. }
  1267. return FINISHED_CHARGE_REASON_MAP.get(reason)
  1268. def pre_processing(self, device, event_data):
  1269. # type:(DeviceDict, dict)->dict
  1270. source = json.dumps(event_data)
  1271. event_data['source'] = source
  1272. if 'duration' in event_data and event_data['duration'] != 0:
  1273. duration = event_data.get('duration')
  1274. event_data['duration'] = ((duration + 59) / 60)
  1275. elif 'fts' in event_data and 'sts' in event_data:
  1276. duration = event_data['fts'] - event_data['sts']
  1277. event_data['duration'] = ((duration + 59) / 60)
  1278. else:
  1279. event_data['duration'] = 0
  1280. if 'elec' in event_data:
  1281. event_data['elec'] = round(event_data.pop('elec') / 3600000.0, 3)
  1282. else:
  1283. event_data['elec'] = 0
  1284. # 初始化分档时间
  1285. if 'time' in event_data:
  1286. event_data['time'] = event_data['time'] / 60.0
  1287. else:
  1288. event_data['time'] = 0.0
  1289. if 'timeMax' in event_data:
  1290. event_data['needTime'] = event_data.pop('timeMax') / 60.0
  1291. if 'elecMax' in event_data:
  1292. event_data['needElec'] = round(event_data.pop('elecMax') / 3600000.0, 3)
  1293. if 'port' in event_data:
  1294. pass
  1295. if 'sub' in event_data:
  1296. subs = event_data.get('sub', [])
  1297. for item in subs:
  1298. if 'card_cst' in item:
  1299. item['fee'] = RMB(item['card_cst']) * Ratio('0.1')
  1300. # event_data['fee'] += item['fee']
  1301. if 'balance' in item:
  1302. item['balance'] = RMB(item['balance']) * Ratio('0.1')
  1303. if 'timeMax' in event_data:
  1304. event_data['needTime'] = event_data.pop('timeMax')
  1305. if 'elecMax' in event_data:
  1306. event_data['needElec'] = event_data.pop('elecMax')
  1307. if event_data['order_type'] != 'com_start':
  1308. package = {'coins': float(event_data['fee']), 'unit': 'time', 'time': 999}
  1309. event_data['package'] = package
  1310. if event_data['status'] == 'finished':
  1311. if 'reason' in event_data: # 正常结束
  1312. event_data['reasonDesc'] = self.analysis_reason(event_data['reason'])
  1313. else:
  1314. event_data['reasonDesc'] = self.analysis_reason('91') # 由轮询订单出来的结果
  1315. if 'time' in event_data and 'needTime' in event_data:
  1316. if event_data['time'] >= event_data['needTime']:
  1317. event_data['time'] = event_data['needTime']
  1318. event_data['reasonDesc'] = '购买的充电时间用完,功率超过额定值时间会相应缩短。'
  1319. if 'elec' in event_data and 'needElec' in event_data:
  1320. if event_data['elec'] >= event_data['needElec']:
  1321. event_data['elec'] = event_data['needElec']
  1322. event_data['reasonDesc'] = '根据您的动态功率计算, 您订购的电量已用完, 当前充电服务已结束, 谢谢您的使用!!'
  1323. if 'cardType' in event_data:
  1324. pass
  1325. if 'cardNo' in event_data:
  1326. event_data['cardNoHex'] = str(event_data.pop('cardNo'))
  1327. event_data['cardNo'] = str(int(event_data['cardNoHex'], 16))
  1328. event_data['cardType'] = 'ID'
  1329. if 'balance' in event_data:
  1330. if event_data['order_type'] == 'com_start':
  1331. event_data['fee'] = RMB(event_data.pop('balance')) * Ratio('0.1')
  1332. elif event_data['order_type'] == 'id_start':
  1333. cst = float(device['otherConf'].get("deviceConfigs", {}).get('cst', 30.0)) * 0.1
  1334. event_data['fee'] = RMB(cst)
  1335. event_data['fee'] = min(RMB(cst), RMB(event_data.pop('balance')) * Ratio('0.1'))
  1336. else:
  1337. event_data['fee'] = RMB(0)
  1338. if event_data['needTime'] == 0:
  1339. event_data['timeFee'] = RMB(0)
  1340. else:
  1341. event_data['timeFee'] = event_data['fee'] * round(event_data['time'] / event_data['needTime'], 2)
  1342. if event_data['needElec'] == 0:
  1343. event_data['elecFee'] = RMB(0)
  1344. else:
  1345. event_data['elecFee'] = event_data['fee'] * round(event_data['elec'] / event_data['needElec'], 2)
  1346. # if event_data.get('reason') in ['00']:
  1347. # event_data['timeFee'] = event_data['fee']
  1348. # event_data['elecFee'] = event_data['fee']
  1349. if event_data['order_type'] != 'com_start':
  1350. package = {'coins': float(event_data['fee']), 'unit': 'time', 'time': 999}
  1351. event_data['package'] = package
  1352. return event_data
  1353. class MyComNetPayAckEvent(ComNetPayAckEvent):
  1354. def __init__(self, smartBox, event_data):
  1355. super(MyComNetPayAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1356. def post_after_start(self, order = None):
  1357. pass
  1358. def post_after_finish(self, order = None):
  1359. # TODO 订单结束处理后付费
  1360. self.pay_order(order)
  1361. def merge_order(self, master_order, sub_orders):
  1362. # type:(ConsumeRecord, list)->dict
  1363. if self.is_postpaid:
  1364. # TODO 显示费用调整 portDict
  1365. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
  1366. portDict = {'billingType': 'time'}
  1367. portDict['coins'] = 0
  1368. portDict['needKind'] = 'needTime'
  1369. portDict['needValue'] = 999
  1370. portDict['unit'] = u'分钟'
  1371. portDict['estimatedTs'] = int(start_time.timestamp + 720 * 60 * 60)
  1372. return portDict
  1373. else:
  1374. needTime, needElec= self.deviceAdapter._check_package(master_order.package)
  1375. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo = settings.TIME_ZONE)
  1376. portDict = {
  1377. }
  1378. if master_order.paymentInfo['via'] == 'virtualCard':
  1379. portDict.update({
  1380. 'vCardId': master_order.virtual_card_id
  1381. })
  1382. all_coins = master_order.package['coins']
  1383. all_price = master_order.package['price']
  1384. all_consume_time_value = needTime
  1385. all_consume_elec_value = needElec
  1386. for sub_order in sub_orders:
  1387. all_coins += sub_order.package['coins']
  1388. all_price += sub_order.package['price']
  1389. sub_needTime, sub_needElec = self.deviceAdapter._check_package(sub_order.package)
  1390. all_consume_time_value += sub_needTime
  1391. all_consume_elec_value += sub_needElec
  1392. portDict['coins'] = str(all_coins)
  1393. portDict['price'] = str(all_price)
  1394. portDict['all_consume_time_value'] = str(all_consume_time_value)
  1395. portDict['all_consume_elec_value'] = str(all_consume_elec_value)
  1396. portDict['needKind'] = 'needTime'
  1397. portDict['needValue'] = 999 #显示充满自停
  1398. portDict['unit'] = u'分钟'
  1399. portDict['estimatedTs'] = int(start_time.timestamp + 720 * 60)
  1400. portDict['consumeType'] = 'mobile'
  1401. return portDict
  1402. def do_finished_event(self, master_order, sub_orders, merge_order_info):
  1403. # type: (ConsumeRecord, [ConsumeRecord], dict)->None
  1404. self._do_finished(master_order, sub_orders, merge_order_info)
  1405. # billing_type = merge_order_info['billingType']
  1406. # if billing_type == 'time':
  1407. # if self.is_postpaid:
  1408. # self.do_postpaid_time_finished(master_order, sub_orders, merge_order_info)
  1409. # else:
  1410. # self.do_time_finished(master_order, sub_orders, merge_order_info)
  1411. # else:
  1412. # self.do_elec_finished(master_order, sub_orders, merge_order_info)
  1413. @SmartBox.check_device_features(device_features=['Postpaid'])
  1414. def pay_order(self, order):
  1415. order.status = 'running'
  1416. order.save()
  1417. order.s_to_e()
  1418. @property
  1419. @SmartBox.check_device_features(device_features=['Postpaid'])
  1420. def is_postpaid(self):
  1421. return True
  1422. def do_postpaid_time_finished(self, master_order, sub_orders=None, merge_order_info=None):
  1423. user = MyUser.objects(openId=master_order.openId,
  1424. groupId=master_order.groupId).first() # type: MyUser
  1425. if not user:
  1426. logger.error(
  1427. 'user is not exist. openId = {}, groupId = {}'.format(master_order.openId, master_order.groupId))
  1428. return
  1429. left = self.event_data.get('leftTime', 0)
  1430. duration = self.event_data.get('duration', 0)
  1431. elec = self.event_data.get('elec', 0)
  1432. consumeDict = {
  1433. 'reason': self.event_data.get('reasonDesc'),
  1434. 'leftTime': str(left),
  1435. 'chargeIndex': str(master_order.used_port),
  1436. 'duration': duration,
  1437. 'elec': elec,
  1438. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1439. }
  1440. logger.debug(
  1441. 'orderNo = {}, orderType = isPostpaid, usedTime = {}, needPayMoney = {}'.format(master_order.orderNo,
  1442. duration,
  1443. master_order.coin))
  1444. extra = []
  1445. desc = r'(已使用账户余额自动结算此次消费)' if master_order.is_finished() else r'(您的账户余额已不足以抵扣此次消费,请前往账单中心进行支付)'
  1446. self.event_data['reasonDesc'] += desc
  1447. extra.append({u'消费金额': '{}(金币)'.format(master_order.money)} if master_order.is_finished() else {
  1448. u'消费金额': '{}(元)'.format(master_order.money)})
  1449. master_order.update_service_info(consumeDict)
  1450. auth_bridge = get_wechat_auth_bridge(source=self.device,
  1451. app_type=APP_TYPE.WECHAT_USER_MANAGER)
  1452. self.notify_user_service_complete(
  1453. service_name='充电',
  1454. openid=user.get_bound_pay_openid(auth_bridge.bound_openid_key),
  1455. port=str(master_order.used_port),
  1456. address=master_order.address,
  1457. reason=self.event_data.get('reasonDesc'),
  1458. finished_time=master_order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1459. extra=extra)
  1460. def insert_vCard_consume_record(self, vCard, order, success, consumeTotal,consumeDay):
  1461. try:
  1462. if success and consumeDay['count'] > 0:
  1463. record = VCardConsumeRecord(
  1464. orderNo=VCardConsumeRecord.make_no(order.logicalCode),
  1465. openId=order.openId,
  1466. nickname=order.nickname,
  1467. cardId=str(vCard.id),
  1468. dealerId=vCard.dealerId,
  1469. devNo=order.devNo,
  1470. devTypeCode = order.devTypeCode,
  1471. devTypeName = order.dev_type_name,
  1472. logicalCode=order.logicalCode,
  1473. groupId=order.groupId,
  1474. address=order.address,
  1475. groupNumber=order.groupNumber,
  1476. groupName=order.groupName,
  1477. attachParas=order.attachParas,
  1478. consumeData=consumeTotal,
  1479. consumeDayData=consumeDay
  1480. )
  1481. record.save()
  1482. except Exception, e:
  1483. logger.exception(e)
  1484. def _do_finished(self, order, sub_orders, merge_order_info):
  1485. # type: (ConsumeRecord, list, dict)->None
  1486. duration, elec = self.event_data.get('duration',0), self.event_data.get('elec',0)
  1487. coins = VirtualCoin(merge_order_info['coins'])
  1488. timeFee = VirtualCoin(self.event_data.get('timeFee', 0.0))
  1489. elecFee = VirtualCoin(self.event_data.get('elecFee', 0.0))
  1490. usedFee = max(timeFee, elecFee)
  1491. auto_refund = self.device.is_auto_refund
  1492. refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
  1493. user = MyUser.objects(openId=order.openId,
  1494. groupId=order.groupId).first() # type: MyUser
  1495. backCoins = VirtualCoin(0)
  1496. if duration < refundProtectionTime:
  1497. backCoins = coins
  1498. usedFee = VirtualCoin(0)
  1499. else:
  1500. if auto_refund:
  1501. backCoins = coins - usedFee
  1502. else:
  1503. usedFee = coins
  1504. logger.debug('{} auto refund enable switch is {}, refund protect time = {} backMoney={}'.format(
  1505. repr(self.device), str(auto_refund), refundProtectionTime, backCoins))
  1506. extra = []
  1507. extra.append({u'本次使用时长':u'{}(分钟)'.format(duration)})
  1508. if order.paymentInfo['via'] == 'free':
  1509. extra.append({u'消费金额': u'当前设备免费使用'})
  1510. elif order.paymentInfo['via'] in ['netPay', 'coins', 'cash', 'coin']:
  1511. all_money = RMB(0)
  1512. all_refund_money = RMB(0)
  1513. orders = [order] + sub_orders
  1514. refundCash = 'refundRMB_device_event' in self.device.owner.features
  1515. for _order in orders[::-1]:
  1516. consumeDict = {
  1517. 'reason': self.event_data.get('reasonDesc', None),
  1518. 'chargeIndex': str(order.used_port),
  1519. 'source': self.event_data.get('source', None)
  1520. }
  1521. need_back_coins, need_consume_coins, backCoins = self._calc_refund_info(backCoins, _order.coin)
  1522. rechargeRcdId = _order.attachParas.get('linkedRechargeRecordId', '')
  1523. if rechargeRcdId != '':
  1524. rechargeRcd = RechargeRecord.objects.filter(id=rechargeRcdId, isQuickPay=True).first()
  1525. else:
  1526. rechargeRcd = None
  1527. if refundCash and rechargeRcd: # 退现金特征 + 有充值订单
  1528. # 退现金部分
  1529. user.clear_frozen_balance(str(_order.id), _order.paymentInfo['deduct'],
  1530. back_coins=VirtualCoin(0),
  1531. consume_coins=VirtualCoin(_order.coin))
  1532. refundRMB = rechargeRcd.money * (float(need_back_coins) / float(_order.coin))
  1533. self.refund_net_pay(user, {'rechargeRcdId': rechargeRcdId, 'openId': user.openId},
  1534. refundRMB, VirtualCoin(0), consumeDict, True)
  1535. all_money += RMB(rechargeRcd.money)
  1536. all_refund_money += RMB(refundRMB)
  1537. else:
  1538. user.clear_frozen_balance(str(_order.id), _order.paymentInfo['deduct'], back_coins=need_back_coins,
  1539. consume_coins=need_consume_coins)
  1540. consumeDict.update({
  1541. DEALER_CONSUMPTION_AGG_KIND.COIN: _order.coin.mongo_amount,
  1542. DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: need_consume_coins.mongo_amount,
  1543. DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: need_back_coins.mongo_amount})
  1544. if _order.orderNo == order.orderNo:
  1545. consumeDict.update({
  1546. DEALER_CONSUMPTION_AGG_KIND.DURATION: duration,
  1547. DEALER_CONSUMPTION_AGG_KIND.ELEC: elec,
  1548. DEALER_CONSUMPTION_AGG_KIND.ELECFEE: self.deviceAdapter.calc_elec_fee(elec),
  1549. })
  1550. _order.update_service_info(consumeDict)
  1551. if refundCash:
  1552. extra.append({u'消费金额': '{}元'.format(all_money - all_refund_money)})
  1553. if all_refund_money > RMB(0):
  1554. extra.append({u'退款金额': '{}元'.format(all_refund_money)})
  1555. else:
  1556. extra.append({u'消费金额': '{}金币'.format(usedFee)})
  1557. if backCoins > VirtualCoin(0):
  1558. extra.append({u'退款金额': '{}金币(当充电金币数量大于或等于扫码充电金额时可抵现金,金币不可提现)'.format(backCoins)})
  1559. else:
  1560. logger.error('not net pay rather user virtual card pay. something is wrong.')
  1561. return
  1562. auth_bridge = get_wechat_auth_bridge(source=self.device,
  1563. app_type=APP_TYPE.WECHAT_USER_MANAGER)
  1564. self.notify_user_service_complete(
  1565. service_name='充电',
  1566. openid=user.get_bound_pay_openid(auth_bridge.bound_openid_key),
  1567. port=str(order.used_port),
  1568. address=order.address,
  1569. reason=self.event_data.get('reasonDesc'),
  1570. finished_time=order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1571. extra=extra)
  1572. def _calc_refund_info(self, backCoins, orderCoin):
  1573. if backCoins >= orderCoin:
  1574. need_back_coins = orderCoin
  1575. need_consume_coins = VirtualCoin(0)
  1576. backCoins -= orderCoin
  1577. else:
  1578. need_back_coins = backCoins
  1579. need_consume_coins = orderCoin - need_back_coins
  1580. backCoins = VirtualCoin(0)
  1581. return need_back_coins, need_consume_coins, backCoins
  1582. class MyIcStartAckEvent(IcStartAckEvent):
  1583. def __init__(self, smartBox, event_data):
  1584. super(MyIcStartAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1585. def post_after_start(self, order = None):
  1586. pass
  1587. def post_after_finish(self, order = None):
  1588. pass
  1589. def merge_order(self, master_order, sub_orders):
  1590. # type:(ConsumeRecord, list)->dict
  1591. consumeModule = self.device.get('otherConf', dict()).get('consumeModule', 0)
  1592. # 按时间计费
  1593. if consumeModule == 0:
  1594. billingType = 'time'
  1595. else:
  1596. billingType = 'elec'
  1597. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo = settings.TIME_ZONE)
  1598. portDict = {
  1599. 'billingType': billingType
  1600. }
  1601. if master_order.paymentInfo['via'] == 'virtualCard':
  1602. portDict.update({
  1603. 'vCardId': master_order.paymentInfo['itemId']
  1604. })
  1605. all_coins = master_order.coin
  1606. all_money = master_order.money
  1607. for sub_order in sub_orders:
  1608. all_coins += sub_order.coin
  1609. all_money += sub_order.money
  1610. portDict['coins'] = str(all_coins)
  1611. portDict['money'] = str(all_money)
  1612. portDict['estimatedTs'] = int(start_time.timestamp + 12 * 60 * 60)
  1613. return portDict
  1614. def do_time_finished(self, card, order, merge_order_info):
  1615. # type: (Card, ConsumeRecord, dict)->None
  1616. duration, elec = self.event_data['duration'], self.event_data['elec']
  1617. coins = VirtualCoin(merge_order_info['coins'])
  1618. left = self.event_data['left']
  1619. consumeDict = {
  1620. 'reason': self.event_data['reason'],
  1621. 'chargeIndex': str(order.used_port),
  1622. 'duration': duration,
  1623. 'elec': elec,
  1624. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1625. }
  1626. # backMoney = VirtualCoin(self.event_data['backMoney'])
  1627. group = self.device.group # type: GroupDict
  1628. extra = [{
  1629. u'实体卡号': self.event_data['cardNo']
  1630. }]
  1631. consumeDict.update({'balance': str(card.balance)})
  1632. order.update_service_info(consumeDict)
  1633. self.notify_user_service_complete(
  1634. service_name = '充电',
  1635. openid = card.managerialOpenId if card else '',
  1636. port = order.used_port,
  1637. address = group.address,
  1638. reason = self.event_data['reason'],
  1639. finished_time = order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1640. extra = extra)
  1641. def do_elec_finished(self, card, order, merge_order_info):
  1642. # type:(Card, ConsumeRecord, dict)->None
  1643. '''
  1644. 电川的板子 按电量退费
  1645. :return:
  1646. '''
  1647. leftElec = self.event_data.get('left', 0) / 100.0
  1648. duration, elec = self.event_data['duration'], self.event_data['elec']
  1649. try:
  1650. consumeDict = {
  1651. 'reason': self.event_data['reasonDesc'],
  1652. 'chargeIndex': order.used_port,
  1653. 'duration': duration,
  1654. 'elec': elec,
  1655. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1656. }
  1657. # backMoney = self.event_data.get('backMoney')
  1658. extra = [{u'实体卡号': self.event_data['cardNo']}]
  1659. # if self.event_data['cardType'] == 'ID':
  1660. # if backMoney > 0:
  1661. # self.refund_money_for_card(RMB(backMoney), card.id)
  1662. # extra.append({
  1663. # u'退款金额': u'{}(金币)'.format(backMoney)
  1664. # })
  1665. #
  1666. # consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))})
  1667. # else:
  1668. consumeDict.update({'balance': str(card.balance)})
  1669. order.update_service_info(consumeDict)
  1670. self.notify_user_service_complete(
  1671. service_name = '充电',
  1672. openid = self.get_managerialOpenId_by_openId(order.openId),
  1673. port = order.used_port,
  1674. address = self.device.group.address,
  1675. reason = self.event_data['reason'],
  1676. finished_time = order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1677. extra = extra)
  1678. except Exception as e:
  1679. logger.exception(e)
  1680. def do_finished_event(self, card, order, merge_order_info):
  1681. # type:(Card, ConsumeRecord, dict)->None
  1682. if 'backMoney' in self.event_data and self.event_data['backMoney'] > RMB(0):
  1683. refund_order = RechargeRecord.objects(orderNo = self.event_data['order_id']).first()
  1684. if not refund_order:
  1685. self.refund_money_for_card(RMB(self.event_data['backMoney']), card.id, self.event_data['order_id'])
  1686. billing_type = merge_order_info['billingType']
  1687. if billing_type == 'time':
  1688. self.do_time_finished(card, order, merge_order_info)
  1689. else:
  1690. self.do_elec_finished(card, order, merge_order_info)
  1691. class MyIcRechargeAckEvent(IcRechargeAckEvent):
  1692. def __init__(self, smartBox, event_data):
  1693. super(MyIcRechargeAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1694. class MyCardRefundAckEvent(CardRefundAckEvent):
  1695. def __init__(self, smartBox, event_data):
  1696. super(MyCardRefundAckEvent, self).__init__(smartBox, event_data, CardRefundAckEventPreProcessor())
  1697. class CardRefundAckEventPreProcessor(AckEventProcessorIntf):
  1698. def pre_processing(self, device, event_data):
  1699. # type:(DeviceDict, dict)->dict
  1700. if 'cardType' in event_data:
  1701. if event_data['cardType'] == 'AA33':
  1702. event_data['cardType'] = 'ID'
  1703. else:
  1704. event_data['cardType'] = 'IC'
  1705. if 'cardNo' in event_data:
  1706. event_data['cardNo'] = str(event_data['cardNo'])
  1707. event_data['backMoney'] = (int(event_data['backMoney']) / 10.0)
  1708. return event_data
  1709. class MyIdStartAckEvent(IdStartAckEvent):
  1710. def __init__(self, smartBox, event_data):
  1711. super(MyIdStartAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1712. def post_after_start(self, order=None):
  1713. pass
  1714. def post_after_finish(self, order=None):
  1715. pass
  1716. def merge_order(self, master_order, sub_orders):
  1717. # type:(ConsumeRecord, list)->dict
  1718. billingType = self.device.get('otherConf', dict()).get('billingType', 'time')
  1719. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo = settings.TIME_ZONE)
  1720. portDict = {
  1721. 'billingType': billingType
  1722. }
  1723. all_coins = master_order.coin
  1724. all_money = master_order.money
  1725. all_consume_time = self.event_data.get('needTime', 0)
  1726. all_consume_elec = self.event_data.get('needElec', 0)
  1727. for sub_order in sub_orders:
  1728. all_coins += sub_order.coin
  1729. all_money += sub_order.money
  1730. if self.event_data.get('sub', []):
  1731. for _ in self.event_data['sub']:
  1732. all_consume_time += _.get('needTime', 0)
  1733. all_consume_elec += _.get('needElec', 0)
  1734. portDict['coins'] = str(all_coins)
  1735. portDict['money'] = str(all_money)
  1736. portDict['all_consume_time_value'] = all_consume_time
  1737. portDict['all_consume_elec_value'] = all_consume_elec
  1738. # 直接显示充满自停
  1739. portDict['needValue'] = 999
  1740. portDict['needKind'] = 'needTime'
  1741. portDict['unit'] = u'分钟'
  1742. portDict['estimatedTs'] = int(start_time.timestamp + portDict['needValue'] * 60)
  1743. return portDict
  1744. def _do_finished(self, order, merge_order_info):
  1745. # type: (ConsumeRecord, dict)->None
  1746. duration, elec = self.event_data.get('duration', 0), self.event_data.get('elec', 0)
  1747. coins = VirtualCoin(merge_order_info['coins'])
  1748. timeFee = VirtualCoin(self.event_data.get('timeFee', 0.0))
  1749. elecFee = VirtualCoin(self.event_data.get('elecFee', 0.0))
  1750. usedFee = max(timeFee, elecFee)
  1751. consumeDict = {
  1752. 'reason': self.event_data.get('reasonDesc', None),
  1753. 'chargeIndex': str(order.used_port),
  1754. 'duration': duration,
  1755. 'elec': elec,
  1756. 'cardNo': self.event_data['cardNo'],
  1757. 'elecFee': self.deviceAdapter.calc_elec_fee(elec),
  1758. DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: coins.mongo_amount,
  1759. 'source': self.event_data.get('source', None)
  1760. }
  1761. refundProtectionTime = int(self.device.get('otherConf', {}).get('refundProtectionTime', 5))
  1762. logger.info('[HDV3]{} refund protect time = {} duration={} coins={} usedFee={}'.format(
  1763. repr(self.device), refundProtectionTime, duration, coins, usedFee))
  1764. if duration <= refundProtectionTime:
  1765. backMoney = coins
  1766. usedFee = VirtualCoin(0)
  1767. else:
  1768. backMoney = coins - usedFee
  1769. logger.info('{} refund protect time = {} backMoney={}'.format(
  1770. repr(self.device), refundProtectionTime, backMoney))
  1771. self.card.clear_frozen_balance(str(order.id), backMoney)
  1772. self.card.reload()
  1773. extra = []
  1774. extra.append({u'实体卡': '{}--No:{}'.format(self.card.cardName, self.card.cardNo)})
  1775. extra.append({u'本次使用时长': '{}(分钟)'.format(duration)})
  1776. extra.append({u'本次消费金额': '{}(金币)'.format(usedFee)})
  1777. extra.append({u'卡片当前余额': '{}(金币)'.format(self.card.balance.mongo_amount)})
  1778. if backMoney > VirtualCoin(0):
  1779. self.record_refund_money_for_card(backMoney, str(self.card.id), orderNo=order.orderNo)
  1780. consumeDict.update({
  1781. DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: usedFee.mongo_amount,
  1782. DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: backMoney.mongo_amount
  1783. })
  1784. order.update_service_info(consumeDict)
  1785. self.notify_user_service_complete(
  1786. service_name='充电',
  1787. openid=self.card.managerialOpenId,
  1788. port=str(order.used_port),
  1789. address=order.address,
  1790. reason=self.event_data.get('reasonDesc'),
  1791. finished_time=order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1792. extra=extra)
  1793. def do_finished_event(self, order, merge_order_info):
  1794. # type:(ConsumeRecord, dict)->None
  1795. self._do_finished(order, merge_order_info)
  1796. def checkout_order(self, order):
  1797. fee = VirtualCoin(order.coin)
  1798. self.card.freeze_balance(transaction_id=str(order.id), fee=fee)
  1799. class MyVirtualCardStartAckEvent(VirtualCardStartAckEvent):
  1800. def __init__(self, smartBox, event_data):
  1801. super(MyVirtualCardStartAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
  1802. def post_after_start(self, order = None, card = None):
  1803. pass
  1804. def post_after_finish(self, order = None):
  1805. pass
  1806. def checkout_order(self, order):
  1807. group = Group.get_group(self.device.groupId) # type:GroupDict
  1808. freeze_user_balance(self.device, group, order, self.virtualCard)
  1809. def merge_order(self, master_order, sub_orders):
  1810. # type:(ConsumeRecord, list)->dict
  1811. billingType = self.device.get('otherConf', dict()).get('billingType', 'time')
  1812. start_time = Arrow.fromdatetime(master_order.startTime, tzinfo = settings.TIME_ZONE)
  1813. portDict = {
  1814. 'billingType': billingType
  1815. }
  1816. all_coins = master_order.coin
  1817. all_money = master_order.money
  1818. all_consume_time = self.event_data.get('needTime', 0)
  1819. all_consume_elec = self.event_data.get('needElec', 0)
  1820. if self.event_data.get('sub', []):
  1821. for _ in self.event_data['sub']:
  1822. all_consume_time += _.get('needTime', 0)
  1823. all_consume_elec += _.get('needElec', 0)
  1824. portDict['coins'] = str(all_coins)
  1825. portDict['money'] = str(all_money)
  1826. if billingType == 'time':
  1827. portDict['needKind'] = 'needTime'
  1828. portDict['needValue'] = all_consume_time
  1829. portDict['unit'] = u'分钟'
  1830. portDict['estimatedTs'] = int(start_time.timestamp + all_consume_time * 60)
  1831. elif billingType == 'elec':
  1832. portDict['needKind'] = 'needElec'
  1833. portDict['needValue'] = round(all_consume_elec / 100.0, 2)
  1834. portDict['unit'] = u'度'
  1835. portDict['estimatedTs'] = int(start_time.timestamp + 12 * 60 * 60)
  1836. else:
  1837. pass
  1838. return portDict
  1839. def do_time_finished(self, card, order, sub_orders, merge_order_info):
  1840. # type: (Card, ConsumeRecord, list, dict)->None
  1841. duration, elec = self.event_data['duration'], self.event_data['elec']
  1842. consumeDict = {
  1843. 'reason': self.event_data['reasonDesc'],
  1844. 'chargeIndex': str(order.used_port),
  1845. 'duration': duration,
  1846. 'elec': elec,
  1847. 'cardNo': self.event_data['cardNo'],
  1848. 'elecFee': self.deviceAdapter.calc_elec_fee(elec)
  1849. }
  1850. auto_refund = self.device.is_auto_refund
  1851. refundProtection = self.device.get('otherConf', {}).get('refundProtection', 0)
  1852. refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
  1853. logger.debug('{} auto refund enable switch is {}. refund protect = {}, refund protect time = {}'.format(
  1854. repr(self.device), str(auto_refund), refundProtection, refundProtectionTime))
  1855. if auto_refund:
  1856. order_need_time = order.package.get('time')
  1857. if order_need_time >= duration:
  1858. usedTime = duration
  1859. duration = 0
  1860. else:
  1861. usedTime = order_need_time
  1862. duration -= order_need_time
  1863. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(transaction_id=str(order.id),
  1864. usedTime=usedTime, spendElec=0,
  1865. backCoins=VirtualCoin(0).mongo_amount)
  1866. self.insert_vCard_consume_record(self.virtualCard, order, success, consumeTotal, consumeDay)
  1867. for sub_order in sub_orders:
  1868. order_need_time = sub_order.package.get('time')
  1869. if order_need_time >= duration:
  1870. usedTime = duration
  1871. duration = 0
  1872. else:
  1873. usedTime = order_need_time
  1874. duration -= order_need_time
  1875. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(transaction_id=str(sub_order.id),
  1876. usedTime=usedTime, spendElec=0,
  1877. backCoins=VirtualCoin(0).mongo_amount)
  1878. self.insert_vCard_consume_record(self.virtualCard, sub_order, success, consumeTotal, consumeDay)
  1879. else:
  1880. order_need_time = order.package.get('time')
  1881. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(transaction_id=str(order.id),
  1882. usedTime=order_need_time, spendElec=0,
  1883. backCoins=VirtualCoin(
  1884. 0).mongo_amount)
  1885. self.insert_vCard_consume_record(self.virtualCard, order, success, consumeTotal, consumeDay)
  1886. for sub_order in sub_orders:
  1887. order_need_time = sub_order.package.get('time')
  1888. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(
  1889. transaction_id=str(sub_order.id),
  1890. usedTime=order_need_time, spendElec=0,
  1891. backCoins=VirtualCoin(0).mongo_amount)
  1892. self.insert_vCard_consume_record(self.virtualCard, sub_order, success, consumeTotal, consumeDay)
  1893. group = self.device.group # type: GroupDict
  1894. extra = [{
  1895. u'虚拟卡号': self.virtualCard.cardNo
  1896. }]
  1897. order.update_service_info(consumeDict)
  1898. self.notify_user_service_complete(
  1899. service_name = '充电',
  1900. openid = card.managerialOpenId if card else '',
  1901. port = order.used_port,
  1902. address = group.address,
  1903. reason = self.event_data['reasonDesc'],
  1904. finished_time = order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1905. extra = extra)
  1906. def do_elec_finished(self, card, order, sub_orders, merge_order_info):
  1907. # type:(Card, ConsumeRecord, list, dict)->None
  1908. duration, elec = self.event_data['duration'], self.event_data['elec']
  1909. consumeDict = {
  1910. 'reason': self.event_data['reasonDesc'],
  1911. 'chargeIndex': str(order.used_port),
  1912. 'duration': duration,
  1913. 'elec': elec,
  1914. 'cardNo': self.event_data['cardNo'],
  1915. 'elecFee': self.deviceAdapter.calc_elec_fee(elec),
  1916. }
  1917. auto_refund = self.device.is_auto_refund
  1918. refundProtection = self.device.get('otherConf', {}).get('refundProtection', 0)
  1919. refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
  1920. logger.debug('{} auto refund enable switch is {}. refund protect = {}, refund protect time = {}'.format(
  1921. repr(self.device), str(auto_refund), refundProtection, refundProtectionTime))
  1922. if auto_refund:
  1923. order_need_time = order.package.get('time')
  1924. if order_need_time >= elec:
  1925. usedTime = duration
  1926. duration = 0
  1927. else:
  1928. usedTime = order_need_time
  1929. elec -= order_need_time
  1930. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(transaction_id=str(order.id),
  1931. usedTime=usedTime, spendElec=0,
  1932. backCoins=VirtualCoin(
  1933. 0).mongo_amount)
  1934. self.insert_vCard_consume_record(self.virtualCard, order, success, consumeTotal, consumeDay)
  1935. for sub_order in sub_orders:
  1936. order_need_time = order.package.get('time')
  1937. if order_need_time >= duration:
  1938. usedTime = duration
  1939. duration = 0
  1940. else:
  1941. usedTime = order_need_time
  1942. duration -= order_need_time
  1943. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(
  1944. transaction_id=str(sub_order.id),
  1945. usedTime=usedTime, spendElec=0,
  1946. backCoins=VirtualCoin(0).mongo_amount)
  1947. self.insert_vCard_consume_record(self.virtualCard, sub_order, success, consumeTotal, consumeDay)
  1948. else:
  1949. order_need_time = order.package.get('time')
  1950. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(
  1951. transaction_id=str(order.id),
  1952. usedTime=order_need_time, spendElec=0,
  1953. backCoins=VirtualCoin(
  1954. 0).mongo_amount)
  1955. self.insert_vCard_consume_record(self.virtualCard, order, success, consumeTotal, consumeDay)
  1956. for sub_order in sub_orders:
  1957. order_need_time = sub_order.package.get('time')
  1958. success, consumeTotal, consumeDay = self.virtualCard.clear_frozen_quota(
  1959. transaction_id=str(sub_order.id),
  1960. usedTime=order_need_time, spendElec=0,
  1961. backCoins=VirtualCoin(0).mongo_amount)
  1962. self.insert_vCard_consume_record(self.virtualCard, sub_order, success, consumeTotal, consumeDay)
  1963. extra = [{
  1964. u'虚拟卡号': self.virtualCard.cardNo
  1965. }]
  1966. order.update_service_info(consumeDict)
  1967. self.notify_user_service_complete(
  1968. service_name = '充电',
  1969. openid = self.get_managerialOpenId_by_openId(order.openId),
  1970. port = order.used_port,
  1971. address = self.device.group.address,
  1972. reason = self.event_data['reason'],
  1973. finished_time = order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
  1974. extra = extra)
  1975. def do_finished_event(self, card, order, sub_orders, merge_order_info):
  1976. # type:(Card, ConsumeRecord, list, dict)->None
  1977. billing_type = merge_order_info['billingType']
  1978. if billing_type == 'time':
  1979. self.do_time_finished(card, order, sub_orders,merge_order_info)
  1980. else:
  1981. self.do_elec_finished(card, order, sub_orders,merge_order_info)
  1982. def insert_vCard_consume_record(self, vCard, order, success, consumeTotal, consumeDay):
  1983. try:
  1984. if success and consumeDay['count'] > 0:
  1985. record = VCardConsumeRecord(
  1986. orderNo=VCardConsumeRecord.make_no(order.logicalCode),
  1987. openId=order.openId,
  1988. nickname=order.nickname,
  1989. cardId=str(vCard.id),
  1990. dealerId=vCard.dealerId,
  1991. devNo=order.devNo,
  1992. devTypeCode = order.devTypeCode,
  1993. devTypeName = order.dev_type_name,
  1994. logicalCode=order.logicalCode,
  1995. groupId=order.groupId,
  1996. address=order.address,
  1997. groupNumber=order.groupNumber,
  1998. groupName=order.groupName,
  1999. attachParas=order.attachParas,
  2000. consumeData=consumeTotal,
  2001. consumeDayData=consumeDay
  2002. )
  2003. record.save()
  2004. except Exception, e:
  2005. logger.exception(e)