1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import json
- import logging
- import time
- from arrow import Arrow
- from django.conf import settings
- from typing import TYPE_CHECKING
- from apilib.monetary import RMB, VirtualCoin, Ratio
- from apps.web.constant import Const, APP_TYPE, DEALER_CONSUMPTION_AGG_KIND, DeviceCmdCode
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.device.models import Device
- from apps.web.device.timescale import FluentedEngine
- from apps.web.eventer.base import FaultEvent, WorkEvent, ComNetPayAckEvent, AckEventProcessorIntf, \
- IcStartAckEvent, IdStartAckEvent
- from apps.web.eventer import EventBuilder
- from apps.web.helpers import get_wechat_auth_bridge
- from apps.web.user.models import VCardConsumeRecord, ServiceProgress, CardRechargeOrder, MyUser, ConsumeRecord
- if TYPE_CHECKING:
- from apps.web.device.models import DeviceDict
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- # 订单机制事件
- if 'order_id' in device_event:
- if device_event['order_type'] == 'com_start':
- return MyComNetPayAckEvent(self.deviceAdapter, device_event)
-
- if device_event['order_type'] == 'ic_recharge':
- pass
-
- if device_event['order_type'] == 'ic_start':
- return OfflineCardStartAckEvent(self.deviceAdapter, device_event)
-
- if device_event['order_type'] == 'id_start':
- return OnlineCardStartAckEvent(self.deviceAdapter, device_event)
-
- if device_event['order_type'] == 'card_refund':
- pass
- else:
- if 'data' not in device_event:
- return None
-
- event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
-
- if event_data is None or 'cmdCode' not in event_data:
- return None
-
- if event_data.get('subCmd') == '3F':
- return GaoBoRuiFaultEvent(self.deviceAdapter, event_data)
-
- else:
- return GeneralEvent(self.deviceAdapter, event_data)
- class GeneralEvent(WorkEvent):
- SUCCESS_01 = '01'
- BALANCE_NOT_ENOUGH_02 = '02'
- INVALID_CARD_03 = '03'
- FREEZE_CARD_04 = '04'
-
- def do(self):
- if self.event_data['subCmd'] == '35':
- self._do_start_with_offline_card()
-
- elif self.event_data['subCmd'] == '36':
- self._do_get_balance()
-
- elif self.event_data['subCmd'] == '3B':
- self._do_sync_balance_with_offline_card()
-
- elif self.event_data['subCmd'] == '32':
- self._graph_power_point()
-
- def _do_get_balance(self):
-
- cardNo = str(int(self.event_data.get('card_no'), 16))
- logger.info('receive cardNo:{}'.format(cardNo))
-
- card = self.update_card_dealer_and_type(cardNo)
-
- mqtt_data = {
- 'funCode': self.event_data.get('cmdCode')
- }
-
- if not card or not card.openId:
- data = self.event_data.get('session')
- data += '36'
- data += self.INVALID_CARD_03
- data += self.event_data.get('card_no')
- data += self.event_data.get('fee')
- data += '{:0>4X}'.format(0)
- logger.info('no this card! card_no_hex<{}>, cardNo<{}>'.format(self.event_data.get('card_no'), cardNo))
-
- elif card.frozen:
- data = self.event_data.get('session')
- data += '36'
- data += self.FREEZE_CARD_04
- data += self.event_data.get('card_no')
- data += self.event_data.get('fee')
- data += '{:0>4X}'.format(0)
- logger.info('card is frozen card_no_hex<{}>, cardNo<{}>'.format(self.event_data.get('card_no'), cardNo))
-
- else:
- # 是否存在没有到账的余额 进行充值
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- self.recharge_id_card(
- card=card,
- rechargeType='append',
- order=card_recharge_order
- )
- card.reload()
-
- fee = RMB(int(self.event_data.get('fee'), 16)) * 0.1
-
- if card.balance >= RMB(fee):
- data = self.event_data.get('session')
- data += '36'
- data += self.SUCCESS_01
- data += self.event_data.get('card_no')
- data += self.event_data.get('fee')
- data += '{:0>4X}'.format(int((card.balance - fee) * 10))
-
- else:
- data = self.event_data.get('session')
- data += '36'
- data += self.BALANCE_NOT_ENOUGH_02
- data += self.event_data.get('card_no')
- data += self.event_data.get('fee')
- data += '{:0>4X}'.format(int((card.balance - fee) * 10))
-
- mqtt_data['data'] = data
- self.send_mqtt(data=mqtt_data, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE)
-
- def send_mqtt(self, data=None, cmd=DeviceCmdCode.OPERATE_DEV_SYNC):
- """
- 发送mqtt 指令默认210 返回data
- """
- result = MessageSender.send(self.device, cmd,
- data)
- if 'rst' in result and result['rst'] != 0:
- if result['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'该设备正在玩命找网络,请您稍候再试', 'rst': -1})
- elif result['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
- else:
- if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]:
- return
-
- return result.get('data', 'ok')
-
- def _do_start_with_offline_card(self):
- cardNo = str(int(self.event_data.get('card_no'), 16))
- port = self.event_data.get('port')
- fee = self.event_data.get('fee')
- balance = self.event_data.get('balance')
- billingType = self.event_data.get('billingType')
-
- logger.info('receive cardNo:{}'.format(cardNo))
- card = self.update_card_dealer_and_type(cardNo, cardType='IC', balance=RMB(balance))
-
- if not card:
- logger.info('no this card! card_no_hex<{}>, cardNo<{}>'.format(self.event_data.get('card_no'), cardNo))
- return
- if card.frozen:
- # 停止此离线卡的充电行为
- self.deviceAdapter.stop_charging_port(port)
- return
-
- lineInfo = Device.get_dev_control_cache(self.device.devNo).get(str(port))
- if lineInfo.get('status') == Const.DEV_WORK_STATUS_WORKING:
- pass
- else:
- logger.info('_do_card_start_charge the once!!')
- # 记录ID卡的消费
- attachParas = {
- 'chargeIndex': port
- }
-
- servicedInfo = {
- 'cardNo': cardNo,
- 'chargeIndex': port
- }
-
- orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(fee), servicedInfo=servicedInfo,
- attachParas=attachParas)
-
- # 记录缓存信息 可以在个人中心以及经销商的端口管理显示
- lineInfo = {
- 'port': str(port),
- 'cardNo': cardNo,
- 'openId': card.openId,
- 'payCount': 1,
- 'coins': fee,
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'orderNo': orderNo,
- 'cardOrderNo': cardOrderNo,
- 'billingType': billingType,
- 'consumeType': 'card'
- }
-
- if 'needTime' in self.event_data:
- lineInfo.update({'needTime': self.event_data['needTime']})
-
- if 'needElec' in self.event_data:
- lineInfo.update({'needElec': self.event_data['needElec']})
-
- ServiceProgress.register_card_service(
- self.device,
- int(port),
- card,
- {
- 'orderNo': orderNo,
- 'coin': RMB(fee).mongo_amount,
- 'cardOrderNo': cardOrderNo
- }
- )
-
- Device.update_port_control_cache(self.device.devNo, lineInfo)
-
- def _do_sync_balance_with_offline_card(self):
- card_no = self.event_data.get('card_no')
- cardNo = str(int(card_no, 16))
- port = self.event_data.get('port')
- fee = self.event_data.get('fee')
- balance = self.event_data.get('balance')
-
- logger.info('receive cardNo:{}'.format(cardNo))
- self.update_card_dealer_and_type(cardNo, cardType='IC', balance=RMB(balance))
- logging.info('Sync balance completed <port-{}> <card-{}>, <hex-{}>, <fee-{}>, <now-{}>'.format(port, cardNo,
- card_no, fee,
- balance))
-
- def _graph_power_point(self):
-
- powers = self.event_data.get('powers')
- for port, power in powers.items():
- FluentedEngine().in_power_udp(devNo=self.device.devNo,
- port=port,
- ts=int(time.time()),
- power=power,
- voltage=None,
- current=None)
- class GaoBoRuiEvent(WorkEvent):
-
- def do(self):
- pass
- class GaoBoRuiFaultEvent(FaultEvent):
-
- def do(self, **args):
- # 将告警的消息打入相应的缓存
- port = self.event_data.get('port')
-
- # 0 表示整机
- if not port:
- part = str(0)
- else:
- part = str(port)
-
- warningData = {
- 'warningStatus': 2,
- 'warningDesc': self.event_data['statusInfo'],
- 'warningTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'warningUart': self.event_data['uart']
- }
-
- Device.update_dev_warning_cache(self.device.devNo, {part: warningData})
-
- super(GaoBoRuiFaultEvent, self).do()
- class StartAckEventPreProcessor(AckEventProcessorIntf):
- def analysis_reason(self, reason, fault_code=None):
- FINISHED_CHARGE_REASON_MAP = {
- 0: u'购买的充电时间或者电量已经用完',
- 1: u'充满自停',
- 2: u'刷卡用户按停止键',
- 3: u'未接负载30秒自停',
- 4: u'充电器移除',
- 5: u'充电功率超限',
-
- # 服务器定义的停止事件
- 97: u'用户使用离线卡手动操作退费 ,充电结束',
- 98: u'用户手动点击结束按钮结束充电',
- 99: u'远程点击停止按钮, 充电结束',
- }
-
- if reason == 0xEE:
- if fault_code:
- fault_code = '{:X}'.format(fault_code)[-1]
- FAULT_ERROR_MAP = {
- '1': '(键盘故障)',
- '2': '(显示器故障)',
- '3': '(刷卡板故障)',
- '4': '(子网故障)',
- '5': '(存储故障)',
- '6': '(过温故障)',
- '7': '(烟雾故障)',
- '8': '(漏电)',
- '9': '(短路)',
- 'A': '(过压)',
- 'B': '(欠压)',
- 'C': '(整机过流)',
- 'D': '(恶意操作)',
- 'E': '(继电器粘连) ',
- 'F': '(其它故障) ',
- }
- return '充电桩发生故障' + FAULT_ERROR_MAP.get(fault_code)
-
- return '充电桩发生故障'
-
- return FINISHED_CHARGE_REASON_MAP.get(reason)
-
- def pre_processing(self, device, event_data):
- # type:(DeviceDict, dict)->dict
-
- source = json.dumps(event_data, indent=4)
- event_data['source'] = source
-
- if 'myDuration' in event_data:
- duration = event_data.pop('myDuration', 0)
- event_data['duration'] = round((duration + 59) / 60.0, 1)
-
- if 'myElec' in event_data:
- myElec = event_data.pop('myElec', 0)
- event_data['elec'] = round(myElec / 3600000.0, 2)
-
- if 'fts' in event_data and 'sts' in event_data:
- duration = event_data['fts'] - event_data['sts']
- event_data['duration'] = round((duration + 59) / 60.0, 1)
-
- if 'elec' in event_data:
- event_data['elec'] = round(event_data.pop('elec') * 0.01, 2)
-
- if 'openId' in event_data:
- pass
-
- if 'power' in event_data:
- event_data['power'] = round(event_data['power'] * 0.1, 1)
-
- if 'status' in event_data and event_data['status'] == 'finished':
- event_data['reasonDesc'] = self.analysis_reason(event_data.get('reason'), event_data.get('fault_code'))
-
- if 'leftTime' in event_data:
- pass
-
- if 'leftElec' in event_data:
- event_data['leftElec'] = round(event_data['leftElec'] * 0.01, 2)
-
- return event_data
- class MyComNetPayAckEvent(ComNetPayAckEvent):
-
- def __init__(self, smartBox, event_data):
- super(MyComNetPayAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
-
- def post_before_start(self, order=None):
-
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_running': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
-
- def post_after_start(self, order=None):
- pass
-
- def post_before_finish(self, order=None):
-
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_finished': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
-
- def post_after_finish(self, order=None):
- pass
-
- def merge_order(self, master_order, sub_orders):
- # type:(ConsumeRecord, list)->dict
-
- cType, cValue = self.event_data['cType'], self.event_data['cValue']
-
- start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
-
- portDict = {
- }
-
- all_coins = master_order.package['coins']
- all_price = master_order.package['price']
- for sub_order in sub_orders:
- all_coins += sub_order.package['coins']
- all_price += sub_order.package['price']
-
- if 'sub' in self.event_data:
- for sub_data in self.event_data['sub']:
- cValue += sub_data['cValue']
-
- portDict['coins'] = str(all_coins)
- portDict['price'] = str(all_price)
- portDict['cType'] = cType
- if cType == 1: # 时间
- portDict['needKind'] = 'needTime'
- portDict['needValue'] = cValue
- portDict['estimatedTs'] = int(start_time.timestamp + cValue * 60)
- portDict['unit'] = u'分钟'
- elif cType == 2: # 电量
- portDict['needKind'] = 'needElec'
- portDict['needValue'] = cValue
- portDict['estimatedTs'] = int(start_time.timestamp + 720 * 60)
- portDict['unit'] = u'度'
-
- portDict['consumeType'] = 'mobile'
-
- return portDict
-
- def do_finished_event(self, master_order, sub_orders, merge_order_info):
- # type: (ConsumeRecord, [ConsumeRecord], dict)->None
-
- self._do_finished(master_order, sub_orders, merge_order_info)
-
- def insert_vCard_consume_record(self, vCard, order, success, consumeTotal, consumeDay):
- try:
- if success and consumeDay['count'] > 0:
- record = VCardConsumeRecord(
- orderNo=VCardConsumeRecord.make_no(order.logicalCode),
- openId=order.openId,
- nickname=order.nickname,
- cardId=str(vCard.id),
- dealerId=vCard.dealerId,
- devNo=order.devNo,
- devTypeCode = order.devTypeCode,
- devTypeName = order.dev_type_name,
- logicalCode=order.logicalCode,
- groupId=order.groupId,
- address=order.address,
- groupNumber=order.groupNumber,
- groupName=order.groupName,
- attachParas=order.attachParas,
- consumeData=consumeTotal,
- consumeDayData=consumeDay
- )
- record.save()
- except Exception, e:
- logger.exception(e)
-
- def _do_finished(self, order, sub_orders, merge_order_info):
- # type: (ConsumeRecord, list, dict)->None
-
- duration, elec, cType, leftTime, leftElec = self.event_data.get('duration', 0), self.event_data.get('elec',
- 0), self.event_data.get(
- 'cType'), self.event_data.get('leftTime', 0), self.event_data.get('leftElec', 0)
- coins, price, needValue = VirtualCoin(merge_order_info['coins']), RMB(merge_order_info['price']), \
- merge_order_info['needValue']
-
- refundRatio = 0.0
- if cType == 1: # 按时计费
- if leftTime > needValue:
- leftTime = needValue
- refundRatio = leftTime * 1.0 / needValue
- elif cType == 2: # 按量计费
- if leftElec > needValue:
- leftElec = needValue
- refundRatio = leftElec * 1.0 / needValue
-
- backCoins = coins * refundRatio
- # refundRMB = price * refundRatio
-
- auto_refund = self.device.is_auto_refund
-
- refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
-
- user = MyUser.objects(openId=order.openId,
- groupId=order.groupId).first() # type: MyUser
-
- if duration < refundProtectionTime:
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- if auto_refund:
- usedFee = coins - backCoins
- else:
- usedFee = coins
-
- logger.debug('{} auto refund enable switch is {}, refund protect time = {} backMoney={}'.format(
- repr(self.device), str(auto_refund), refundProtectionTime, backCoins))
-
- extra = []
- extra.append({u'本次使用时长': u'{}(分钟)'.format(duration)})
-
- if order.paymentInfo['via'] == 'free':
- extra.append({u'消费金额': u'当前设备免费使用'})
-
- elif order.paymentInfo['via'] in ['netPay', 'coins', 'cash', 'coin']:
- extra.append({u'消费金额': '{}(金币)'.format(usedFee)})
- if backCoins > VirtualCoin(0):
- extra.append({u'退款金额': '{}(金币)'.format(backCoins)})
-
- order_processing_list = [order] + sub_orders
- for order_ in order_processing_list[::-1]:
- consumeDict = {
- 'reason': self.event_data.get('reasonDesc', None),
- 'chargeIndex': str(order.used_port)
- }
-
- need_back_coins, need_consume_coins, backCoins = self._calc_refund_info(backCoins, order_.coin)
-
- user.clear_frozen_balance(str(order_.id), order_.paymentInfo['deduct'],
- back_coins=need_back_coins,
- consume_coins=need_consume_coins)
-
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.COIN: order_.coin.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: need_back_coins.mongo_amount,
- })
- # 子单直接更新
- if order_ in sub_orders:
- order_.update_service_info(consumeDict)
- # 主单需要填写聚合信息后进行更新
- else:
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.DURATION: duration,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: elec,
- DEALER_CONSUMPTION_AGG_KIND.ELECFEE: self.deviceAdapter.calc_elec_fee(elec),
- })
- order.update_service_info(consumeDict)
- else:
- logger.error('not net pay rather user virtual card pay. something is wrong.')
- return
-
- auth_bridge = get_wechat_auth_bridge(source=self.device,
- app_type=APP_TYPE.WECHAT_USER_MANAGER)
-
- self.notify_user_service_complete(
- service_name='充电',
- openid=user.get_bound_pay_openid(auth_bridge.bound_openid_key),
- port=str(order.used_port),
- address=order.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
-
- def _calc_refund_info(self, backCoins, orderCoin):
- if backCoins >= orderCoin:
- need_back_coins = orderCoin
- need_consume_coins = VirtualCoin(0)
- backCoins -= orderCoin
- else:
- need_back_coins = backCoins
- need_consume_coins = orderCoin - need_back_coins
- backCoins = VirtualCoin(0)
-
- return need_back_coins, need_consume_coins, backCoins
- class CardStartAckEventPreProcessor(AckEventProcessorIntf):
-
- def analysis_reason(self, reason, fault_code=None):
-
- FINISHED_CHARGE_REASON_MAP = {
- 0: u'购买的充电时间或者电量已经用完',
- 1: u'充满自停',
- 2: u'刷卡用户按停止键',
- 3: u'未接负载30秒自停',
- 4: u'充电器移除',
- 5: u'充电功率超限',
-
- # 服务器定义的停止事件
- 97: u'用户使用离线卡手动操作退费 ,充电结束',
- 98: u'用户手动点击结束按钮结束充电',
- 99: u'远程点击停止按钮, 充电结束',
- }
-
- if reason == 0xEE:
- if fault_code:
- fault_code = '{:X}'.format(fault_code)[-1]
- FAULT_ERROR_MAP = {
- '1': '(键盘故障)',
- '2': '(显示器故障)',
- '3': '(刷卡板故障)',
- '4': '(子网故障)',
- '5': '(存储故障)',
- '6': '(过温故障)',
- '7': '(烟雾故障)',
- '8': '(漏电)',
- '9': '(短路)',
- 'A': '(过压)',
- 'B': '(欠压)',
- 'C': '(整机过流)',
- 'D': '(恶意操作)',
- 'E': '(继电器粘连) ',
- 'F': '(其它故障) ',
- }
- return '充电桩发生故障' + FAULT_ERROR_MAP.get(fault_code)
-
- return '充电桩发生故障'
- return FINISHED_CHARGE_REASON_MAP.get(reason)
-
- def pre_processing(self, device, event_data):
- # type:(DeviceDict, dict)->dict
-
- source = json.dumps(event_data, indent=4)
- event_data['source'] = source
-
- if 'cardNo' in event_data:
- cardNo = '{}'.format(int(event_data['cardNo'], 16))
- event_data['cardNo'] = cardNo
-
- if 'myDuration' in event_data:
- duration = event_data.pop('myDuration', 0)
- event_data['myDuration'] = round((duration + 59) / 60.0, 2)
-
- if 'myElec' in event_data:
- myElec = event_data.pop('myElec', 0)
- event_data['myElec'] = round(myElec / 3600000.0 * 0.1, 2) # 功率上报的功率是x10的
-
- if 'fts' in event_data and 'sts' in event_data:
- duration = event_data['fts'] - event_data['sts']
- event_data['duration'] = round((duration + 59) / 60.0, 2)
-
- if 'elec' in event_data:
- event_data['elec'] = round(event_data.pop('elec') * 0.01, 2)
-
- if 'needTime' in event_data:
- pass
-
- if 'needElec' in event_data:
- event_data['needElec'] = round(event_data['power'] * 0.01, 2)
-
- if 'power' in event_data:
- event_data['power'] = round(event_data['power'] * 0.1, 1)
-
- if 'status' in event_data and event_data['status'] == 'finished':
- event_data['reasonDesc'] = self.analysis_reason(event_data.get('reason'), event_data.get('fault_code'))
-
- if 'leftTime' in event_data:
- pass
-
- if 'leftElec' in event_data:
- event_data['leftElec'] = round(event_data['leftElec'] * 0.01, 2)
-
- if 'fee' in event_data:
- event_data['fee'] = round(event_data['fee'] * 0.1, 2)
-
- if 'refundFee' in event_data:
- event_data['refundFee'] = round(event_data['refundFee'] * 0.1, 2)
-
- if 'balance' in event_data:
- event_data['balance'] = round(event_data['balance'] * 0.1, 2)
-
- if 'sub' in event_data:
- for sub_dict in event_data['sub']:
- if 'fee' in sub_dict:
- sub_dict['fee'] = round(sub_dict['fee'] * 0.1, 2)
-
- if 'power' in sub_dict:
- sub_dict['power'] = round(sub_dict['power'] * 0.1, 1)
-
- if 'needTime' in event_data:
- pass
-
- if 'needElec' in event_data:
- event_data['needElec'] = round(event_data['power'] * 0.01, 2)
-
- return event_data
- class OfflineCardStartAckEvent(IcStartAckEvent):
- def __init__(self, smartBox, event_data):
- super(OfflineCardStartAckEvent, self).__init__(smartBox, event_data, CardStartAckEventPreProcessor())
-
- def post_before_start(self, order=None):
-
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_running': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
-
- def post_after_start(self, order=None):
- pass
-
- def post_before_finish(self, order=None):
-
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_finished': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
-
- def post_after_finish(self, order=None):
- pass
-
- def merge_order(self, master_order, sub_orders):
- # type:(ConsumeRecord, list)->dict
-
- start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
-
- portDict = {
- }
-
- cType = self.event_data['cType']
- all_coins = VirtualCoin(master_order.coin)
- all_money = RMB(master_order.money)
- all_consume_time = self.event_data.get('needTime', 0)
- all_consume_elec = self.event_data.get('needElec', 0)
-
- for sub_order in sub_orders:
- all_coins += VirtualCoin(sub_order.coin)
- all_money += RMB(sub_order.money)
-
- if self.event_data.get('sub', []):
- for _ in self.event_data['sub']:
- all_consume_time += _.get('needTime', 0)
- all_consume_elec += _.get('needElec', 0)
-
- portDict['cType'] = cType
- portDict['coins'] = str(all_coins)
- portDict['money'] = str(all_money)
-
- if cType == 1:
- portDict['needValue'] = all_consume_time
- portDict['needKind'] = 'needTime'
- portDict['unit'] = u'分钟'
- portDict['estimatedTs'] = int(start_time.timestamp + all_consume_time * 60)
- # portDict['all_consume_time_value'] = all_consume_time
-
- elif cType == 2:
- portDict['needValue'] = all_consume_elec
- portDict['needKind'] = 'needElec'
- portDict['unit'] = u'度'
- portDict['estimatedTs'] = int(start_time.timestamp + 3600 * 12)
- # portDict['all_consume_elec_value'] = all_consume_elec
-
- portDict['consumeType'] = 'card'
- return portDict
-
- def _do_finished(self, order, merge_order_info):
- # type: (ConsumeRecord, dict)->None
- # 离线卡 只记录 不处理!!!
-
- duration, elec = self.event_data.get('duration', 0), self.event_data.get('elec', 0)
-
- consumeDict = {
- 'reason': self.event_data.get('reasonDesc', None),
- 'chargeIndex': str(order.used_port),
- 'cardNo': self.event_data['cardNo'],
- }
-
- leftTime = self.event_data.get('leftTime', 0)
- leftElec = self.event_data.get('leftElec', 0)
- refundFee = self.event_data.get('refundFee', 0)
- balance = self.event_data.get('balance', 0)
-
- if 'sub' in self.event_data:
- for sub_info in self.event_data['sub'][::-1]:
-
- sub_order = ConsumeRecord.objects.filter(devNo=self.device.devNo, startKey=sub_info['order_id']).first()
- if not sub_order:
- continue
- subConsumeDict = {
- 'reason': self.event_data.get('reasonDesc', None),
- 'chargeIndex': str(order.used_port),
- 'cardNo': self.event_data['cardNo'],
- }
-
- if 'refundFee' in self.event_data:
-
- # 做一个数据保护
- if refundFee > merge_order_info['coins']:
- refundFee = merge_order_info['coins']
-
- sub_fee = sub_info.get('fee')
- if refundFee > sub_fee:
- subConsumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: 0,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: sub_fee,
- })
- refundFee -= sub_fee
- else:
- consumeFee = sub_fee - refundFee
- subConsumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: consumeFee,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: refundFee,
- })
- refundFee = 0
-
- else:
-
- if 'needTime' in self.event_data:
-
- # 做一个数据保护
- if leftTime > merge_order_info['needValue']:
- leftTime = merge_order_info['needValue']
-
- needTime = sub_info.get('needTime')
- subConsumeDict.update({
- 'needTime': needTime,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: sub_order.coin,
- })
-
- if leftTime > sub_info.get('needTime'):
- # 全退
- subConsumeDict.update({
- 'leftTime': needTime,
- 'duration': 0,
- })
- leftTime -= needTime
-
- else:
- # 部分退
- usedTime = needTime - leftTime
- leftTime = 0
- subConsumeDict.update({
- 'leftTime': leftTime,
- 'duration': usedTime,
- })
-
- elif 'needElec' in self.event_data:
-
- # 做一个数据保护
- if leftElec > merge_order_info['needValue']:
- leftElec = merge_order_info['needValue']
-
- needElec = sub_info.get('needElec')
- subConsumeDict.update({
- 'needElec': needElec,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: sub_order.coin,
- })
-
- if leftElec > needElec:
- # 全退
- subConsumeDict.update({
- 'leftElec': needElec,
- 'elec': 0,
- 'elecFee': self.deviceAdapter.calc_elec_fee(0),
- })
- leftElec -= needElec
-
- else:
- # 部分退
- usedElec = needElec - leftElec
- subConsumeDict.update({
- 'leftElec': leftElec,
- 'elec': usedElec,
- 'elecFee': self.deviceAdapter.calc_elec_fee(elec),
- })
- leftElec = 0
-
- sub_order.update_service_info(subConsumeDict)
-
- if 'refundFee' in self.event_data:
- fee = self.event_data.get('fee', 0)
- if refundFee > fee:
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: 0,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: fee,
- })
- else:
- consumeFee = fee - refundFee
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: consumeFee,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: refundFee,
- })
- else:
-
- if 'needTime' in self.event_data:
- if leftTime > self.event_data['needTime']:
- # 全退
- consumeDict.update({
- 'leftTime': self.event_data['needTime'],
- 'duration': 0,
- 'needTime': self.event_data['needTime']
- })
-
- else:
- # 部分退
- usedTime = self.event_data['needTime'] - leftTime
- consumeDict.update({
- 'leftTime': leftTime,
- 'duration': usedTime,
- 'needTime': self.event_data['needTime']
- })
-
- if 'needElec' in self.event_data:
- if leftElec > self.event_data['needElec']:
- # 全退
- consumeDict.update({
- 'leftElec': self.event_data['needElec'],
- 'elec': 0,
- 'needElec': self.event_data['needElec'],
- 'elecFee': self.deviceAdapter.calc_elec_fee(0),
- })
-
- else:
- # 部分退
- usedElec = self.event_data['needElec'] - leftElec
- consumeDict.update({
- 'leftElec': leftTime,
- 'elec': usedElec,
- 'needElec': self.event_data['needElec'],
- 'elecFee': self.deviceAdapter.calc_elec_fee(usedElec),
- })
-
- order.update_service_info(consumeDict)
-
- extra = [
- {u'线下卡': '{}--No:{}'.format(self.card.cardName, self.card.cardNo)},
- {u'本次使用时长': '{}(分钟)'.format(duration)},
- ]
-
- if refundFee > 0:
- extra.append({u'退费金额': '{}'.format(refundFee)})
- extra.append({u'卡余额': '{}'.format(balance)})
-
- self.notify_user_service_complete(
- service_name='充电',
- openid=self.card.managerialOpenId,
- port=str(order.used_port),
- address=order.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
-
- def do_finished_event(self, order, merge_order_info):
- # type:(ConsumeRecord, dict)->None
- self._do_finished(order, merge_order_info)
-
- def checkout_order(self, order):
- # 离线卡 只记录不处理
- pass
- class OnlineCardStartAckEvent(IdStartAckEvent):
- def __init__(self, smartBox, event_data):
- super(OnlineCardStartAckEvent, self).__init__(smartBox, event_data, CardStartAckEventPreProcessor())
-
- def post_before_start(self, order=None):
-
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_running': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
-
- def post_after_start(self, order=None):
- pass
-
- def post_before_finish(self, order=None):
-
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_finished': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
-
- def post_after_finish(self, order=None):
- pass
-
- def merge_order(self, master_order, sub_orders):
- # type:(ConsumeRecord, list)->dict
-
- start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
-
- portDict = {
- }
-
- cType = self.event_data['cType']
- all_coins = VirtualCoin(master_order.coin)
- all_money = RMB(master_order.money)
- all_consume_time = self.event_data.get('needTime', 0)
- all_consume_elec = self.event_data.get('needElec', 0)
-
- for sub_order in sub_orders:
- all_coins += VirtualCoin(sub_order.coin)
- all_money += RMB(sub_order.money)
-
- if self.event_data.get('sub', []):
- for _ in self.event_data['sub']:
- all_consume_time += _.get('needTime', 0)
- all_consume_elec += _.get('needElec', 0)
-
- portDict['cType'] = cType
- portDict['coins'] = str(all_coins)
- portDict['money'] = str(all_money)
-
- if cType == 1:
- portDict['needValue'] = all_consume_time
- portDict['needKind'] = 'needTime'
- portDict['unit'] = u'分钟'
- portDict['estimatedTs'] = int(start_time.timestamp + all_consume_time * 60)
- # portDict['all_consume_time_value'] = all_consume_time
-
- elif cType == 2:
- portDict['needValue'] = all_consume_elec
- portDict['needKind'] = 'needElec'
- portDict['unit'] = u'度'
- portDict['estimatedTs'] = int(start_time.timestamp + 3600 * 12)
- # portDict['all_consume_elec_value'] = all_consume_elec
-
- portDict['consumeType'] = 'card'
- return portDict
-
- def _do_finished(self, order, merge_order_info):
- # type: (ConsumeRecord, dict)->None
-
- duration, elec = self.event_data.get('duration', 0), self.event_data.get('elec', 0)
-
- consumeDict = {
- 'reason': self.event_data.get('reasonDesc', None),
- 'chargeIndex': str(order.used_port),
- 'cardNo': self.event_data['cardNo'],
- }
-
- leftTime = self.event_data.get('leftTime', 0)
- leftElec = self.event_data.get('leftElec', 0)
- coins = VirtualCoin(merge_order_info['coins'])
- money = RMB(merge_order_info['money'])
-
- auto_refund = self.device.is_auto_refund
- refundProtectionTime = self.device.get('otherConf', {}).get('refundProtectionTime', 5)
-
- backCoins = VirtualCoin(0)
- usedFee = coins
- if duration <= refundProtectionTime:
- usedFee = VirtualCoin(0)
- if 'needTime' in self.event_data:
- leftTime = merge_order_info['needValue']
- if 'needElec' in self.event_data:
- leftElec = merge_order_info['needValue']
-
- else:
- if auto_refund:
- if 'needTime' in self.event_data:
-
- # 做一个数据保护
- if leftTime > merge_order_info['needValue']:
- leftTime = merge_order_info['needValue']
-
- backCoins = coins * Ratio(leftTime * 1.0 / merge_order_info['needValue'])
- elif 'needElec' in self.event_data:
-
- # 做一个数据保护
- if leftElec > merge_order_info['needValue']:
- leftElec = merge_order_info['needValue']
-
- backCoins = coins * Ratio(leftElec * 1.0 / merge_order_info['needValue'])
- usedFee = coins - backCoins
- else:
- pass
-
- # 分批塞入订单信息
- master_info = {
- 'order_id': self.event_data['order_id'],
- 'fee': self.event_data['fee'],
- }
-
- if 'needTime' in self.event_data:
- master_info.update({'needTime': self.event_data['needTime']})
-
- if 'needElec' in self.event_data:
- master_info.update({'needElec': self.event_data['needElec']})
-
- order_processing_list = [master_info]
-
- if 'sub' in self.event_data:
- order_processing_list += self.event_data['sub']
-
- # 订单服务信息与退款处理
- for info_ in order_processing_list[::-1]:
-
- order_ = ConsumeRecord.objects.filter(devNo=self.device.devNo, startKey=info_['order_id']).first()
- if not order_:
- continue
-
- if 'needTime' in self.event_data:
- needTime = info_.get('needTime')
- consumeDict.update({
- 'needTime': needTime,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: order_.coin,
- })
-
- if leftTime > info_.get('needTime'):
- # 全退
- back_ = VirtualCoin(order_.coin)
- consumeDict.update({
- 'leftTime': needTime,
- 'duration': 0,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: 0,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: order_.coin,
- })
-
- # 结单
- self.card.clear_frozen_balance(str(order_.id), back_)
- # 有退款 添加退款记录
- self.record_refund_money_for_card(back_, str(self.card.id), orderNo=order.orderNo)
-
- leftTime -= needTime
-
-
-
- else:
- # 部分退
- usedTime = needTime - leftTime
- coins_ = VirtualCoin(order_.coin)
- back_ = self.get_backCoins(coins_, leftTime, needTime)
- consumeDict.update({
- 'leftTime': leftTime,
- 'duration': usedTime,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: coins_ - back_,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: back_,
- })
-
- # 结单
- self.card.clear_frozen_balance(str(order_.id), back_)
- # 有退款 添加退款记录
- if back_ > VirtualCoin(0):
- self.record_refund_money_for_card(back_, str(self.card.id), orderNo=order.orderNo)
-
- leftTime = 0
-
- elif 'needElec' in self.event_data:
-
- needElec = info_.get('needElec')
- consumeDict.update({
- 'needElec': needElec,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: order_.coin,
- })
-
- if leftElec > needElec:
- # 全退
-
- back_ = VirtualCoin(order_.coin)
- consumeDict.update({
- 'leftElec': needElec,
- 'elec': 0,
- 'elecFee': self.deviceAdapter.calc_elec_fee(0),
- })
-
- # 结单
- self.card.clear_frozen_balance(str(order_.id), back_)
- # 有退款 添加退款记录
- self.record_refund_money_for_card(back_, str(self.card.id), orderNo=order.orderNo)
-
- leftTime -= needElec
-
- else:
- # 部分退
- usedElec = needElec - leftElec
- coins_ = VirtualCoin(order_.coin)
- back_ = self.get_backCoins(coins_, leftElec, needElec)
- consumeDict.update({
- 'leftElec': leftElec,
- 'elec': usedElec,
- 'elecFee': self.deviceAdapter.calc_elec_fee(elec),
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: coins_ - back_,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: back_,
- })
-
- # 结单
- self.card.clear_frozen_balance(str(order_.id), back_)
- # 有退款 添加退款记录
- if back_ > VirtualCoin(0):
- self.record_refund_money_for_card(back_, str(self.card.id), orderNo=order.orderNo)
-
- leftElec = 0
-
- order_.update_service_info(consumeDict)
-
- self.card.reload()
- extra = []
- extra.append({u'在线卡': '{}--No:{}'.format(self.card.cardName, self.card.cardNo)})
- extra.append({u'本次使用时长': '{}(分钟)'.format(duration)})
- extra.append({u'本次消费金额': '{}(金币)'.format(usedFee)})
- extra.append({u'卡片当前余额': '{}(金币)'.format(self.card.balance.mongo_amount)})
-
- self.notify_user_service_complete(
- service_name='充电',
- openid=self.card.managerialOpenId,
- port=str(order.used_port),
- address=order.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
-
- def do_finished_event(self, order, merge_order_info):
- # type:(ConsumeRecord, dict)->None
- self._do_finished(order, merge_order_info)
-
- def checkout_order(self, order):
- # 在线卡 执行扣费
- fee = VirtualCoin(order.coin)
- self.card.freeze_balance(transaction_id=str(order.id), fee=fee)
|