# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging from mongoengine import DoesNotExist from apilib.monetary import RMB from apilib.utils_datetime import to_datetime from apps.web.constant import Const 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.south_intf.zhejiang_fire import send_event_to_zhejiang from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, MyUser 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 ['06']: return ChargingJNDZWorkEvent(self.deviceAdapter, event_data) return None class ChargingJNDZWorkEvent(WorkEvent): def do(self, **args): devNo = self.device['devNo'] logger.info('jingnengdianzi charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data)) if self.event_data['cmdCode'] == '06': # 结束的命令 try: lineInfo = Device.update_port_control_cache(devNo, self.event_data) group = Group.get_group(self.device['groupId']) if not lineInfo.has_key('coins'): return 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))) cardId = lineInfo.get('cardId', '') vCardId = lineInfo.get('vCardId', None) money = RMB(lineInfo['coins']) price = lineInfo.get('price', 0.0) leftTime = self.event_data['leftTime'] refundProtection = lineInfo.get('refundProtection', 0) backCoins, backPrice = 0.0, 0.0 if leftTime == 65535: actualNeedTime = 0 backCoins = money backPrice = price usedTime = 0 else: actualNeedTime = usedTime + leftTime leftTimeStr = leftTime needTime = lineInfo['needTime'] backCoins = money * (float(leftTime) / float(actualNeedTime)) # refundProtection 开关, 控制 5 分钟内全额退款 if (refundProtection == 1 and usedTime < 5) and backCoins != 0: backCoins = money if backCoins > money: backCoins = money backPrice = round(price * float(backCoins) / float(money), 2) if cardId == '' and vCardId is None: # 扫码的方式 openId = lineInfo['openId'] leftTimeStr = leftTime if leftTime != 65535 else needTime title = u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % ( self.event_data['reason'], actualNeedTime, leftTimeStr) # 通知充电完成 user = MyUser.objects(openId = openId, groupId = self.device['groupId']).first() self.notify_user(user.managerialOpenId, 'service_complete', **{ 'title': title, 'service': u'充电服务(设备编号:%s,端口:%s,地址:%s)' % ( self.device['logicalCode'], self.event_data['port'], group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) consumeDict = {'chargeIndex': lineInfo['port'], 'reason': lineInfo['reason'], 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime, 'duration': usedTime} leftTimeStr = leftTime if leftTime != 65535 else needTime consumeDict.update({'leftTime': leftTimeStr, 'needTime': u'扫码订购%s分钟' % needTime}) # 如果需要退款,计算退款数据. if not self.device.is_auto_refund: ServiceProgress.update_progress_and_consume_rcd( self.device['ownerId'], {'open_id': openId, 'device_imei': self.device['devNo'], 'port': lineInfo['port'], 'isFinished': False}, consumeDict ) else: # 扫码退钱, 退到个人账号 refund_money(self.device, backCoins, lineInfo['openId']) consumeDict.update({'refundedMoney': str(backCoins)}) ServiceProgress.update_progress_and_consume_rcd( self.device['ownerId'], {'open_id': openId, 'device_imei': self.device['devNo'], 'port': lineInfo['port'], 'isFinished': False}, consumeDict) leftTimeStr = leftTime if leftTime != 65535 else needTime desc = u'您使用的%s号端口充电,共付款:%s元,充电预定时间为:%s分钟,剩余时间:%s分钟,给您退款:%s元' % ( lineInfo['port'], money, needTime, leftTimeStr, backCoins) self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{ 'title': desc, 'backCount': u'金币:%s' % backCoins, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) elif vCardId is not None: # 使用的是虚拟卡 leftTimeStr = leftTime if leftTime != 65535 else needTime title = u'%s 按动态功率计算总时间为:%s分钟,剩余时间:%s分钟' % ( self.event_data['reason'], actualNeedTime, leftTimeStr) # 通知充电完成 try: 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']), 'service_complete', **{ 'title': title, 'service': u'充电服务(设备编号:%s,端口:%s,地址:%s)' % ( self.device['logicalCode'], self.event_data['port'], group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) consumeDict = {'chargeIndex': lineInfo['port'], 'reason': lineInfo['reason'], 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime, 'duration': usedTime} ServiceProgress.update_progress_and_consume_rcd( self.device['ownerId'], {'open_id': lineInfo['openId'], 'device_imei': self.device['devNo'], 'port': lineInfo['port'], '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.mongo_amount) except Exception, e: logger.exception('deal with jingneng devNo=%s event e=%s' % (devNo, e)) finally: Device.clear_port_control_cache(devNo, str(self.event_data['port'])) dataDict = {'backMoney': backPrice, 'backCoins': backCoins.mongo_amount} if lineInfo.has_key('orderNo'): dataDict.update({'orderNo': lineInfo['orderNo']}) notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL, desc = self.event_data['reason'], dataDict = dataDict) send_event_to_zhejiang(self.dealer, self.device, self.event_data)