# -*- 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 Group, Device 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.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, Card, MyUser, CardRechargeOrder 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 'elec' in device_event: event_data.update({'elec': device_event['elec']}) if event_data['cmdCode'] in ['02', '03', '04', '20']: return ChargingMOXIAOZHI2WorkEvent(self.deviceAdapter, event_data) return None class ChargingMOXIAOZHI2WorkEvent(WorkEvent): def do(self, **args): devNo = self.device['devNo'] logger.info('moxiaozhi2 charging event detected, devNo=%s' % (devNo,)) smartBox = self.deviceAdapter if self.event_data['cmdCode'] == '02': # 刷卡,用于查询余额.如果发现有充值订单,马上下发充值 cardNo = self.event_data['cardNo'] card = self.update_card_dealer_and_type(cardNo, 'ID') # type: Card card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) # type: CardRechargeOrder result = self.recharge_id_card(card = card, rechargeType = 'append', order = card_recharge_order) card.reload() # 如果卡挂失,直接余额为0 if card.frozen: balance = RMB(0) else: balance = result['balance'] try: smartBox.response_card_balance(cardNo, balance) except Exception, e: logger.error('response card balance error=%s' % e) return elif self.event_data['cmdCode'] == '03': # 刷卡,开始结束充电。刷卡是后扣费,移动支付是先扣费,后退费 group = Group.get_group(self.device['groupId']) portInfo = Device.update_port_control_cache(self.device['devNo'], self.event_data, 'overwrite') port = portInfo['port'] card = self.update_card_dealer_and_type(portInfo['cardNo'], 'ID') portInfo['openId'] = card.openId portInfo['cardId'] = str(card.id) portInfo['startTime'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING}) Device.update_port_control_cache(self.device['devNo'], portInfo) # 如果是开始报文,最重要的是刷新内存计费相关数据,前面代码已经完成.刷卡不预扣费,等待结束后,直接扣费 if portInfo['isStart']: # 如果是刷卡启动的,禁用的端口不允许充电 isNormal = True otherConf = Device.objects.get(devNo = self.device['devNo']).otherConf if otherConf.has_key(str(port)) and otherConf[str(port)] == Const.DEV_WORK_STATUS_FORBIDDEN: logger.info('this port is forbidden port=%s' % (port,)) isNormal = False # 刷卡启动,需要等级正在服务的progress ServiceProgress.register_card_service(self.device, port, card) try: smartBox.response_card_charging(isNormal) except Exception, e: logger.exception('response card=%s e=%s' % (portInfo['cardNo'], e)) else: #: 结束,就需要扣费咯.先支持按时间扣费,后续再支持按电量扣费 ------------比较奇怪,从来没有收到这个协议 #: 回复设备 try: smartBox.response_card_charging(True) except Exception, e: logger.exception('response devNo=%s card charging e=%s' % (self.device['devNo'], e)) if self.event_data.has_key('duration') and self.event_data['duration'] > 0: duration = self.event_data['duration'] else: duration = (to_datetime(portInfo['endTime']) - to_datetime( portInfo['startTime'])).total_seconds() / 60.0 if duration < 0: duration = 0 if self.event_data.has_key('elec'): consumeElec = round(self.event_data['elec'] / 3600.0, 4) else: consumeElec = 0.03 * duration / 0.9 # 这里做个特殊的保护,只有模块出现异常的时候,但是需要计费 if consumeElec < 0: consumeElec = 0 consumeMoney, desc = smartBox.calc_consume_money(duration, consumeElec) card = self.update_card_dealer_and_type(portInfo['cardNo'], 'ID') self.consume_money_for_card(card, consumeMoney) self.record_consume_for_card(card, consumeMoney, desc = u'充电时间:%s分钟,充电电量%s度' % (duration, consumeElec)) desc = u'您本次充电约:%s分钟,收费标准为:%s,共计花费:%s元' % (duration, desc, consumeMoney) self.notify_balance_has_consume_for_card(card, consumeMoney) self.notify_user(card.managerialOpenId if card else '', 'service_complete', **{ 'title': desc, '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 self.event_data['cmdCode'] in ['04', '20']: # 收到的结束事件 portInfo = Device.update_port_control_cache(self.device['devNo'], self.event_data) port = self.event_data['port'] try: # 回复设备,04号报文是设备主动停止的,所以需要我们回复一条消息过去 if self.event_data['cmdCode'] == '04': try: smartBox.response_finished_back(True) except Exception, e: logger.error('response devNo=%s card charging e=%s' % (self.device['devNo'], e)) # 如果是开始报文,最重要的是刷新内存计费相关数据,前面代码已经完成.刷卡不预扣费,等待结束后,直接扣费 if self.event_data['isStart']: pass else: # 结束,就需要扣费咯.支持按时间扣费,也支持按电量扣费 if self.event_data.has_key('duration') and self.event_data['duration'] > 0: duration = self.event_data['duration'] else: duration = (datetime.datetime.now() - to_datetime(portInfo['startTime'])).total_seconds() / 60.0 if duration < 0: duration = 0 if self.event_data.has_key('elec'): consumeElec = round(self.event_data['elec'] / 3600.0, 4) else: consumeElec = 0.03 * duration / 0.9 # 这里做个特殊的保护,只有模块出现异常的时候,但是需要计费 if consumeElec < 0: consumeElec = 0 if (not portInfo.has_key('cardNo')) and portInfo.has_key('openId') and ( not portInfo.has_key('consumeRcdId')): # 非刷卡的是退费,刷卡的结束扣费。两种方式不一样 consumeMoney, descFee = smartBox.calc_consume_money(duration, consumeElec) backMoney = RMB(portInfo['coins']) - consumeMoney if backMoney > RMB(0): refund_money(self.device, backMoney, portInfo['openId']) else: backMoney = RMB(0) desc = u'您本次充电使用%s号端口,共计:%s分钟,收费标准为:%s,共计花费:%s元,您预支了:%s元,退回:%s元到您的个人中心中。' % \ (port, duration, descFee, consumeMoney, portInfo['coins'], backMoney) consumeDict = {'reason': self.event_data['reason'], 'duration': duration, 'feeType': descFee, 'refundedMoney': str(backMoney), 'spendMoney': str(consumeMoney), 'chargeIndex': port} ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'open_id': portInfo['openId'], 'port': port, 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict) user = MyUser.objects(openId = portInfo['openId'], groupId = self.device['groupId']).first() self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{ 'title': '%s%s' % (self.event_data['reason'], desc), 'backCount': u'金币:%s' % backMoney, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) self.notify_charging_finished(user.managerialOpenId if user else '') elif portInfo.has_key('consumeRcdId'): consumeMoney, descFee = smartBox.calc_consume_money(duration, consumeElec) backMoney = RMB(portInfo['coins']) - consumeMoney if backMoney < RMB(0): backMoney = RMB(0) desc = u'您本次充电使用%s号端口,共计:%s分钟,收费标准为:%s,共计花费:%s元,您预支了:%s元,退回:%s元到您的个人中心中。' % \ (port, duration, descFee, consumeMoney, portInfo['coins'], backMoney) consumeDict = {'reason': self.event_data['reason'], 'duration': duration, 'feeType': descFee, 'chargeIndex': port} ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'open_id': portInfo['openId'], 'port': port, 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict) # 退额度 try: vCardId = portInfo['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(portInfo['openId']) if vCard else '', 'refund_coins', **{ 'title': '%s%s' % (self.event_data['reason'], desc), 'backCount': u'金币:%s' % backMoney, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) consumeRcdId = portInfo.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, duration, consumeElec, backMoney.mongo_amount) elif portInfo.has_key('cardNo'): card = self.update_card_dealer_and_type(portInfo['cardNo'], 'ID') consumeMoney, descFee = smartBox.calc_consume_money(duration, consumeElec) self.consume_money_for_card(card, consumeMoney) desc = u'您本次充电使用%s号端口,共计:%s分钟,收费标准为:%s,共计花费:%s元' % \ (port, duration, descFee, consumeMoney) consumeDict = {'reason': self.event_data['reason'], 'duration': duration, 'feeType': descFee, 'spendMoney': str(consumeMoney), 'chargeIndex': port} self.record_consume_for_card(card, consumeMoney, desc = u'充电时间:%s分钟' % duration, servicedInfo = consumeDict) ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'cardId': str(card.id), 'port': port, 'device_imei': self.device['devNo'], 'isFinished': False}, consumeDict, False) self.notify_balance_has_consume_for_card(card, consumeMoney, desc) self.notify_charging_finished(card.managerialOpenId) finally: Device.clear_port_control_cache(self.device['devNo'], str(port)) notify_event_to_north(self.dealer, self.device, level = Const.EVENT_NORMAL, desc = self.event_data['reason'])