# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import random import time from typing import TYPE_CHECKING from apilib.monetary import sum_rmb, RMB, VirtualCoin, Ratio from apilib.utils_datetime import to_datetime from apps.web.common.models import District from apps.web.constant import Const, FAULT_CODE, FAULT_LEVEL, DEALER_CONSUMPTION_AGG_KIND from apps.web.core.accounting import Accounting from apps.web.core.helpers import ActionDeviceBuilder from apps.web.dealer.models import Dealer from apps.web.device.models import PortReport, Part, Group, Device from apps.web.device.timescale import FluentedEngine from apps.web.eventer import EventBuilder from apps.web.eventer.base import FaultEvent, WorkEvent from apps.web.south_intf.delixi import DelixiNorther from apps.web.south_intf.liangxi_fire import LiangXiXiaoFang from apps.web.south_intf.platform import notify_event_to_north, notify_event_to_north_v2, \ handle_and_notify_event_to_north_Dc from apps.web.south_intf.yuhuan_fire import YuhuanNorther from apps.web.south_intf.zhejiang_fire import send_event_to_zhejiang from apps.web.user.models import VCardConsumeRecord, ServiceProgress, UserVirtualCard, CardRechargeOrder, MyUser, \ Redpack, RechargeRecord from apps.web.user.models import Card if TYPE_CHECKING: from apps.web.device.models import GroupDict logger = logging.getLogger(__name__) class builder(EventBuilder): def __getEvent__(self, device_event): if 'data' not in device_event: return None # 100228 互感器事件处理 if 'type' in device_event: if device_event['type'] == 'alert': return InteroperatorAlertEvent(self.deviceAdapter, device_event) if device_event['type'] == 'report': return InteroperatorReport(self.deviceAdapter, device_event) else: event_data = self.deviceAdapter.analyze_event_data(device_event['data']) if event_data is None or 'cmdCode' not in event_data: return None if 'duration' in device_event: event_data.update({'duration': device_event['duration']}) if 'elec' in device_event: event_data.update({'elec': device_event['elec']}) if 'v' in device_event: event_data.update({'v': device_event['v']}) if 'today_coins' in device_event and 'ts' in device_event: event_data.update({'today_coins': device_event['today_coins']}) event_data.update({'ts': device_event['ts']}) if event_data.get('cmdCode') in ['03', '05', '11', '12', '17', '22']: return ChargingZHIXIA2WorkEvent(self.deviceAdapter, event_data) if event_data.get('cmdCode') == '0D': return ZHIXIA2FaultEvent(self.deviceAdapter, event_data) if event_data.get('cmdCode') == '35' or event_data.get('cmdCode') == '41': return ZHIXIA2InductorEvent(self.deviceAdapter, event_data) if event_data.get("cmdCode") == "2C": return ZhongRunYiHeCardEvent(self.deviceAdapter, event_data) return None class ChargingZHIXIA2WorkEvent(WorkEvent): @property def support_playback(self): if self.event_data['cmdCode'] in ['05']: return True else: return False def __parse_device_finished_data(self, event_data): duration = event_data.get('duration', -1) if duration != -1: if 'v' in event_data: duration = (duration / 60) elec = event_data.get('elec', -1) if elec != -1: if 'v' in event_data: elec = round(elec / (10000.0 * 3600.0), 3) else: elec = round(elec / 3600.0, 3) logger.debug('device duration is {}, device elec is {}'.format(duration, elec)) return duration, elec def do(self, **args): logger.info('zhixiakeji2 charging event detected, devNo=%s,info=%s' % (self.device.devNo, self.event_data)) if self.event_data['cmdCode'] == '03': if 'today_coins' in self.event_data and 'ts' in self.event_data: Accounting.syncOfflineCoin( self.device, datetime.datetime.fromtimestamp(self.event_data['ts']).strftime('%Y-%m-%d'), self.event_data['today_coins']) if self.event_data['coins'] > 0: FluentedEngine().in_put_coins_udp(devNo=self.device.devNo, ts=int(time.time()), coins=self.event_data['coins'], mode='uart') else: # 老的流程会单条记录上报记录 Accounting.recordOfflineCoin(device=self.device, report_ts=int(time.time()), coins=int(self.event_data['coins']), mode='uart', port=self.event_data.get('port', None)) try: # 如果是投币,直接把端口状态刷新下 self.deviceAdapter.get_port_status_from_dev() except Exception, e: logger.info('some err=%s' % e) YuhuanNorther.send_dev_status(self.device, self.event_data['port'], 1) elif self.event_data['cmdCode'] == '22': # ID在线卡刷卡查询余额 cardNo = self.event_data['cardNo'] fee = RMB(self.event_data['fee']) cardType = self.event_data['cardType'] card = self.update_card_dealer_and_type(cardNo) # 首先检查订单,并进行充值 # 不存在卡的情况下 直接 if not card: res = "03" elif not card.openId: res = '03' elif card.frozen: res = '04' # 有绑定的卡 并且卡没被冻结的情况下 else: # 刷新卡的金额 card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) result = self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order) card.reload() logger.info('cardNo=%s,openId=%s,result=%s,fee=%s,info=%s' % ( cardNo, card.openId, result, fee, self.event_data)) res = "01" if result["balance"] >= fee else "02" balance = RMB(0) if not card else card.balance try: logger.info("card is <{}> fee is <{}> response res is <{}>".format(cardNo, fee, res)) result = self.deviceAdapter.response_card_status(cardNo, balance, res) except Exception, e: logger.info('resp back error=%s' % e) return if fee <= RMB(0): # 仅仅是查询余额 logger.debug( 'query the balance of card in device'.format(card.cardNo, self.device.devNo)) return # 设备回复扣款成功,服务器就需要正式扣掉钱 if result['status'] == '01' and res == '01': virtual_card = card.bound_virtual_card if virtual_card is not None: group = Group.get_group(self.device['groupId']) VCardConsumeRecord( orderNo=VCardConsumeRecord.make_no(self.device.logicalCode), openId=card.openId, cardId=str(virtual_card.id), dealerId=card.dealerId, devNo=self.device.devNo, devTypeCode = self.device.devTypeCode, devTypeName = self.device.devTypeName, logicalCode=self.device['logicalCode'], groupId=group['groupId'], address=group['address'], groupNumber=self.device['groupNumber'], groupName=group['groupName'], ).save() else: self.consume_money_for_card(card, fee) # 记录卡消费记录以及消费记录 orderNo, cardOrderNo = self.record_consume_for_card(card, fee) # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来 ServiceProgress.register_card_service( self.device, -1, card, { 'orderNo': orderNo, 'money': self.event_data['fee'], 'coin': self.event_data['fee'], 'needTime': 0, 'cardOrderNo': cardOrderNo } ) # 通知微信,已经扣费 self.notify_balance_has_consume_for_card(card, fee) elif self.event_data['cmdCode'] == '11' and self.event_data['status'] == '01': # 开始启动某个端口 # 按下端口,开始使用。IC卡和ID卡都会上报这条信息。IC卡只记录消费记录信息,ID卡主要是上报了具体的某一个端口.ID卡和劲能的类似,主要是表示开始某一个端口以及回收余额 cardType = self.event_data['cardType'] card = self.update_card_dealer_and_type(self.event_data['cardNo'], cardType) # 这个地方将计费方式更新到 portDict 刷卡退费的时候会将刷卡的退费金额上报过来 结束事件需要这个字段 主要的是要更新consumeDict的字段 # 0 按时间收费 # 1 按度计费 consumeModule = self.device.get("otherConf", dict()).get("consumeModule", 0) if consumeModule == 0: self.event_data["billingType"] = "time" else: self.event_data["billingType"] = "elec" if cardType == 'ID': consumeDict = {'chargeIndex': self.event_data['port']} queryDict = {'device_imei': self.device.devNo, 'port': -1, 'isFinished': False, 'cardId': str(card.id), 'start_time': {'$gte': int(time.time()) - 3600}} progressDict = {'port': self.event_data['port']} ServiceProgress.update_progress_and_consume_rcd(ownerId=self.device.ownerId, queryDict=queryDict, consumeDict=consumeDict, updateConsume=True, progressDict=progressDict) # 找出对应的卡的ID记录到端口内存数据 queryDict.update(progressDict) rcds = ServiceProgress.get_collection().find(queryDict, {'consumeOrder': 1}, sort=[('start_time', -1)]) allCoins = sum_rmb([rcd['consumeOrder']['coin'] for rcd in rcds]) try: d = Device.objects(devNo=self.device.devNo).first() billingType = d.otherConf.get('billingType', 'time') if self.device.bill_as_service_feature.on: billingType = 'elec' actionBox = ActionDeviceBuilder.create_action_device(Device.get_dev(self.device.devNo)) cardTime = actionBox.get_freemode_volume_andsoon_config()['card1Time'] icMoney = int(actionBox.get_IC_coin_power_config()['icMoney']) / 10 allCardTime = int(int(allCoins) / icMoney) * int(cardTime) except Exception as e: logger.error('allCardTime error: %s' % e) allCardTime = 0 billingType = 'time' self.event_data.update({'cardOrderTime': str(allCardTime)}) self.event_data.update({'cardId': str(card.id)}) self.event_data.update({'openId': card.openId}) self.event_data.update({'coins': str(allCoins)}) self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)}) self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING}) self.event_data.update({'billingType': billingType}) Device.update_port_control_cache(self.device.devNo, self.event_data) # 记录该端口累计需要的时间和钱,cardId else: # IC卡,需要记录消费记录 if card is not None: fee = RMB(self.event_data['fee']) card.balance = RMB(self.event_data['balance']) try: card.save() except Exception, e: logger.exception(e) orderNo, cardOrderNo = self.record_consume_for_card(card, fee) ServiceProgress.register_card_service(self.device, self.event_data['port'], card, {'orderNo': orderNo, 'money': self.event_data['fee'], 'coin': self.event_data['fee'], 'cardOrderNo': cardOrderNo}) # 通知微信,已经扣费 self.notify_balance_has_consume_for_card(card, fee) self.event_data.update({'cardId': str(card.id)}) self.event_data.update({'openId': card.openId}) self.event_data.update({'coins': self.event_data['fee']}) self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)}) self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING}) Device.update_port_control_cache(self.device.devNo, self.event_data) # 记录该端口累计需要的时间和钱,cardId YuhuanNorther.send_dev_status(self.device, self.event_data['port'], 1) elif self.event_data['cmdCode'] == '17': # 余额回收 card = self.update_card_dealer_and_type(self.event_data['cardNo'], 'IC') # type: Card if not card: logger.warning('Card is not registered.'.format( str(self.dealer.id), self.event_data['cardNo'])) return self.refund_money_for_card(RMB(self.event_data['backMoney']), card.id) elif self.event_data['cmdCode'] == '12': cardNo = self.event_data['cardNo'] preBalance = RMB(self.event_data['balance']) card = self.update_card_dealer_and_type(cardNo, 'IC', balance=preBalance) # type: Card if not card: return if card.frozen: logger.debug('{} has been frozen.'.format(repr(card))) return card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder if not card_recharge_order: logger.debug('{} has no recharge order.'.format(repr(card))) return self.recharge_ic_card(card=card, preBalance=preBalance, rechargeType='overwrite', order=card_recharge_order) elif self.event_data['cmdCode'] == '05': # 新版本的结束事件,比就版本多刷卡ID卡的在线退费 devNo = self.device.devNo port = str(self.event_data['port']) try: # 这个lineInfo 就是缓存全部的信息 lineInfo = Device.clear_port_control_cache(devNo, port) if not lineInfo: logger.debug('get null control cache from {}'.format(repr(self.device))) return logger.debug('port<{}> cache is: {}'.format(port, str(lineInfo))) if lineInfo.get('isApi', False) is True: self.event_data.update({'deviceCode': self.device['logicalCode']}) return handle_and_notify_event_to_north_Dc(self.device["devNo"], self.event_data) if lineInfo.get("ZRYH", False): return self._do_zryh_card_finish(devNo, port, lineInfo) billingType = lineInfo.get("billingType", "time") if self.device.bill_as_service_feature.on: billingType = 'elec' # 红包退费的判断处理 if 'redpackInfo' in lineInfo: for _info in lineInfo['redpackInfo']: redpack = Redpack.get_one(_info['redpackId']) redpackCoins = VirtualCoin(redpack['redpackCoins']) lineInfo['coins'] = float(VirtualCoin(lineInfo['coins']) - redpackCoins) redpackMoney = RMB(redpack['redpackMoney']) lineInfo['price'] = float(RMB(lineInfo['price']) - redpackMoney) logger.debug( 'redpack is <{}> redpack money is: {}; redpack coins is: {}'.format(redpack.get('id'), str(redpackMoney.amount), str(redpackCoins.amount))) if billingType == "elec": return self.do_elec_finish(devNo, port, lineInfo, self.event_data) else: return self.do_time_finish(devNo, port, lineInfo, self.event_data) finally: notify_event_to_north_v2(self.device["devNo"], self.event_data) notify_event_to_north(self.dealer, self.device, level=Const.EVENT_NORMAL, desc=self.event_data['reason']) send_event_to_zhejiang(self.dealer, self.device, self.event_data) if self.event_data['reasonCode'] == '04': # 功率过载导致的断电,一条告警,一条恢复告警 YuhuanNorther.send_dev_event(self.device, '97', port) YuhuanNorther.send_dev_event(self.device, '98', port) # 发送一条端口使用结束的告警 YuhuanNorther.send_dev_status(self.device, port, 2) def _do_zryh_card_finish(self, devNo, port, lineInfo): """ 中润易和的卡的结束 :param devNo: :param port: :param lineInfo: :return: """ logger.info("zryh dev = {} receice car stop event = {}".format(self.device.devNo, self.event_data)) coins = lineInfo["coins"] cardNo = lineInfo["cardNo"] leftTime = self.event_data["leftTime"] duration, elec = self.__parse_device_finished_data(self.event_data) # 时间重算一次 needTime = str(min(int(duration) + int(leftTime), int(lineInfo["needTime"]))) duration = str(int(needTime) - int(leftTime)) card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="ID") if not card: return consumeDict = { 'reason': self.event_data['reason'], 'leftTime': leftTime, 'chargeIndex': port, 'actualNeedTime': u"%s分钟" % needTime, 'duration': duration, } # 获取退费信息 if self.device.is_auto_refund: refundMoney = VirtualCoin(coins) * Ratio(Ratio(leftTime).amount / Ratio(needTime).amount) if refundMoney: self.refund_money_for_card(refundMoney, lineInfo["cardId"]) # 结算sp以及消费 ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { 'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False }, consumeDict ) # 发出通知 self.notify_user_service_complete( service_name=u'充电', openid=card.managerialOpenId if card else '', port=port, address=self.device.group['address'], reason=self.event_data['reason'], finished_time=to_datetime(self.recvTime).strftime('%Y-%m-%d %H:%M:%S'), extra=[{ u'实体卡号': cardNo }] ) def do_elec_finish(self, devNo, port, lineInfo, msgDict): """ 电川的板子 按电量退费 :return: """ logger.info("[{} do_elec_finish] devNo = {}, port = {}, lineInfo = {}, msgDict = {}, event = {}".format( self.__class__.__name__, devNo, port, lineInfo, msgDict, self.event_data)) if not self.dealer: logger.error( "[{} do_elec_finish] dealer {} is not found!".format(self.__class__.__name__, self.device.ownerId)) return # 提取事件信息 leftElec = self.event_data.get("leftTime", 0) / 100.0 reasonCode = self.event_data.get("endType") reasonStr = self.event_data.get("reason") cardNo = self.event_data.get("cardNo", None) cardType = self.event_data.get("cardType", None) price = RMB(lineInfo.get('price', 0)) startTime = lineInfo.get("startTime") # 投币事件 if not startTime: return startTime = to_datetime(startTime) recvTime = to_datetime(self.recvTime) # 启动时间小于300秒的 直接进行保险退款 if int((recvTime - startTime).total_seconds()) <= 300: rechargeIds = list() payInfo = lineInfo.get('payInfo', list()) for item in payInfo: if 'rechargeRcdId' not in item: continue rechargeIds.append(item['rechargeRcdId']) # 回归正常的处理流程 deviceDuration, deviceElec = self.__parse_device_finished_data(self.event_data) try: consumeDict = { "reason": reasonStr, "chargeIndex": port, "uartData": self.event_data.get('uartData', '') } # 计算充电的时间 if deviceDuration and deviceDuration > 0: usedTime = deviceDuration else: if startTime > recvTime: usedTime = 0 else: usedTime = int(round(((recvTime - startTime).total_seconds() / 60.0))) refundProtectionTime = self.device.get_other_conf_item('refundProtectionTime', 3) consumeDict.update({"duration": usedTime}) # 获取组信息 group = Group.get_group(self.device["groupId"]) coins = VirtualCoin(lineInfo.get("coins")) # 扫码的结束 if not cardNo: consumeDict.update({ "reason": reasonStr, "chargeIndex": port }) needElec = lineInfo.get("needElec") refundCoins = VirtualCoin(0) refundedMoney = RMB(0) if leftElec == int("FFFF", 16): refundCoins = VirtualCoin(coins) refundedMoney = RMB(price) leftElec = needElec spendElec = 0 else: if usedTime < refundProtectionTime: refundCoins = VirtualCoin(coins) refundedMoney = RMB(price) spendElec = 0 else: if leftElec > needElec: logger.error('left elec is bigger than need elec. something is wrong') leftElec = 0 spendElec = needElec - leftElec refundSwitch = self.device.is_auto_refund if refundSwitch: refundCoins = VirtualCoin(coins) * Ratio(leftElec / needElec) refundedMoney = RMB(price) * Ratio(leftElec / needElec) logger.debug('left elec = {}, duration = {}, need elec = {}, back coins = {}, refund cash = {}'.format( leftElec, usedTime, needElec, refundCoins, refundedMoney)) if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']: # 虚拟卡的结束 consumeRcdId = lineInfo['consumeRcdId'] vCardId = lineInfo.get("vCardId", "") vCard = UserVirtualCard.objects(id=vCardId).first() if not vCard: logger.info('can not find the vCard id = %s' % vCardId) return try: ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { 'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False }, consumeDict ) if refundCoins > VirtualCoin(0): vCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRcdId) vCard.refund_quota(vCardConsumeRcd, needElec - spendElec, spendElec, refundCoins.mongo_amount) finally: user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device.groupId).first() self.notify_user_service_complete( service_name=u'充电', openid=user.managerialOpenId if user else '', port=port, address=group['address'], reason=self.event_data['reason'], finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'), extra=[ {u'虚拟卡号': vCard.cardNo} ] ) elif 'openId' in lineInfo and lineInfo['openId']: # 扫码使用金币启动 user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device.groupId).first() try: is_cash = False if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0): is_cash = True consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: VirtualCoin(coins).mongo_amount}) if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0): consumeDict.update( {DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(coins) - refundCoins).mongo_amount}) self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash) if self.device.bill_as_service_feature.on: serviceFee = round(spendElec * float(self.device.bill_as_service_feature.service_charge),2) elecFee = round(spendElec * float(self.device.bill_as_service_feature.elec_charge),2) consumeDict.update({"elec": spendElec, "elecFee": elecFee,"serviceFee":serviceFee}) ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { 'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False }, consumeDict) finally: extra = [] if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict: real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH]) if real_refund > RMB(0): extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)}) extra.append({u'退款金额': '{}(元)'.format(real_refund)}) else: extra.append({u'消费金额': '{}(元)'.format(price)}) if self.device.bill_as_service_feature.on: elecCharge = round(spendElec * float(self.device.bill_as_service_feature.elec_charge),2) serviceCharge = round(spendElec * float(self.device.bill_as_service_feature.service_charge),2) extra.append({u'服务费金额': '{}(元)'.format(serviceCharge)}) extra.append({u'电费金额': '{}(元)'.format(elecCharge)}) elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict: real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS]) if real_refund > VirtualCoin(0): extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)}) extra.append({u'退款金额': '{}(金币)'.format(real_refund)}) else: extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))}) if self.device.bill_as_service_feature.on: elecCharge = round(spendElec * float(self.device.bill_as_service_feature.elec_charge),2) serviceCharge = round(spendElec * float(self.device.bill_as_service_feature.service_charge),2) extra.append({u'服务费金额': '{}(金币)'.format(serviceCharge)}) extra.append({u'电费金额': '{}(金币)'.format(elecCharge)}) else: extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))}) if self.device.bill_as_service_feature.on: elecCharge = spendElec * float(self.device.bill_as_service_feature.elec_charge) serviceCharge = spendElec * float(self.device.bill_as_service_feature.service_charge) extra.append({u'服务费金额': '{}(金币)'.format(serviceCharge)}) extra.append({u'电费金额': '{}(金币)'.format(elecCharge)}) self.notify_user_service_complete( service_name=u'充电', openid=user.managerialOpenId if user else '', port=port, address=group['address'], reason=self.event_data['reason'], finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'), extra=extra) else: logger.error('not net pay rather user virtual card pay. something is wrong.') else: backMoney = self.event_data.get("backMoney") # 刷卡的结束 如果没有开启刷卡退费 则结束上报过来的backMoney = 0 if cardType == "IC": # IC卡结束 只有刷卡结束的IC卡才能够刷新IC卡余额 card = self.update_card_dealer_and_type(cardNo, "IC") if self.device.bill_as_service_feature.on: total = float(self.deviceAdapter.get_elecCharge_function()) backMoney = leftElec * total needCoins = float(lineInfo.get('coins')) usedMoney = needCoins - backMoney elec = usedMoney / total elecFee = elec * float(self.device.bill_as_service_feature.elec_charge) serviceFee = elec * float(self.device.bill_as_service_feature.service_charge) consumeDict.update( {"elec": elec, "elecFee": elecFee, "serviceFee": serviceFee}) if reasonCode == "05" and backMoney > 0: # 原因为05表示刷卡结束充电,会把退费金额报上来. 否则只能通过11指令报上来 self.refund_money_for_card(VirtualCoin(backMoney), card.id) consumeDict.update({'balance': str(card.balance + VirtualCoin(backMoney))}) else: consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来 elif cardType == "ID": # ID卡结束 直接退费就行了 card = self.update_card_dealer_and_type(cardNo, "ID") if self.device.bill_as_service_feature.on: total = self.device.otherConf.get('totalCharge') backMoney = round(leftElec * total,2) needCoins = float(lineInfo.get('coins')) usedMoney = needCoins - backMoney elec = round(usedMoney / total,2) elecFee = round(elec * float(self.device.bill_as_service_feature.elec_charge),2) serviceFee = round(elec * float(self.device.bill_as_service_feature.service_charge),2) consumeDict.update( {"elec": elec, "elecFee": elecFee, "serviceFee": serviceFee}) if backMoney > 0: self.refund_money_for_card(RMB(backMoney), str(card.id)) consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: VirtualCoin(backMoney).mongo_amount }) consumeDict.update({'balance': str(card.balance + VirtualCoin(backMoney))}) else: logger.error("invalid card type event data is <{}>".format(self.event_data)) ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { 'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False }, consumeDict ) extra = [{u'实体卡号': cardNo}] if backMoney > 0: extra.append({ u'退款金额': u'{}(金币)'.format(backMoney) }) if self.device.bill_as_service_feature.on: extra.append({ u'消费电量':u'{}(度)'.format(elec), u'电费金额': u'{}(金币)'.format(elecFee), u'服务费金额': u'{}(金币)'.format(serviceFee), }) self.notify_user_service_complete( service_name=u'充电', openid=self.get_managerialOpenId_by_openId(lineInfo['openId']), port=port, address=group['address'], reason=self.event_data['reason'], finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'), extra=extra ) except Exception as e: logger.exception(e) def do_time_finish(self, devNo, port, lineInfo, msgDict): logger.info("[{} do_time_finish] devNo = {}, port = {}, lineInfo = {}, msgDict = {}, event = {}".format( self.__class__.__name__, devNo, port, lineInfo, msgDict, self.event_data)) try: if not self.dealer: logger.error( "[{} do_time_finish] dealer {} is not found!".format(self.__class__.__name__, self.device.ownerId)) return price = RMB(lineInfo.get('price', 0)) refundProtectionTime = self.device.get_other_conf_item('refundProtectionTime', 5) deviceDuration, deviceElec = self.__parse_device_finished_data(self.event_data) recvTime = to_datetime(self.recvTime) if lineInfo is not None and 'startTime' in lineInfo: startTime = to_datetime(lineInfo['startTime']) if startTime > recvTime: logger.error('start time is bigger than now time,devNo={}'.format(devNo)) serverDuration = -1 else: serverDuration = int(round((((recvTime - startTime).total_seconds() + 59) / 60.0))) else: logger.info('lineinfo has not startTime,devNo=%s' % devNo) serverDuration = -1 leftTime = self.event_data['leftTime'] logger.debug('serverDuration = {}; deviceDuration = {}; leftTime = {}; lineInfo = {}'.format( serverDuration, deviceDuration, leftTime, lineInfo)) if serverDuration < 0 and deviceDuration < 0: logger.warning('serverDuration and deviceDuration is valid. ignore this event.') return usedTime = 0 if leftTime == 65535: # 设备返回65535说明端口没有启动 leftTimeStr = u'端口未使用' actualNeedTime = 0 else: usedTime = max(serverDuration, deviceDuration) leftTimeStr = leftTime actualNeedTime = usedTime + leftTime if usedTime < refundProtectionTime: # 通过使用的时间来判断是否可以进行保险的退款 rechargeIds = list() payInfo = lineInfo.get('payInfo', list()) for item in payInfo: if 'rechargeRcdId' not in item: continue rechargeIds.append(item['rechargeRcdId']) group = self.device.group # type: GroupDict consumeDict = { 'reason': self.event_data['reason'], 'leftTime': leftTimeStr, 'chargeIndex': port, 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime, 'duration': usedTime, 'deviceDuration': deviceDuration, 'serverDuration': serverDuration, 'uartData': self.event_data.get('uartData', '') } try: groupObj = Group.objects(id=self.device.groupId).first() if groupObj.otherConf.get('zhuxing', None) is not None: spendElec = round((float(random.randint(15, 19)) / 100) * (float(usedTime) / 60), 3) consumeDict.update({'elec': spendElec}) consumeDict.update({'elecFee': self.deviceAdapter.calc_elec_fee(spendElec)}) else: if deviceElec != -1: consumeDict.update({'elec': deviceElec}) if deviceElec == 0 and usedTime > 0: consumeDict.update( {'elec': round((float(random.randint(15, 19)) / 100) * (float(usedTime) / 60), 3)}) else: consumeDict.update({'elec': 0.0}) consumeDict.update({'elecFee': RMB(0.0).mongo_amount}) except Exception as e: logger.error("device <{}> elec add error! <{}>".format(self.device.devNo, e)) # 涉及到卡的退费 不要以缓存为准 以设备上报的为准 cardNo = self.event_data.get("cardNo", None) if cardNo: # 如果是刷卡的,直接更新消费记录,发通知消息,支持ID卡的退费。 # IC卡的退费, 如果结束原因是刷卡退费(05), 则会把退费信息返回; # 否则不会把退费信息传过来,会通过11号命令返回 cardType = self.event_data.get("cardType") if cardType == 'ID': card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="ID") consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))}) if self.event_data.has_key('backMoney') and self.event_data['backMoney'] > 0: dealer = Dealer.objects(id=self.device.ownerId).first() if dealer is not None and 'doNotRefundIDcardForDC' in dealer.features: pass else: self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id) # 通知微信,已经退费 self.notify_user(card.managerialOpenId, 'refund_coins', **{ 'title': u'退币完成!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName), 'backCount': u'金币:%s' % VirtualCoin(self.event_data['backMoney']), 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S') }) elif cardType == "IC": card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="IC") if not card: logger.warning('Card is not registered.'.format( str(self.dealer.id), cardNo)) return # IC 并且结束code是05 表示卡贴上去了 if self.event_data['endType'] == '05': # 刷卡退费结束的时候,才能够刷新IC卡的余额 self.refund_money_for_card(VirtualCoin(self.event_data['backMoney']), card.id) consumeDict.update({'balance': str(card.balance + VirtualCoin(self.event_data['backMoney']))}) else: consumeDict.update({'balance': str(card.balance)}) # IC卡必须下次刷卡的时候回收上来 else: logger.error("invalid card type event data is <{}>".format(self.event_data)) ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId, {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False}, consumeDict) extra = [{ u'实体卡号': lineInfo['cardNo'] }] if VirtualCoin(self.event_data['backMoney']) > VirtualCoin(0): extra.append({ u'退费金额': u'{}(金币)'.format(self.event_data['backMoney']) }) templateMap = { 'cardCoins': lineInfo.get('coins', 0), 'cardOrderTime': lineInfo.get('cardOrderTime', 0), 'actualNeedTime': actualNeedTime, 'usedTime': usedTime, 'backCoins': self.event_data['backMoney'], 'reason': self.event_data['reason'] } title = self.generate_service_complete_title_by_devType(self.device['devType']['id'], templateMap) if title != '': # u"\\n\\n刷卡扣费金额:\\t\\t{cardCoins}\\n\\n刷卡订购时间:\\t\\t{cardOrderTime}\\n\\n动态功率计算时间:\\t\\t{actualNeedTime}\\n\\n使用时间:\\t\\t{usedTime}\\n\\n退款金额:\\t\\t{backCoins}\\n\\n结束原因:\\t\\t{reason}", self.notify_user( card.managerialOpenId if card else '', 'service_complete', **{ 'title': title, 'service': u'充电服务', 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'动态功率计算时间是指按照你的电动车功率大小进行折算出来的实际充电时间。' }) else: self.notify_user_service_complete( service_name=u'充电', openid=card.managerialOpenId if card else '', port=port, address=group['address'], reason=self.event_data['reason'], finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'), extra=extra) else: if 'coins' not in lineInfo: logger.warning('has no coins fields in lineInfo. may be coins start.') return coins = VirtualCoin(lineInfo['coins']) refundCoins = VirtualCoin(0) refundedMoney = RMB(0) if leftTime == 65535 or (usedTime < refundProtectionTime): refundCoins = coins refundedMoney = RMB(price) elif self.device.is_auto_refund: refundCoins = coins * (float(leftTime) / float(actualNeedTime)) refundedMoney = RMB(price * (float(leftTime) / float(actualNeedTime))) if refundCoins > coins: refundCoins = coins if refundedMoney > RMB(price): refundedMoney = RMB(price) logger.debug('left time = {}, duration = {}, need time = {}, back coins = {}'.format( leftTime, usedTime, actualNeedTime, refundCoins)) if 'consumeRcdId' in lineInfo and lineInfo['consumeRcdId']: vCardId = lineInfo['vCardId'] vCard = UserVirtualCard.objects(id=vCardId).first() # type: UserVirtualCard if not vCard: logger.info('can not find the vCard id = %s' % vCardId) return try: ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId, {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False}, consumeDict) if refundCoins > VirtualCoin(0): vCardConsumeRcd = VCardConsumeRecord.objects.get(id=lineInfo['consumeRcdId']) vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, refundCoins.mongo_amount) finally: user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device.groupId).first() self.notify_user_service_complete( service_name=u'充电', openid=user.managerialOpenId if user else '', port=port, address=group['address'], reason=self.event_data['reason'], finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'), extra=[ {u'虚拟卡号': vCard.cardNo} ] ) elif 'openId' in lineInfo and lineInfo['openId']: user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device.groupId).first() try: is_cash = False if 'refundRMB_device_event' in self.device.owner.features and refundedMoney > RMB(0): is_cash = True consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: VirtualCoin(coins).mongo_amount}) if refundedMoney > RMB(0) or refundCoins > VirtualCoin(0): consumeDict.update( {DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(coins) - refundCoins).mongo_amount}) self.refund_net_pay(user, lineInfo, refundedMoney, refundCoins, consumeDict, is_cash) ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId, {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device.devNo, 'isFinished': False}, consumeDict) finally: extra = [] if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict: real_refund = RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH]) if real_refund > RMB(0): extra.append({u'消费金额': '{}(元)'.format(RMB(price) - real_refund)}) extra.append({u'退款金额': '{}(元)'.format(real_refund)}) else: extra.append({u'消费金额': '{}(元)'.format(price)}) elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict: real_refund = VirtualCoin(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS]) if real_refund > VirtualCoin(0): extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins) - real_refund)}) extra.append({u'退款金额': '{}(金币)'.format(real_refund)}) else: extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))}) else: extra.append({u'消费金额': '{}(金币)'.format(VirtualCoin(coins))}) self.notify_user_service_complete( service_name=u'充电', openid=user.managerialOpenId if user else '', port=port, address=group['address'], reason=self.event_data['reason'], finished_time=recvTime.strftime('%Y-%m-%d %H:%M:%S'), extra=extra) else: logger.error('not net pay rather user virtual card pay. something is wrong.') except Exception as e: logger.exception(e) class ZHIXIA2FaultEvent(FaultEvent): LX_FAULE_CODE_MAP = { "01": "07", "02": "03", "03": "05" } def do_norther(self): """ 上报其他平台的,都在这个地方处理 可迁移至异步任务 :return: """ # 玉环的消防对接 YuhuanNorther.send_dev_event(self.device, self.event_data['FaultCode'], self.event_data['port']) DelixiNorther.send_dev_event(self.device, self.event_data) # 梁溪消防局的对接 faultContent = self.event_data["statusInfo"] faultCode = self.LX_FAULE_CODE_MAP.get(self.event_data["FaultCode"], "") districtInfo = District.get_district(self.device.group["districtId"]) self.device.update({"districtInfo": districtInfo, "groupAddr": self.device.group["address"]}) LiangXiXiaoFang.send_to_xf_fault(self.device, faultCode, faultContent, self.event_data["port"]) def do(self, **args): # 将告警的消息打入相应的缓存 port = self.event_data["port"] # 0 表示整机 if port == 0xFF: 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}) self.do_norther() super(ZHIXIA2FaultEvent, self).do() class ZHIXIA2InductorEvent(FaultEvent): def do(self, **args): # 处理数据 voltage = self.event_data.get('voltage', -1) temperature = self.event_data.get('temperature', -1) smokeWarning = self.event_data.get('smokeWarning', False) try: otherConf = Device.objects.get(devNo=self.device.devNo).otherConf maxVoltage = otherConf.get('voltageThre', 230) if voltage >= maxVoltage: desc = u'当前电压%s伏超过了门限值:%s伏' % (voltage, maxVoltage) self.record(faultCode=FAULT_CODE.OVER_VOLTAGE, description=desc, title=u'主机电压过高', detail=None, level=FAULT_LEVEL.CRITICAL) maxTemperature = otherConf.get('temThre', 60) if temperature > maxTemperature: desc = u'当前主机温度%s度超过了门限值:%s度' % (temperature, maxTemperature) self.record(faultCode=FAULT_CODE.OVER_TEMPERATURE, description=desc, title=u'主机温度过高', detail=None, level=FAULT_LEVEL.CRITICAL) self.send_fault_to_xf() if smokeWarning: desc = u'当前主机出现冒烟,请第一时间确定是否有起火。此告警十万火急,请迅速联系物业、消防相关部门!' self.record(faultCode=FAULT_CODE.SMOKE, description=desc, title=u'主机出现冒烟', detail=None, level=FAULT_LEVEL.FATAL) self.send_fault_to_xf() except Exception, e: logger.error('some error=%s' % e) return def send_fault_to_xf(self): try: code = self.event_data.get('cmdCode') # 无锡 梁溪区 粤万通 消防对接 推送 if code == '41': faultCode = '02' faultContent = u'烟雾报警' elif code == '35': faultCode = '01' faultContent = u'温度报警' else: return from taskmanager.mediator import task_caller task_caller('send_to_xf_falut', dealerId=self.device.ownerId, devNo=self.device.devNo, faultCode=faultCode, faultContent=faultContent) except Exception: pass class InteroperatorAlertEvent(FaultEvent): def __Analyze_alert_data(self, data): alertInfo = {'cmdCode': data['cmd'], 'logicalCode': self.device['logicalCode']} address = Group.get_group(self.device['groupId'])['address'] # 这里判断数据格式 if 'status' not in data: logger.error('Data arrays have no keywords status') return # 这里做漏电告警处理 if '5' in data['status']: electricityNum = str(int(data['values'][0:4], 16)) + 'mA' alertInfo['electricity'] = {'electricityNum': electricityNum, 'address': address, 'reasonCode': '12', 'reason': u'在{}编号为{}发生漏电,漏电量为{}' .format(address, self.device['logicalCode'], electricityNum)} # 这里做高温告警处理 if '6' in data['status']: temperatureAccess = [index for index, acces in enumerate(data['status'], 1) if acces == '6'] temperatureAlertList = [] for i in temperatureAccess: temperatureValue = str(int(data['values'][(i - 1) * 4:(i - 1) * 4 + 4], 16)) temperatureAlertList.append( {'temperatureValue': temperatureValue, 'address': address, 'reasonCode': '11', 'reason': u'在{}编号为{}的设备有高温预警,当前温度为{}摄氏度' .format(address, self.device['logicalCode'], temperatureValue)}) alertInfo['temperature'] = temperatureAlertList return alertInfo def do(self, **args): # 判断不存在的设备网上报 if not self.device.ownerId: logger.error('This device cant find a dealer') return # 是否存在温感和电感 temperaturePart = Part.objects(logicalCode=self.device['logicalCode'], partType='3001') electricityPart = Part.objects(logicalCode=self.device['logicalCode'], partType='3002') if not temperaturePart.count() or not electricityPart.count(): logger.error( 'There are no transformers in the locigalcode {} equipment'.format(self.device['logicalCode'])) return # 处理数据 eventInfo = self.__Analyze_alert_data(self.event_data['data']) try: # 先处理高温情况 if 'temperature' in eventInfo: for InfoDetail in eventInfo['temperature']: send_event_to_zhejiang(self.dealer, self.device, InfoDetail, partId=temperaturePart[0].id) # 提示用户 group = Group.get_group(self.device['groupId']) self.notify_dealer('device_fault', **{ 'title': u'注意!注意!您的设备发生故障', 'device': u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']), 'location': u'组名称:%s, 地址:%s' % (group['groupName'], group['address']), 'fault': InfoDetail['reason'], 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) # 上报高温至消防 # if self.device["ownerId"] in ("5b4ed32e8732d67bd0626528", "5b6c29388732d669f3ae6f94"): group = Group.get_group(self.device['groupId']) districtInfo = District.get_district(group["districtId"]) self.device.update({"districtInfo": districtInfo, "groupAddr": group["address"]}) LiangXiXiaoFang.send_to_xf_fault(self.device, "01", u"设备温度过高") # 处理漏电情况 elif 'electricity' in eventInfo: # 获取漏电告警插件 send_event_to_zhejiang(self.dealer, self.device, eventInfo['electricity'], partId=electricityPart[0].id) # 提示用户 group = Group.get_group(self.device['groupId']) self.notify_dealer('device_fault', **{ 'title': u'注意!注意!您的设备发生故障', 'device': u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']), 'location': u'组名称:%s, 地址:%s' % (group['groupName'], group['address']), 'fault': eventInfo['electricity']['reason'], 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) # 上报漏电至消防 # if self.device["ownerId"] in ("5b4ed32e8732d67bd0626528", "5b6c29388732d669f3ae6f94"): group = Group.get_group(self.device['groupId']) districtInfo = District.get_district(group["districtId"]) self.device.update({"districtInfo": districtInfo, "groupAddr": group["address"]}) LiangXiXiaoFang.send_to_xf_fault(self.device, "04", u"设备发生漏电") except: logger.error('Array {} nonspecification'.format(eventInfo)) return self.record(detail=eventInfo) class InteroperatorReport(WorkEvent): def do(self, **args): if 'type' not in self.event_data: logger.error('Array {} is not format,lose a key named "type"'.format(self.event_data)) if self.event_data.get('type') == 'report': devReportDict = {'logicalCode': 'logicalCode', 'time': self.event_data['time_stamp'], 'portInfo': {}} temperature = '' voltage = 220 try: # 拿到个数判断是不是第一次 reportNum = PortReport.get_collection().find({ 'logicalCode': self.device['logicalCode'] }).sort('time', -1).count() if reportNum: # 获取上一次存储的信息 reportLast = PortReport.get_collection().find({ 'logicalCode': self.device['logicalCode'] }).sort('time', -1)[0] for ii in range(10): power = self.__saveDate(1, msgDict=self.event_data, ii=ii) if power: electricity = float(power) / voltage / 10 else: electricity = reportLast['portInfo'][str(ii + 1)]['electricity'] temperatureR = self.__saveDate(2, msgDict=self.event_data, ii=ii, electricity=electricity, devReportDict=devReportDict) if temperatureR: temperature = temperatureR devReportDict.update({'temperature': temperature}) # 查看现在的跟以前差距多少 timeInterval = devReportDict['time'] - reportLast['time'] if timeInterval > 2: PortReportNewList = [ {"logicalCode": self.device['logicalCode'], "temperature": reportLast['temperature'], 'portInfo': reportLast['portInfo'], 'time': reportLast['time'] + (v + 1) * 2} for v in range(int(timeInterval / 2) - 1)] PortReport.get_collection().insert_many(PortReportNewList) # 首存的情况 else: for ii in range(10): power = self.__saveDate(1, msgDict=self.event_data, ii=ii) electricity = float(power) / voltage / 10 temperatureR = self.__saveDate(2, msgDict=self.event_data, ii=ii, electricity=electricity, devReportDict=devReportDict) if temperatureR: temperature = temperatureR devReportDict.update({'temperature': temperature}) except Exception, e: logger.error('solve dev=%s device report has an error e=%s' % (self.device.devNo, e)) finally: newInfo = PortReport( logicalCode=self.device['logicalCode'], temperature=devReportDict['temperature'], time=devReportDict['time'], portInfo=devReportDict['portInfo'] ) newInfo.save() def __saveDate(self, data, msgDict, ii, electricity=None, devReportDict=None): # 存储数据库 if data == 1: powerData = msgDict['data']['power_data'][0 + 4 * ii:4 + 4 * ii] power = int(powerData, 16) return power if data == 2: temperature = '' status = 'idle' if electricity == 0 else 'busy' devReportDict['portInfo'].update( {str(ii + 1): {'electricity': round(electricity, 3), 'status': status}}) if ii < 4 and msgDict['data']['temp_data'][0 + 4 * ii:4 + 4 * ii] != '0000': temperatureNum = msgDict['data']['temp_data'][0 + 4 * ii:4 + 4 * ii] temperature = int(temperatureNum, 16) return temperature class ZhongRunYiHeCardEvent(WorkEvent): # 中润易和 的刷卡启动 def do(self, **args): logger.info("zhong run yi he card event, event data = {}".format(self.event_data)) cardNo = self.event_data["cardNo"] portStr = self.event_data["portStr"] num = min(self.event_data["num"], 3) # 最多刷卡3次 # 是否是有效刷卡 当端口号为0的时候无效 if portStr == 0: logger.info("illegal card start ,cardNo = {}, devNo = {}".format(cardNo, self.device.devNo)) return # 判断卡 card = self.update_card_dealer_and_type(cardNo) # type: Card if not card or card.frozen: logger.info("illegal card ,cardNo = {}, devNo = {}".format(cardNo, self.device.devNo)) return card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) self.recharge_id_card(card, rechargeType="append", order=card_recharge_order) card.reload() # 判断钱 otherConf = self.device.get("otherConf") or dict() try: icMoney = otherConf['icMoney'] except KeyError: icSettings = self.deviceAdapter.get_IC_coin_power_config() icMoney = icSettings['icMoney'] needMoney = RMB(int(icMoney) / 10.0) * Ratio(num) if card.balance < needMoney: logger.info( "more Money, cardNo = {}, devNo = {}, icMoney = {}, num = {}".format(cardNo, self.device.devNo, icMoney, num)) return # 然后就是启动设备 # 获取启动的时间 try: card1Time = otherConf["card1Time"] card2Time = otherConf["card2Time"] card3Time = otherConf["card3Time"] except KeyError: cardTimeSettings = self.deviceAdapter.get_freemode_volume_andsoon_config() card1Time = cardTimeSettings["card1Time"] card2Time = cardTimeSettings["card2Time"] card3Time = cardTimeSettings["card3Time"] if num == 1: needTime = card1Time elif num == 2: needTime = card1Time + card2Time else: needTime = card1Time + card2Time + card3Time self.deviceAdapter._start_device_for_card(needTime, portStr) # 记录卡消费 card.balance -= needMoney card.save() orderNo, cardOrderNo = self.record_consume_for_card(card, needMoney, desc=u"刷卡消费") serviceDict = { "orderNo": orderNo, "cardOrderNo": cardOrderNo } # 记录缓存 ServiceProgress.register_card_service( self.device, int(portStr), card, serviceDict ) portDict = { "orderNo": orderNo, # 订单号码 "cardOrderNo": cardOrderNo, "cardNo": cardNo, # 卡号 0-99999999 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'coins': str(needMoney), 'price': str(needMoney), 'isStart': True, 'openId': card.openId, 'ZRYH': True, "needTime": needTime, "cardId": str(card.id) } Device.update_dev_control_cache(self.device["devNo"], {portStr: portDict})