# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging from typing import TYPE_CHECKING from apilib.monetary import RMB from apilib.utils_sys import memcache_lock from apps.web.constant import ErrorCode from apps.web.device.models import Group from apps.web.eventer import EventBuilder from apps.web.eventer.weifuleCommon import WeiFuLeStatusEvent, WeiFuLePolicyProcess from apps.web.user.models import ServiceProgress, Card, CardRechargeOrder, CardRechargeRecord, UserVirtualCard logger = logging.getLogger(__name__) created_order_32 = 32 exec_order_33 = 33 finished_order_34 = 34 id_card_request_35 = 35 card_recharge_order_36 = 36 status_change_event_44 = 44 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 if TYPE_CHECKING: from apps.web.core.adapter.base import SmartBox from apps.web.core.adapter.weifule_policy import POLICYBox 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, exec_order_33, finished_order_34, id_card_request_35, card_recharge_order_36]: return ChargingSocketWorkEvent(self.deviceAdapter, event_data) if event_data['fun_code'] in [status_change_event_44]: return WeiFuLeStatusEvent(self.deviceAdapter, device_event) class ChargingSocketWorkEvent(WeiFuLePolicyProcess): def __init__(self, smartBox, event_data): # type:(SmartBox,dict)->None super(ChargingSocketWorkEvent, self).__init__(smartBox, event_data) self.deviceAdapter = smartBox # type: POLICYBox def create_progress_for_socket_order(self, consumeRcd, devInfo): try: port = int(devInfo['port']) progress = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=port, devTypeCode=self.device.devTypeCode).first() if not progress: progress = ServiceProgress(device_imei=self.device.devNo, port=port, devTypeCode=self.device.devTypeCode) progress.start_time = devInfo['create_time'] progress.finished_time = devInfo['create_time'] + 60 * 60 * 12 progress.isFinished = False else: if devInfo['id'] in progress.consumes: return if progress.isFinished == False: progress.finished_time = progress.finished_time + 60 * 60 * 12 else: progress.consumes = [] progress.start_time = devInfo['create_time'] progress.finished_time = devInfo['create_time'] + devInfo.get('amount_time', 60 * 60 * 12) progress.isFinished = False progress.open_id = consumeRcd.openId progress.consumes.append(devInfo['id']) progress.status = 'running' progress.save() except Exception as e: logger.exception(e) def do(self, **args): devNo = self.device['devNo'] funCode = self.event_data.get('fun_code') order = self.event_data.get('order', {}) if funCode == id_card_request_35: return self.response_id_card() logger.info('weifule charging event detected, devNo=%s' % (devNo,)) with memcache_lock(key='%s-%s-%s-finished' % (devNo, order.get('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 == exec_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)) elif funCode == card_recharge_order_36: # 如果是卡充值,直接回复订单 self.deal_with_ic_charge_event() 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 translate_reason(self, order): cause = order.get('cause') if cause == 1: if self.duration < self.refundProtectionTime: return u'充电已结束,如有异常情况,请联系本台设备经销商。' else: 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: return u'整机功率超限,系统为了安全,关闭所有充电端口。' elif cause == 10: return u'检测到温度超限,系统为了安全,关闭所有充电端口。' elif cause == 11: 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'订购的电量已用完' elif cause == 0x0E: return u"当前充电功率超过套餐允许最大功率" elif cause == 20: return u'端口功率过小。可能是电池已经充满,也可能是所接负载功率太小' return u'充电结束。' def deal_with_ic_charge_event(self): cardNo = self.event_data['card_no'] 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 = card.balance 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 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 try: operation_result, balance = self.deviceAdapter.recharge_card(card.cardNo, sendMoney, orderNo=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: order.update_after_recharge_ic_card(device=self.device, sendMoney=sendMoney, preBalance=preBalance, syncBalance=balance, result=ErrorCode.EXCEPTION, description=e.message) return False except Exception as e: logger.exception(e) return False finally: Card.set_card_status(str(card.id), 'idle') def prepaid_end_for_app_start(self, order): """ :param order: 主板上报的 object order 信息 """ # 虚拟卡支付的 if self.consumeRcd and self.consumeRcd.virtual_card_id: ue = order["elec"] / 1000 * 1000 ut = order["time"] / 60.0 vcardRcd = UserVirtualCard.objects.get(id=self.consumeRcd.virtual_card_id) # type: UserVirtualCard modified, consumeTotal, consumeDay = vcardRcd.clear_frozen_quota(str(self.consumeRcd.id), ut, ue, 0) # 支付完成之后 穿件一笔消费记录 if not modified: return vcardRcd.new_consume_record(self.device, self.consumeRcd.user, consumeTotal) else: super(ChargingSocketWorkEvent, self).prepaid_end_for_app_start(order)