# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging from apilib.monetary import RMB from apilib.utils_sys import memcache_lock from apps.web.constant import FAULT_CODE, FAULT_LEVEL, ErrorCode from apps.web.device.models import Group from apps.web.eventer import EventBuilder from apps.web.eventer.base import WorkEvent, FaultEvent from apps.web.eventer.weifuleCommon import WeiFuLePolicyProcess from apps.web.user.models import WeifuleCardStamp, Card, CardRechargeOrder, CardRechargeRecord logger = logging.getLogger(__name__) created_order_32 = 32 executing_order_33 = 33 finished_order_34 = 34 id_card_request_35 = 35 card_recharge_order_37 = 37 fault_event_overload_38 = 38 # 整机功率过载 fault_event_relay_39 = 39 # 继电器故障 fault_event_counter_40 = 40 # 计量芯片故障 fault_event_mcu_36 = 36 # mcu重启 power_event_41 = 999 # 待设备实现 ic_consume_event_48 = 48 # ic卡花钱的时候,会上报此事件 part_sn_event = 49 # 组件上报相关信息 card_is_normal = 1 card_not_in_db = 2 card_is_forzen = 3 card_has_not_order = 4 # IC卡适用 card_less_balance = 5 # ID卡适用 card_type_is_ic = 6 # IC卡不允许当做ID卡使用 no_load_code = 7 class builder(EventBuilder): def __getEvent__(self, device_event): event_data = self.deviceAdapter.analyze_event_data(device_event['data']) if event_data is None: return None if event_data['fun_code'] in [created_order_32, executing_order_33, finished_order_34, id_card_request_35, card_recharge_order_37]: return ChargingWEIFULEWorkEvent(self.deviceAdapter, event_data) if event_data['fun_code'] in [fault_event_mcu_36, fault_event_overload_38, fault_event_relay_39, fault_event_counter_40]: return WEIFULEFaultEvent(self.deviceAdapter, event_data) if event_data['fun_code'] in [ic_consume_event_48]: return WEIFULEICCardConsume(self.deviceAdapter, event_data) if event_data['fun_code'] in [power_event_41]: return WEIFULEPowerEvent(self.deviceAdapter, event_data) class WEIFULEPowerEvent(WorkEvent): def do(self, **args): power = int(self.event_data['power']) orderNo = str(self.event_data['orderNo']) # PowerInfoManager.instence().append_power(orderNo, power) class WEIFULEICCardConsume(FaultEvent): def do(self, **args): cardNo = str(int(self.event_data['card_no'], 16)) stamp = self.event_data['stamp'] isCopy = WeifuleCardStamp.is_copy_card(cardNo, self.device['ownerId'], stamp) if isCopy: self.event_data.update({ 'faultName': u'复制卡告警', 'faultCode': FAULT_CODE.COPY_CARD, 'level': FAULT_LEVEL.CRITICAL, 'desc': u'卡号为:%s的卡,极可能是复制卡,建议冻结处理。' % cardNo }) super(WEIFULEICCardConsume, self).do() newObj = WeifuleCardStamp( cardNo=cardNo, dealerId=self.device['ownerId'], stamp=str(stamp), dateTimeAdded=datetime.datetime.now() ) newObj.save() class WEIFULEFaultEvent(FaultEvent): def do(self, **args): if self.event_data['fun_code'] == fault_event_mcu_36: self.event_data.update({ 'faultName': u'单片机告警', 'faultCode': FAULT_CODE.MCU_REBOOT, 'level': FAULT_LEVEL.NORMAL, 'desc': u'充电主板上的单片机重启。' }) elif self.event_data['fun_code'] == fault_event_relay_39: self.event_data.update({ 'faultName': u'继电器告警', 'port': int(self.event_data['port']), 'faultCode': FAULT_CODE.RELAY_FAULT, 'level': FAULT_LEVEL.CRITICAL, 'desc': u'继电器发送粘连。' }) elif self.event_data['fun_code'] == fault_event_counter_40: self.event_data.update({ 'faultName': u'计量芯片告警', 'port': int(self.event_data['port']), 'faultCode': FAULT_CODE.COUNTER_FAULT, 'level': FAULT_LEVEL.CRITICAL, 'desc': u'计量芯片获取功率失败。' }) elif self.event_data['fun_code'] == fault_event_overload_38: self.event_data.update({ 'faultName': u'整机功率过载告警', 'faultCode': FAULT_CODE.DEV_OVERLOAD, 'level': FAULT_LEVEL.FATAL, 'desc': u'整机功率超过7500瓦。' }) else: pass super(WEIFULEFaultEvent, self).do() class ChargingWEIFULEWorkEvent(WeiFuLePolicyProcess): # 微付乐的板子:根据设备上报上来的订单,创建正在服务的信息 def translate_reason(self, order): cause = order.get('cause') if cause == 0: if self.duration < self.refundProtectionTime: return u'充电已结束,如有异常情况,请联系本台设备经销商。' else: return u'订购的套餐已用完。' elif cause == 1: return u'用户拔掉充电器,或者插座脱落。' elif cause == 2: return u'用户刷卡停止充电。' elif cause == 3: return u'远程停止。' elif cause == 4: return u'整机过载,系统为了安全,关闭掉所有充电端口。' elif cause == 5: return u'充电端口电流过载,系统为了安全,关闭此充电端口。' elif cause == 6: return u'端口功率过载,系统为了安全,关闭此充电端口。' elif cause == 7: return u'端口空载。可能是插座松动、充电端口故障、或者充电电池故障。' elif cause == 8: return u'恭喜您电池已经充满。' elif cause == 9: if self.duration < self.refundProtectionTime: return u'充电已结束,如有异常情况,请联系设备经销商。' else: return u'套餐金额已用完' elif cause == 12: if self.duration < self.refundProtectionTime: return u'充电已结束,如有异常情况,请联系本台设备经销商。' else: return u'订购的时间已用完' elif cause == 13: if self.duration < self.refundProtectionTime: return u'充电已结束,如有异常情况,请联系本台设备经销商。' else: return u'订购的电量已用完' return u'充电结束。' def deal_with_ic_charge_event(self, msgDict): cardNo = str(int(self.event_data['card_no'], 16)) card = self.update_card_dealer_and_type(cardNo, 'IC') if not card: return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_not_in_db) elif card.frozen: return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_is_forzen) preBalance = RMB(self.event_data['balance'] / 100.0) self.update_balance_for_IC_card(card, preBalance) rechargeOrder = CardRechargeOrder.get_last_to_do_one(str(card.id)) if rechargeOrder: self.recharge_ic_card(card=card, preBalance=preBalance, rechargeType='append', order=rechargeOrder, need_verify=False) else: return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_has_not_order) def analyse_need_from_package(self, order): needKind, needValue, unit = 'needElec', 0, u'度' if order['chrmt'] == 'TIME': needKind = 'needTime' needValue = order['amount_time'] / 60 unit = u'分钟' else: needValue = order['amount_elec'] / 1000000.0 return needKind, needValue, unit def do(self, **args): devNo = self.device['devNo'] funCode = self.event_data['fun_code'] if funCode == card_recharge_order_37: # 如果是卡充值,直接回复订单 self.deal_with_ic_charge_event(self.event_data) elif funCode == id_card_request_35: self.response_id_card() else: # 处理任务事件 order = self.event_data['order'] logger.info('weifule charging event detected, devNo=%s' % (devNo,)) with memcache_lock(key='%s-%s-%s-finished' % (devNo, order['id'], funCode), value='1', expire=120) as acquired: if acquired: self._do_ack_order(order) try: if funCode == created_order_32: self._do_created_order_32(order) elif funCode == executing_order_33: self._do_exec_order_33(order) elif funCode == finished_order_34 and order['order_type'] != 'card_charge': self._do_finished_order_34(order) elif funCode == finished_order_34 and order['order_type'] == 'card_charge': self.update_card_recharge_for_success_event(order['id'], RMB(order['balance'] / 100.0)) except Exception: import traceback logger.warn(traceback.format_exc()) logger.info('deal order is finished < funCode: {} order: {} >'.format(funCode, order.get('id'))) else: logger.info('weifule charging event is doing !!!, devNo=%s' % (devNo,)) def recharge_ic_card(self, card, preBalance, rechargeType, order, need_verify=True): # type:(Card, RMB, str, CardRechargeOrder, bool)->bool """ # rechargeType有两种,一种是用直接覆写overwrite的方式,一种是append追加钱的方式。 # 不同的的设备,充值的方式还不一样.注意:money是实际用户付的钱,coins是给用户充值的钱,比如付10块(money),充15(coins)。 :param card: :param preBalance: :param rechargeType: :param order: :return: """ if not order or order.coins == RMB(0): return False status = Card.get_card_status(str(card.id)) if status == 'busy': return False Card.set_card_status(str(card.id), 'busy') try: # IC卡需要下发到设备,设备写卡,把余额打入卡中 if rechargeType == 'overwrite': sendMoney = preBalance + order.coins else: sendMoney = order.coins # 先判断order最近一次充值是否OK. 满足三个条件在认为上次充值成功: # 1、操作时间已经超过三天 # 2、操作结果是串口超时, 即result == 1 # 3、当前余额大于最后一次充值操作的充值前余额 if need_verify and len(order.operationLog) > 0: log = order.operationLog[-1] result = log['result'] time_delta = (datetime.datetime.now() - log['time']).total_seconds() last_pre_balance = RMB(log['preBalance']) if (result == ErrorCode.DEVICE_CONN_FAIL or result == ErrorCode.BOARD_UART_TIMEOUT) \ and (time_delta > 3 * 24 * 3600 or preBalance > last_pre_balance): logger.debug('{} recharge verify result is finished.'.format(repr(card))) order.update_after_recharge_ic_card(device=self.device, sendMoney=sendMoney, preBalance=preBalance, result=ErrorCode.SUCCESS, description=u'充值校验结束') # 现将订单状态改为待充值 CardRechargeRecord.add_record( card=card, group=Group.get_group(order.groupId), order=order, device=self.device) return False if self.device.support_reliable: # 如果是新版本的,只管发,结果根据异步的事件进行处理 self.deviceAdapter.recharge_card_async(card.cardNo, sendMoney, str(order.id)) return False else: operation_result, balance = self.deviceAdapter.recharge_card(card.cardNo, sendMoney, str(order.id)) order.update_after_recharge_ic_card(device=self.device, sendMoney=sendMoney, preBalance=preBalance, syncBalance=balance, result=operation_result['result'], description=operation_result['description']) if operation_result['result'] != ErrorCode.SUCCESS: return False if not balance: balance = preBalance + order.coins CardRechargeRecord.add_record( card=card, group=Group.get_group(order.groupId), order=order, device=self.device) # 刷新卡里面的余额 card.balance = balance card.lastMaxBalance = balance card.save() return True except Exception as e: logger.exception(e) return False finally: Card.set_card_status(str(card.id), 'idle')