# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging from apilib.monetary import RMB, VirtualCoin from apilib.utils_datetime import to_datetime from apps.web.agent.models import Agent from apps.web.dealer.models import Dealer from apps.web.device.models import Group, Device from apps.web.eventer.base import WorkEvent from apps.web.eventer import EventBuilder from apps.web.eventer.errors import NoCommandHandlerAvailable from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, MyUser from apps.web.user.transaction_deprecated import refund_money logger = logging.getLogger(__name__) service_id_generator = lambda dev_no, port, ts: '{}_{}_{}'.format(dev_no, port, ts) 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 event_data['cmdCode'] in [0x09]: return ChargingNanjiguangWorkEvent(self.deviceAdapter, event_data) class ChargingNanjiguangWorkEvent(WorkEvent): def do(self, **args): devNo = self.device['devNo'] logger.info('nanjiguang charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data)) cmdCode = self.event_data['cmdCode'] #: 结束的命令 if cmdCode in [0x09]: group = Group.get_group(self.device['groupId']) dealer = Dealer.objects(id = group['ownerId']).first() if not dealer: logger.error('dealer is not found, dealerId=%s' % group['ownerId']) return agent = Agent.objects(id = dealer.agentId).first() if not agent: logger.error('agent is not found, agentId=%s' % dealer.agentId) return ctrl_info = Device.get_dev_control_cache(self.device['devNo']) lineInfo = ctrl_info.get(str(self.event_data['port'])) if 'ts' not in lineInfo or lineInfo['ts'] != self.event_data['ts']: service_progress = ServiceProgress.objects( id = service_id_generator(dev_no = devNo, port = self.event_data['port'], ts = self.event_data['ts'])).first() if not service_progress: logger.error( 'not find port status info. devNo = {}, port = {}'.format(devNo, self.event_data['port'])) return lineInfo = { } vCardId = lineInfo.get('vCardId', None) coins = VirtualCoin(lineInfo['coins']) price = RMB(lineInfo.get('price', 0.0)) spendTime = int(self.event_data['consumeTime']) spendElec = round(float(self.event_data['consumeElec']), 2) billingType = lineInfo.get('billingType') backCoins, backPrice = VirtualCoin(0.0), RMB(0.0) try: if billingType == 'autoClose': # 充满自停 left_elec = lineInfo['needElec'] - spendElec if left_elec < 0: left_elec = 0 else: backCoins = coins * (float(left_elec) / float(lineInfo['needElec'])) backPrice = price * (float(left_elec) / float(lineInfo['needElec'])) startTime = to_datetime(lineInfo['startTime']) nowTime = datetime.datetime.now() if startTime > nowTime: duration = 0 else: duration = int(round(((nowTime - startTime).total_seconds() / 60.0))) else: leftTime = lineInfo['needTime'] - spendTime if leftTime < 0: leftTime = 0 else: backCoins = coins * (float(leftTime) / float(lineInfo['needTime'])) backPrice = price * (float(leftTime) / float(lineInfo['needTime'])) duration = int(lineInfo['needTime'] / 60.0) is_auto_refund = self.device.is_auto_refund openId = lineInfo['openId'] consumeDict = { 'chargeIndex': lineInfo['port'], 'duration': duration } if backCoins > VirtualCoin(0): 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) if vCardId is None: # 扫码的方式 if is_auto_refund: # 扫码退钱, 退到个人账号 refund_money(self.device, backCoins, lineInfo['openId']) #: 使用的是虚拟卡 elif vCardId is not None: try: consumeRcdId = lineInfo.get('consumeRcdId', None) if consumeRcdId: vCardConsumeRcd = VCardConsumeRecord.objects.get(id = consumeRcdId) vCard = UserVirtualCard.objects.get(id = vCardId) vCard.refund_quota(vCardConsumeRcd, duration, spendElec, backCoins.mongo_amount) except Exception as e: logger.exception(e) except Exception as 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'])) title = u'充电结束,感谢您的使用!' if is_auto_refund and backCoins > 0: title = u'充电结束,感谢您的使用!退款金额已经返还到您的账号,请注意查收。' if billingType == 'autoClose': service_notify = u'自助充电\r\n' \ u'设备编号:{logicalCode}\r\n' \ u'充电端口:{port}\r\n' \ u'预付金额:{money}币\r\n' \ u'退款金额:{back}币\r\n' \ u'设备地址:{address}\r\n' \ u'充电状态:{status}'.format( logicalCode = self.device['logicalCode'], port = self.event_data['port'], money = coins, back = backCoins, address = group['address'], status = self.event_data['statusDesc']) else: service_notify = u'自助充电\r\n' \ u'设备编号:{logicalCode}\r\n' \ u'充电端口:{port}\r\n' \ u'预付金额:{money}币\r\n' \ u'退款金额:{back}币\r\n' \ u'订购时间:{reverseTime}\r\n' \ u'剩余时间:{leftTime}\r\n' \ u'设备地址:{address}\r\n' \ u'充电状态:{status}'.format( logicalCode = self.device['logicalCode'], port = self.event_data['port'], money = coins, back = backCoins, reverseTime = lineInfo['needTime'], leftTime = leftTime, address = group['address'], status = self.event_data['statusDesc']) user = MyUser.objects(openId = openId, groupId = self.device['groupId']).first() self.notify_user( user.managerialOpenId, 'service_complete', **{ 'title': title, 'service': service_notify, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) else: raise NoCommandHandlerAvailable( '[nanjiguang] no command handler for cmd %s, curDevInfo=%s' % (cmdCode, self.event_data))