# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import time from apilib.monetary import VirtualCoin, 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 FaultEvent, 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, 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 ("16", "10"): return ChargingHongZhuoWorkEvent(self.deviceAdapter, event_data) if event_data['cmdCode'] == '0A': return FaultEvent(self.deviceAdapter, event_data) return None class ChargingHongZhuoWorkEvent(WorkEvent): SUCCESS = "01" FAIL = "00" def support_playback(self): return self.event_data['cmdCode'] == '16' def do(self, **args): devNo = self.device['devNo'] logger.info('hongzhuo charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data)) if self.event_data['cmdCode'] == '16': lineInfo = Device.clear_port_control_cache(devNo, str(self.event_data['port'])) recvTime = to_datetime(self.recvTime) cardNo = lineInfo.get("cardNo") # 构建 发向山东省平台的数据 coins = float(lineInfo.get('coins', 0)) if not coins: logger.info("Cache is missing or Offline card , pass!! ") # 缓存丢失 或者使用离线卡 return northerDict = { "elec": self.event_data.get("elec"), "startTime": lineInfo.get("startTime"), "spendMoney": round(coins - self.event_data.get("leftMoney", 0),2) if coins > self.event_data.get("leftMoney", 0) else 0 } # 刷卡启动的结束事件 if cardNo: try: card = self.update_card_dealer_and_type(cardNo) user = MyUser.objects.filter(openId=card.openId, groupId=self.device["groupId"]).first() consumeDict = { "chargeIndex": self.event_data.get("portStr"), "reason": self.event_data.get("reason"), 'actualNeedTime': lineInfo.get("needTime"), "duration": self.event_data.get("duration"), "elec": self.event_data.get("elec") } # 设备支持余额回收并且 有余额可以回收 refundMoney = self.event_data.get("leftMoney") if refundMoney and refundMoney > 0 and self.device.is_auto_refund: refundMoney = VirtualCoin(refundMoney) self.refund_money_for_card(refundMoney, str(card.id)) consumeDict.update({ "refundMoney": str(refundMoney) }) desc = u'您使用的%s号端口充电,卡付款:%s元,给您退款:%s元' % ( self.event_data['port'], lineInfo.get("coins"), refundMoney) self.notify_user( user.managerialOpenId if user else '', 'refund_coins', **{ 'title': desc, 'backCount': u'金币:%s' % refundMoney, 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S') } ) # 通知用户充电结束 group = Group.get_group(self.device["groupId"]) self.notify_user( managerialOpenId=user.managerialOpenId if user else "", templateName="service_complete", title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}".format( reason=self.event_data["reason"], logicalCode=self.device["logicalCode"], port=self.event_data["port"], group=group["address"], ), service=u"充电桩充电服务", finishTime=datetime.datetime.strftime(recvTime, "%Y-%m-%d %H:%M:%S"), remark=u'谢谢您的支持' ) # 结束充电服务进程,并且累计相关信息 ServiceProgress.update_progress_and_consume_rcd( self.device["ownerId"], { "open_id": card.openId, "device_imei": self.device["devNo"], "port": int(self.event_data.get("port")), "isFinished": False }, consumeDict ) except Exception as e: logger.exception('deal with hongzhuo devNo=%s event e=%s' % (devNo, e)) finally: logger.info('hongzhuo_notify_to_sd_norther:{}'.format(northerDict)) self.notify_to_sd_norther(portStr=str(self.event_data.get("port")), consumeDict=northerDict) Device.clear_port_control_cache(devNo, str(self.event_data['port'])) else: dataDict = dict() try: 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']) if startTime > recvTime:#如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大 usedTime = 0 else: usedTime = int(round(((recvTime - startTime).total_seconds() / 60.0))) money = float(lineInfo['coins']) leftMoney = float(self.event_data['leftMoney']) if leftMoney > money: leftMoney = money workMode = self.event_data['mode'] openId = lineInfo['openId'] user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first() if workMode == 2: # 计算退币金额 backCoins = VirtualCoin(leftMoney) consumeDict = {'chargeIndex': self.event_data['port'], 'reason': self.event_data['reason'], 'duration': usedTime} 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': self.event_data['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': self.event_data['port'], 'isFinished': False}, consumeDict) desc = u'您使用的%s号端口充电,共付款:%s元,给您退款:%s元' % ( self.event_data['port'], money, backCoins) self.notify_user(user.managerialOpenId if user else '', 'refund_coins', **{ 'title': desc, 'backCount': u'金币:%s' % backCoins, 'finishTime': recvTime.strftime('%Y-%m-%d %H:%M:%S') }) dataDict.update({'backCoins': float(backCoins)}) except Exception, e: logger.exception('deal with hongzhuo devNo=%s event e=%s' % (devNo, e)) finally: logger.info('hongzhuo_notify_to_sd_norther:{}'.format(northerDict)) self.notify_to_sd_norther(portStr=str(self.event_data.get("port")), consumeDict=northerDict) 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) # 刷卡启动事件 elif self.event_data['cmdCode'] == "10": cardNo = self.event_data.get("cardNo") preFee = self.event_data.get("preFee") portStr = self.event_data.get("portStr") portCache = Device.get_dev_control_cache(self.device["devNo"]).get(portStr, {}) if portCache.get("status", Const.DEV_WORK_STATUS_IDLE) == Const.DEV_WORK_STATUS_WORKING: logger.info("port is working!") card = self.update_card_dealer_and_type(cardNo) # 无效的卡 if not card or not card.openId: logger.info("bad card, cardNo is {}".format(cardNo)) self.deviceAdapter.response_use_card(self.FAIL, portStr, 0) return # 卡冻结 if card.frozen: logger.info("card is frozen, cardNo is {}".format(cardNo)) balance = float(card.balance) * 10 self.deviceAdapter.response_use_card(self.FAIL, portStr, balance) return # 余额不足 payMoney = RMB(preFee / 10.0) if float(card.balance) < float(payMoney): logger.info("card balance is not enough, cardNo is {}".format(card.balance)) balance = float(card.balance) * 10 self.deviceAdapter.response_use_card(self.FAIL, portStr, balance) return # 正常扣费流程, 先创建订单,再注册服务 orderNo, cardOrderNo = self.record_consume_for_card(card, payMoney) ServiceProgress.register_card_service( self.device, int(portStr), card, { "cardOrderNo": cardOrderNo, "orderNo": orderNo, "money": payMoney.mongo_amount, "coin": payMoney.mongo_amount, "needTime": 0, } ) leftBalance = float(card.balance - payMoney) * 10 # 卡扣钱 self.consume_money_for_card(card, payMoney) # 回复主板 self.deviceAdapter.response_use_card(self.SUCCESS, portStr, leftBalance) # 通知已经扣费 self.notify_balance_has_consume_for_card(card, payMoney) portDict = { 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'status': Const.DEV_WORK_STATUS_WORKING, 'finishedTime': int(time.time()) + 12 * 60 * 60, 'coins': float(payMoney), 'isStart': True, 'price': str(float(payMoney)), 'openId': card.openId, 'refunded': False, "cardNo": cardNo } Device.update_dev_control_cache(self.device["devNo"], {portStr: portDict}) # 设备上报的本地付费打开信息,需更新有用的端口信息 elif self.event_data['cmdCode'] == "20": portStr = self.event_data.get("portStr") devCache = Device.get_dev_control_cache(self.device["devNo"]) portCache = devCache.get(portStr) # 不干扰宝东的扫码支付 if not portCache or not portCache.get("cardNo") or self.event_data.get("typeCode") != "01": logger.info("no port card start cache, so this info is useless!") return portCache.update({ "coins": self.event_data.get("money"), })