# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging from apilib.monetary import RMB, VirtualCoin from apps import serviceCache from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND from apps.web.core.device_define.water_despenser import CMD_CODE from apps.web.dealer.models import Dealer from apps.web.device.models import Device, Group from apps.web.eventer.base import 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 taskmanager.mediator import task_caller logger = logging.getLogger(__name__) class builder(EventBuilder): def __getEvent__(self, device_event): event_data = self.deviceAdapter.analyze_event_data(device_event['data']) if not event_data or 'cmdCode' not in event_data: return None if event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_ALERT_EVENT_CODE: return WaterDispenserAlertEvent(self.deviceAdapter, event_data) if event_data['cmdCode'] in [ CMD_CODE.WATER_DISPENSE_SETTING_EVENT_CODE, CMD_CODE.WATER_DISPENSE_WORK_STATUS_EVENT_CODE, CMD_CODE.WATER_DISPENSE_FINISH_EVENT_CODE ]: return WaterDispenserWorkEvent(self.deviceAdapter, event_data) class WaterDispenserAlertEvent(WorkEvent): def do(self, **args): def _send_alert_message_to_dealer(dealer, group, fault): notifyData = { 'title': '设备故障', 'device': u'{gNum}组-{lc}'.format(gNum=self.device['groupNumber'], lc=self.device['logicalCode']), 'location': u'{address}-{groupName}'.format(address=group['address'], groupName=group['groupName']), 'fault': fault, 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') } task_caller( func_name='report_to_dealer_via_wechat', openId=dealer.managerialOpenId, dealerId=str(dealer.id), templateName='device_fault', **notifyData ) devNo = self.device['devNo'] logger.info('water dispenser event detected, devNo=%s, curInfo=%s' % (devNo, self.event_data)) if self.event_data['eventKey'] != '00': pass else: if self.event_data['isError'] is True: group = Group.objects(id=self.device['groupId']).first() dealer = Dealer.objects(id=self.device['ownerId']).first() portStatus = {} temp = [] if self.event_data['noWater'] is True: temp.append('noWater') if self.event_data['moreWater'] is True: temp.append('moreWater') if self.event_data['port1Leak'] is True: temp.append('port1Leak') if self.event_data['port2Leak'] is True: temp.append('port2Leak') if self.event_data['port1Error'] is True: temp.append('port1Error') if self.event_data['port2Error'] is True: temp.append('port2Error') cache_key = '' fault = u'' statusErrorInfo1 = u'' statusErrorInfo2 = u'' # 遍历temp, 然后更新数据 for _ in temp: cache_key += _ portStatus = { '1': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'}, '2': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'} } if 'noWater' == _: statusErrorInfo1 += u'水箱缺液' statusErrorInfo2 += u'水箱缺液' portStatus['1'].update({'statusErrorInfo': statusErrorInfo1}) portStatus['2'].update({'statusErrorInfo': statusErrorInfo2}) fault = u'水箱缺液!' if 'moreWater' == _: statusErrorInfo1 = statusErrorInfo1 + u' ' + u'水箱溢流' statusErrorInfo2 = statusErrorInfo2 + u' ' + u'水箱溢流' portStatus['1'].update({'statusErrorInfo': statusErrorInfo1}) portStatus['2'].update({'statusErrorInfo': statusErrorInfo2}) fault = fault + u' ' + u'水箱溢流!' if 'port1Leak' == _: statusErrorInfo1 = statusErrorInfo1 + u' ' + u'漏水' portStatus['1'].update({'statusErrorInfo': statusErrorInfo1}) fault = fault + u' ' + u'通道1漏水!' if 'port2Leak' == _: statusErrorInfo2 = statusErrorInfo2 + u' ' + u'漏水' portStatus['2'].update({'statusErrorInfo': statusErrorInfo2}) fault = fault + u' ' + u'通道2漏水!' if 'port1Error' == _: statusErrorInfo1 = statusErrorInfo1 + u' ' + u'电磁阀故障' portStatus['1'].update({'statusErrorInfo': statusErrorInfo1}) portStatus['1'].update({'status': Const.DEV_WORK_STATUS_FAULT}) fault = fault + u' ' + u'通道1电磁阀故障!' if 'port2Error' == _: statusErrorInfo2 = statusErrorInfo2 + u' ' + u'电磁阀故障' portStatus['2'].update({'statusErrorInfo': statusErrorInfo2}) portStatus['2'].update({'status': Const.DEV_WORK_STATUS_FAULT}) fault = fault + u' ' + u'通道2电磁阀故障!' jsjCache = serviceCache.get(dealer.username + '_jsj', 0) jsjData = dealer.username + '_' + cache_key if jsjCache == 0: _send_alert_message_to_dealer(dealer, group, fault) serviceCache.set(dealer.username + '_jsj', jsjData, 60 * 60) else: if jsjCache == jsjData: pass else: _send_alert_message_to_dealer(dealer, group, fault) serviceCache.set(dealer.username + '_jsj', jsjData, 60 * 60) Device.update_dev_control_cache(devNo, {'deviceId': self.event_data['deviceId']}) Device.update_dev_control_cache(devNo, portStatus) else: portStatus = { '1': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'}, '2': {'status': Const.DEV_WORK_STATUS_IDLE, 'statusErrorInfo': u'无'} } ctrlInfo = Device.get_dev_control_cache(devNo) if ctrlInfo.get('1', None) is not None and ctrlInfo.get('2', None) is not None: if ctrlInfo['1'].get('status', '') == 3: portStatus.update({'1': {'status': Const.DEV_WORK_STATUS_FORBIDDEN, 'statusErrorInfo': u'无'}}) if ctrlInfo['2'].get('status', '') == 3: portStatus.update({'2': {'status': Const.DEV_WORK_STATUS_FORBIDDEN, 'statusErrorInfo': u'无'}}) Device.update_dev_control_cache(devNo, {'deviceId': self.event_data['deviceId']}) Device.update_dev_control_cache(devNo, portStatus) class WaterDispenserWorkEvent(WorkEvent): def calc_backCoins(self, reason, need, left, coins): device = Device.objects(logicalCode=self.device['logicalCode']).first() minConsumeRatio = device.otherConf.get('minConsumeRatio', 5) minConsumeTime = int(need * (float(minConsumeRatio) / 100)) staticMinConsumeTime = int(need * 0.95) if left > need: backCoins = RMB('0.0') else: if reason in ['01', '05']: if (float(left) / float(need)) > (float(staticMinConsumeTime) / float(need)): backCoins = coins else: if (need - left) > minConsumeTime: backCoins = coins * (float(left) / float(need)) else: backCoins = coins * (1 - float(minConsumeRatio) / 100) elif reason == '04': if (need - left) > minConsumeTime: backCoins = coins * (float(left) / float(need)) else: backCoins= coins * (1-float(minConsumeRatio) / 100) elif reason == '06': if (float(left) / float(need)) > (float(staticMinConsumeTime) / float(need)): backCoins = coins else: backCoins = coins * (float(left) / float(need)) elif reason in ['03']: backCoins = coins elif reason in ['02', '08', '09']: backCoins = coins * (float(left) / float(need)) elif reason in ['07']: backCoins = RMB('0.0') else: backCoins = RMB('0.0') return backCoins def do(self, **args): devNo = self.device['devNo'] logger.info('WaterDispenser event detected, devNo=%s, curInfo=%s' % (devNo, self.event_data)) if self.event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_SETTING_EVENT_CODE: boardSoftVer = self.event_data['boardSoftVer'] return self.deviceAdapter.init_dev_settings(boardSoftVer) if self.event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_WORK_STATUS_EVENT_CODE: Device.update_dev_control_cache(devNo, {str(self.event_data['port']): {'isPause': False if self.event_data['isPause'] == '02' else True}}) return if self.event_data['cmdCode'] == CMD_CODE.WATER_DISPENSE_FINISH_EVENT_CODE: port = self.event_data['port'] reason = self.event_data['reason'] try: ctrInfo = Device.get_dev_control_cache(self.device['devNo']) lineInfo = ctrInfo.get(port) coins = lineInfo['coins'] refundedMoney = RMB('0.0') refundCoins = VirtualCoin('0.0') consumeDict = {} reasonDesc = self.event_data['desc'] reasonCode = self.event_data['reason'] agentId = Dealer.objects(id=self.device['ownerId']).first().agentId users = MyUser.objects(openId=lineInfo['openId'], agentId=agentId) for _ in users: breakRuleTimes = _.blacklistConfig.get('breakRuleTimes', 0) if reasonCode in ['08', '09']: breakRuleTimes += 1 if breakRuleTimes > 3: breakRuleTimes = 3 else: breakRuleTimes -= 1 if breakRuleTimes < 0: breakRuleTimes = 0 _.blacklistConfig['breakRuleTimes'] = breakRuleTimes _.save() # 计时 if lineInfo['consumeMode'] == '1': usedTime = self.event_data['duration'] needTime = lineInfo['needTime'] leftTime = needTime - usedTime consumeDict = {'reason': reasonDesc, 'desc': reasonDesc, 'chargeIndex': port, 'duration': usedTime} group = Group.get_group(self.device['groupId']) user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device['groupId']).first() # 通知服务结束 self.notify_user(user.managerialOpenId if user else '', 'service_complete', **{ 'title': u'%s' % reasonDesc, 'service': u'设备服务(设备编号:%s, 端口:%s,地址:%s)' % ( self.device['logicalCode'], port, group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict) backCoins = self.calc_backCoins(reason, needTime, leftTime, RMB(lineInfo['coins'])) refundedMoney = backCoins refundCoins = backCoins consumeDict.update({'refundedMoney': refundedMoney}) isRefund = True # 计量 elif lineInfo['consumeMode'] == '2': usedLitre = self.event_data['spendLitre'] needLitre = lineInfo['needLitre'] leftLitre = needLitre - usedLitre consumeDict = {'reason': reasonDesc, 'desc': reasonDesc, 'chargeIndex': port, 'usedLitre': usedLitre} group = Group.get_group(self.device['groupId']) user = MyUser.objects(openId=lineInfo['openId'], groupId=self.device['groupId']).first() # 通知服务结束 self.notify_user(user.managerialOpenId if user else '', 'service_complete', **{ 'title': u'%s' % reasonDesc, 'service': u'设备服务(设备编号:%s, 端口:%s,地址:%s)' % ( self.device['logicalCode'], port, group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'open_id': lineInfo['openId'], 'port': int(port), 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict) backCoins = self.calc_backCoins(reason, needLitre, leftLitre, RMB(lineInfo['coins'])) refundedMoney = backCoins refundCoins = backCoins consumeDict.update({'refundedMoney': refundedMoney}) isRefund = True else: user = None group = None isRefund = False if self.device.is_auto_refund is True and isRefund is True: 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) extra = [] price = RMB(lineInfo['price']) coins = VirtualCoin(coins) 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='服务完成', openid=user.managerialOpenId if user else '', port=port, address=group['address'], reason=reasonDesc, finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), extra=extra) finally: Device.clear_port_control_cache(devNo, str(port)) notify_event_to_north(self.dealer, self.device, level=Const.EVENT_NORMAL, desc=reason)