# -*- coding: utf-8 -*- #!/usr/bin/env python import datetime import logging from decimal import Decimal from apilib.monetary import RMB from apilib.utils_datetime import to_datetime from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND, FAULT_LEVEL from apps.web.device.models import Device, Group from apps.web.eventer.base import FaultEvent, WorkEvent from apps.web.eventer import EventBuilder from apps.web.south_intf.platform import notify_event_to_north from apps.web.user.models import ServiceProgress, MyUser from apps.web.user.transaction_deprecated import refund_money logger = logging.getLogger(__name__) class builder(EventBuilder): def __getEvent__(self, device_event): if 'data' not in device_event: logger.warning('event of device has no data.'.format(self.device.devNo)) return event_data = self.deviceAdapter.analyze_event_data(device_event['data']) if event_data is None or 'cmdCode' not in event_data: return if event_data['cmdCode'] in ['88', '80', '01', '02', '03']: return ChargingCXJZWorkEvent(self.deviceAdapter, event_data) if event_data['cmdCode'] in ['04', 'AE']: return CXJZEventerFailure(self.deviceAdapter, event_data) class CXJZEventerFailure(FaultEvent): def do(self, **args): # 不改变之前的流程 if self.event_data["cmdCode"] == '04': return if self.event_data["cmdCode"] == "AE": return self._do_AE() def _do_AE(self): # 告警开关有无打开 以及 是否处于告警状态 if not self.event_data["buzzer"] or not self.event_data["smokeSwitch"]: return # 通知经销商 if self.is_notify_dealer(): self.notify_dealer( 'device_fault', **{ 'title': u"设备故障告警", 'device': u'%s号设备\\n' % self.device.groupNumber, 'faultType': u'设备烟雾告警\\n', 'notifyTime': u'%s\\n' % datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'fault': u"设备当前温度 {}, 烟雾浓度 {}".format(self.event_data["temperature"], self.event_data["smokeCon"]), } ) # 写入故障记录 self.record( faultCode = "AE", description = u"设备故障告警 当前温度 {}, 当前烟雾浓度 {}", title = u"设备故障", detail = u"", level = FAULT_LEVEL.NORMAL, portNo = 0 ) class ChargingCXJZWorkEvent(WorkEvent): def do(self, **args): devNo = self.device['devNo'] logger.info('cxjz charging event detected, devNo=%s, curInfo=%s' % (devNo, self.event_data)) if self.event_data['cmdCode'] in ['88', '80', '01', '02', '03']: port = str(self.event_data['port']) try: ctrInfo = Device.get_dev_control_cache(self.device['devNo']) lineInfo = ctrInfo.get(port) if (not lineInfo) or ('openId' not in lineInfo): logger.warning('openId is missing, lineInfo=%s' % lineInfo) return # 锁定用户 user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device['groupId']).first() # 判断是否为远程关闭 if 'leftTime' in lineInfo and 'leftElec' in lineInfo: leftTime = lineInfo['leftTime'] leftElec = lineInfo['leftElec'] reason = u'充电结束, 经销商远程关闭充电!' else: leftTime = self.event_data['leftTime'] leftElec = self.event_data['leftElec'] reason = self.event_data['reason'] startTime = to_datetime(lineInfo['startTime']) nowTime = datetime.datetime.now() if startTime > nowTime:#如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大 usedTime = 0 else: usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0))) actualNeedTime = usedTime + leftTime group = Group.get_group(self.device['groupId']) consumeDict = {'reason': self.event_data['reason'], 'leftTime': leftTime, 'leftElec': leftElec, 'chargeIndex': port, 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime, 'duration': usedTime} coins = RMB(lineInfo['coins']) if lineInfo['workMode'] == 0: # 按时间计费 self.notify_user(user.managerialOpenId if user else '', 'service_complete', **{ 'title': u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % ( reason, actualNeedTime, leftTime), 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % ( self.device['logicalCode'], port, group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) # 如果需要退款,计算退款数据. if not self.device.is_auto_refund: consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount}) ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict) else: backCoins = coins * (float(leftTime) / float(actualNeedTime)) if backCoins > coins: backCoins = coins consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.COIN: (coins - backCoins).mongo_amount, DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: backCoins.mongo_amount }) refund_money(self.device, backCoins, lineInfo['openId']) 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(user.managerialOpenId if user else '', 'refund_coins', **{ 'title': u'%s 按动态功率计算总时间为:%s分钟,还有:%s分钟的时间未使用完,给您退还成相应的金币:%s元,您下次可以接着使用哦' % ( self.event_data['reason'], actualNeedTime, leftTime, backCoins), 'backCount': u'金币:%s' % backCoins, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) elif lineInfo['workMode'] in [1, 2]: # 智能模式统一按照计量模式进行判断 self.notify_user(user.managerialOpenId if user else '', 'service_complete', **{ 'title': u'%s 您购买的电量为:%s度,剩余电量:%s度' % ( reason, lineInfo['needElec'], leftElec), 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % ( self.device['logicalCode'], port, group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) # 如果需要退款,计算退款数据. if not self.device.is_auto_refund: consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount }) ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict) return else: backCoins = RMB(coins.amount - coins.amount * (Decimal(lineInfo.get('needElec',1000)) - Decimal(str(leftElec)))/Decimal(lineInfo.get('needElec',1000))) if backCoins > coins: backCoins = coins consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.COIN: (coins - backCoins).mongo_amount, DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: backCoins.mongo_amount }) consumeDict.update({'refundedMoney': str(backCoins)}) refund_money(self.device, backCoins, lineInfo['openId']) 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(user.managerialOpenId if user else '', 'refund_coins', **{ 'title': u'%s 您购买的电量为:%s度,还有:%s度未使用完,给您退还成相应的金币:%s元,您下次可以接着使用哦' % ( self.event_data['reason'], lineInfo['needElec'], leftElec, backCoins), 'backCount': u'金币:%s' % backCoins, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) finally: Device.clear_port_control_cache(devNo, str(port)) elif self.event_data['cmdCode'] == '04': notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL, desc = self.event_data['reason'])