# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging from mongoengine import DoesNotExist from apilib.monetary import RMB, VirtualCoin from apilib.utils_datetime import to_datetime from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND from apps.web.device.models import Group, Device from apps.web.eventer.base import WorkEvent, FaultEvent from apps.web.eventer import EventBuilder from apps.web.user.models import ServiceProgress, MyUser, CardRechargeOrder, UserVirtualCard, \ VCardConsumeRecord, Card from apps.web.user.transaction_deprecated import refund_money logger = logging.getLogger(__name__) class builder(EventBuilder): def __getEvent__(self, device_event): 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 event_data['cmdCode'] in ['05', '04', '12']: return ChargingXUZHOUWorkEvent(self.deviceAdapter, event_data) if event_data['cmdCode'] == '0D': return FaultEvent(self.deviceAdapter, event_data) class ChargingXUZHOUWorkEvent(WorkEvent): def do(self, **args): devNo = self.device['devNo'] logger.info('xuzhoudianzi charging event detected, devNo=%s' % (devNo,)) if self.event_data['cmdCode'] == '05': port = str(self.event_data['port']) try: ctrInfo = Device.get_dev_control_cache(self.device['devNo']) lineInfo = ctrInfo.get(port) if 'duration' in self.event_data and self.event_data['duration'] > 0: usedTime = self.event_data['duration'] else: if (not lineInfo) or (not lineInfo.has_key('startTime')): return 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))) group = Group.get_group(self.device['groupId']) consumeDict = {'reason': self.event_data['reason'], 'chargeIndex': port, 'duration': usedTime} isBackCoins = self.device.is_auto_refund backCoins = self.event_data['leftMoney'] if isBackCoins: consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: VirtualCoin(backCoins).mongo_amount, }) # 如果是刷卡的,直接更新消费记录,然后发送通知消息,不支持退费 if lineInfo.has_key('cardNo'): card = Card.objects(cardNo = lineInfo['cardNo'], agentId = self.dealer.agentId).first() consumeDict.update({'balance': lineInfo['balance']}) 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(card.managerialOpenId if card else '', 'service_complete', **{ 'title': u'%s 卡号:%s,剩余时间:%s分钟' % ( self.event_data['reason'], lineInfo['cardNo'], usedTime, 0), 'service': u'充电服务(设备编号:%s, 端口:%s,地址:%s)' % ( self.device['logicalCode'], port, group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) elif lineInfo.has_key('consumeRcdId'): # 退额度 try: vCardId = lineInfo['vCardId'] vCard = UserVirtualCard.objects.get(id = vCardId) except DoesNotExist, e: logger.info('can not find the vCard id = %s' % vCardId) return # 通知服务结束 self.notify_user(self.get_managerialOpenId_by_openId(lineInfo['openId']) if vCard else '', 'service_complete', **{ 'title': u'%s,退费:%s元' % ( self.event_data['reason'], backCoins) if not isBackCoins else self.event_data[ 'reason'], '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) consumeRcdId = lineInfo.get('consumeRcdId', None) if consumeRcdId is None: logger.info('can not find consume rcd id') return try: vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId) except DoesNotExist, e: logger.info('can not find the consume rcd id = %s' % consumeRcdId) return vCard.refund_quota(vCardConsumeRcd, usedTime, 0.0, backCoins) else: if not lineInfo.has_key('openId'): return user = MyUser.objects(openId = lineInfo['openId'], groupId = self.device['groupId']).first() # 通知服务结束 self.notify_user(user.managerialOpenId if user else '', 'service_complete', **{ 'title': u'%s,退费:%s元' % ( self.event_data['reason'], backCoins) if isBackCoins else self.event_data[ 'reason'], '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 isBackCoins: 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: 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元,您下次可以接着使用哦' % ( self.event_data['reason'], 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': cardNo = self.event_data['cardNo'] card = self.update_card_dealer_and_type(cardNo, 'IC') if not card: return lineInfo = Device.update_port_control_cache(self.device['devNo'], self.event_data) lineInfo['openId'] = card.openId lineInfo = Device.update_port_control_cache(self.device['devNo'], lineInfo) balance = RMB(self.event_data['balance']) consumeMoney = RMB(self.event_data['coins']) if self.event_data['status'] == '01': # 扣款成功,表示马上需要使用卡了,需要登记 desc = u'正在刷卡使用,卡号:%s,卡名称:%s,端口号:%s,扣费:%s,余额:%s' % ( card.cardNo, card.cardName, self.event_data['port'], self.event_data['coins'], balance) orderNo, cardOrderNo = \ self.record_consume_for_card(card = card, money = consumeMoney, desc = desc, servicedInfo = { 'balance': self.event_data['balance'], 'coin': self.event_data['coins'], 'port': self.event_data['port']}) # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来 ServiceProgress.register_card_service(self.device, self.event_data['port'], card, {'orderNo': orderNo, 'coin': self.event_data['coins'], 'cardOrderNo': cardOrderNo}) self.notify_balance_has_consume_for_card(card, consumeMoney, desc) # 更新下balance,便于刷卡记录中,更新到数据库中 lineInfo['balance'] = str(balance) lineInfo['cardId'] = str(card.id) lineInfo['startTime'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') lineInfo['isStart'] = True lineInfo['status'] = Const.DEV_WORK_STATUS_WORKING Device.update_port_control_cache(self.device['devNo'], lineInfo) # 如果卡挂失掉了,立马把端口关闭掉 if card.frozen: logger.debug('{} has been frozen.'.format(repr(card))) self.deviceAdapter.stop_charging_port(lineInfo['port']) elif self.event_data['status'] == '02': # 扣款失败,余额不足 pass elif self.event_data['status'] == '03': # 返现 balance = balance + consumeMoney self.update_card_balance(card, balance) elif self.event_data['cmdCode'] == '12': # 电川的板子充值是覆写方式,需要把上次的余额一起累加进来 cardNo = self.event_data['cardNo'] card = self.update_card_dealer_and_type(cardNo, 'IC') # type: Card if card.frozen: logger.debug('{} has been frozen.'.format(repr(card))) return preBalance = RMB(self.event_data['balance']) card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder self.recharge_ic_card(card = card, preBalance = preBalance, rechargeType = 'overwrite', order = card_recharge_order, need_verify = False)