# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import time import simplejson as json import logging from typing import TYPE_CHECKING from apilib.monetary import RMB, VirtualCoin from apilib.utils_datetime import to_datetime from apps.web.common.models import TempValues from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND from apps.web.core.accounting import Accounting 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.report.utils import record_consumption_stats from apps.web.user.transaction_deprecated import refund_money from apps.web.user.models import ServiceProgress, CardRechargeOrder, MyUser, Card, \ ConsumeRecord if TYPE_CHECKING: from apps.web.device.models import GroupDict logger = logging.getLogger(__name__) class builder(EventBuilder): def __getEvent__(self, device_event): if "ack_event_id" in device_event: self.deviceAdapter.ack_05_event(device_event.get("ack_event_id")) event_data = self.deviceAdapter.analyze_event_data(device_event) if "FaultCode" in event_data: return LVZHIFaultEvent(self.deviceAdapter, event_data) elif event_data.get('cmd') == '99': return LVZHIOnline(self.deviceAdapter, event_data) else: return ChargingLVZHIWorkEvent(self.deviceAdapter, event_data) class ChargingLVZHIWorkEvent(WorkEvent): def __parse_device_finished_data(self, event_data): duration = event_data.get("duration", -1) if duration != -1: if "v" in event_data: duration = ((duration + 59) / 60) elec = event_data.get("elec", -1) if elec != -1: if "v" in event_data: elec = round(elec / (10000.0 * 3600.0), 3) else: elec = round(elec / 3600.0, 3) logger.debug("lz_device duration is {}, device elec is {}".format(duration, elec)) return duration, elec def do(self, **args): logger.info("lz_charging event to do devNo=%s,info=%s" % ( self.device.devNo, json.dumps(self.event_data, ensure_ascii=False))) cmd = self.event_data.get("cmd") if cmd == "03": coins = self.event_data.get("coins") port = self.event_data.get("port") port_control_cache = Device.get_dev_control_cache(self.device.devNo) lineInfo = port_control_cache.get(port, {}) offlineCoin = float(coins) - float(lineInfo.get("coins", 0)) if offlineCoin: Accounting.recordOfflineCoin(self.device, int(time.time()), int(offlineCoin)) else: Accounting.recordOfflineCoin(self.device, int(time.time()), int(float(coins))) consumeDict = { "totalCount": offlineCoin, "chargeIndex": port } orderNo = self.record_consume_for_coin(RMB(coins), servicedInfo=consumeDict) # 更新端口缓存 billingType = self.event_data.get("billingType") portInfo = { "port": port, "status": Const.DEV_WORK_STATUS_WORKING, "coins": coins, "billingType": billingType, "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "consumeType": "coin", "orderNo": orderNo, } deviceConfigs = self.device['otherConf'].get('deviceConfigs', {}) if not deviceConfigs: deviceConfigs = self.deviceAdapter.get_consumption_rules() if billingType == "time": coinTime = deviceConfigs.get("coinTime", 240) needTime = int(float(coinTime) * float(coins)) portInfo.update({"needTime": needTime}) elif billingType == 'billAsService': coinElec = deviceConfigs.get("coinElec", 0.6) serviceCharge = self.device.bill_as_service_feature.service_charge elecCharge = self.device.bill_as_service_feature.elec_charge if float(coinElec) == 0.0: coinElec = elecCharge unitFee = float(serviceCharge) + float(coinElec) needElec = round(float(coins) / unitFee, 2) portInfo.update({"needElec": needElec}) else: coinElec = deviceConfigs.get("coinElec", 0.6) needElec = round(float(coinElec) * float(coins), 2) portInfo.update({"needElec": needElec}) if lineInfo.get("startTime"): lastOrder = lineInfo.get("orderNo") historicalOrders = lastOrder portInfo["startTime"] = lineInfo.get("startTime") portInfo["coins"] = coins portInfo["historicalOrders"] = historicalOrders try: order = ConsumeRecord.objects.filter(orderNo=historicalOrders).first() order.finishedTime = datetime.datetime.now() order.status = "finished" order.servicedInfo.update({"reason": "再次投币使用,当前订单金额({})累计到下一单(消费订单号:{})".format(order.coin, orderNo), "duration": ((order.finishedTime - order.dateTimeAdded).total_seconds() + 59) / 60, }) order.coin = VirtualCoin(0).mongo_amount order.money = RMB(0).mongo_amount order.save() ServiceProgress.objects(device_imei=self.device.devNo, port=int(port), isFinished=False).update_one(upsert=False, consumeOrder={ "orderNo": orderNo, "coins": portInfo[ "coins"]}) except Exception: pass Device.update_port_control_cache(self.device.devNo, portInfo) # 如果是投币,直接把端口状态刷新下 try: self.deviceAdapter.get_all_port_status() except Exception, e: logger.info("lz_some err=%s" % e) elif cmd == "04": # 只有离线卡 离线卡记录数据更新 cardNo = self.event_data["cardNo"] fee = RMB(self.event_data["fee"]) cardType = self.event_data["cardType"] cardBalance = RMB(self.event_data["cardBalance"]) port = self.event_data["port"] eventCode = self.event_data["eventCode"] card = self.update_card_dealer_and_type(cardNo, cardType=cardType, balance=cardBalance) if not card: card = Card(cardNo=cardNo, remarks="中山智能离线卡", agentId=self.dealer.agentId, openId=Const.DEFAULT_CARD_OPENID, dealerId=str(self.dealer.id), cardType=cardType, isHaveBalance=False, devNo=self.device.devNo, balance=cardBalance) card.save() if cardType == "IC": if eventCode == "01": # 刷卡上报事件 01 代表扣费 02 代表退费 billingType = self.event_data.get("billingType") port_control_cache = Device.get_dev_control_cache(self.device.devNo) portInfo = { "port": port, "status": Const.DEV_WORK_STATUS_WORKING, "cardType": cardType, "cardNo": cardNo, "coins": str(fee), "billingType": billingType, "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "consumeType": "card", } # 如果是绑定了卡的 if card.cardNo != card.openId: portInfo.update({"openId": card.openId}) deviceConfigs = self.device['otherConf'].get('deviceConfigs', {}) if not deviceConfigs: deviceConfigs = self.deviceAdapter.get_consumption_rules() if billingType == "time": cardTime = deviceConfigs.get("cardTime", 240) needTime = int(float(cardTime) * float(fee)) portInfo.update({"needTime": needTime}) elif billingType == 'billAsService': cardElec = deviceConfigs.get("cardElec", 0.6) serviceCharge = self.device.bill_as_service_feature.service_charge elecCharge = self.device.bill_as_service_feature.elec_charge if float(cardElec) == 0.0: cardElec = elecCharge unitFee = float(serviceCharge) + float(cardElec) needElec = round(float(fee) / unitFee, 2) portInfo.update({"needElec": needElec}) else: cardElec = deviceConfigs.get("cardElec", 0.6) needElec = round(float(cardElec) * float(fee), 2) portInfo.update({"needElec": needElec}) servicedInfo = {"卡号": cardNo, "chargeIndex": port} # 记录卡消费记录以及消费记录 orderNo, cardOrderNo = self.record_consume_for_card(card, fee, servicedInfo=servicedInfo) portInfo.update({"orderNo": orderNo}) lineInfo = port_control_cache.get(port, {}) if lineInfo.get("startTime"): lastOrder = lineInfo.get("orderNo") historicalOrders = lastOrder portInfo["startTime"] = lineInfo.get("startTime") portInfo["coins"] = str(fee) portInfo["historicalOrders"] = historicalOrders try: order = ConsumeRecord.objects.filter(orderNo=historicalOrders).first() order.finishedTime = datetime.datetime.now() order.status = "finished" order.servicedInfo.update( {"reason": "再次刷卡使用,当前订单金额({})累计到下一单(消费订单号:{})".format(order.coin, orderNo), "duration": ((order.finishedTime - order.dateTimeAdded).total_seconds() + 59) / 60, }) order.coin = VirtualCoin(0).mongo_amount order.money = RMB(0).mongo_amount order.save() ServiceProgress.objects(device_imei=self.device.devNo, port=int(port), isFinished=False).update_one(upsert=False, consumeOrder={ "orderNo": orderNo, "coins": portInfo[ "coins"]}) except Exception: pass else: # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来 ServiceProgress.register_card_service(self.device, int(port), card, {"orderNo": orderNo, "money": self.event_data["fee"], "coin": self.event_data["fee"], "needTime": 0, "cardOrderNo": cardOrderNo}) Device.update_port_control_cache(self.device.devNo, portInfo) # 卡号与openId相同,则为未绑定卡不用发送 if card.cardNo == card.openId: return # 通知微信,已经扣费 self.notify_balance_has_consume_for_card(card, fee) # 离线卡退费事件 更新卡余额 else: self.update_card_dealer_and_type(cardNo, balance=cardBalance) elif cmd == "05": devNo = self.device.devNo port = self.event_data["port"] try: # 获取充电的模式 ctrInfo = Device.get_dev_control_cache(devNo) lineInfo = ctrInfo.get(port) if not lineInfo: logger.debug("lz_get null control cache from {}".format(repr(self.device))) return billingType = self.event_data.get("billingType") if billingType == "elec": return self.do_elec_finish(devNo, port, lineInfo, self.event_data) elif billingType == "billAsService": return self.do_billAsService_finish(devNo, port, lineInfo, self.event_data) else: return self.do_time_finish(devNo, port, lineInfo, self.event_data) finally: Device.clear_port_control_cache(devNo, str(port)) elif cmd == "1D": cardNo = self.event_data["cardNo"] cardType = self.event_data["cardType"] cardBalance = self.event_data["cardBalance"] if cardType == "ID": logger.info("lz_cardType is IdCard return!!!") card = self.update_card_dealer_and_type(cardNo, cardType, balance=RMB(cardBalance)) # type: Card if not card: card = Card(cardNo=cardNo, remarks="中山智能离线卡", agentId=self.dealer.agentId, openId=Const.DEFAULT_CARD_OPENID, dealerId=str(self.dealer.id), cardType=cardType, isHaveBalance=False, devNo=self.device.devNo, balance=RMB(cardBalance)) card.save() logger.info("lz_ no such card now create!! cardNo:%s" % cardNo) money, coins, orderNos, cardOrderNos = CardRechargeOrder.get_to_do_list(str(card.id)) if not orderNos: logger.info("lz_not card recharge record!, card is <{}>".format(cardNo)) # 缓存里面更新低余额卡号 card.reload() self.deviceAdapter.updata_no_balance_list(self.device.devNo, card) return orderNos = [str(item) for item in orderNos] CardRechargeInfo = { "rechargeRecord": orderNos, "cardRechargeOrder": cardOrderNos, "asyncMoney": str(coins), "cardBalance": str(cardBalance) } tempKey = "%s-%s" % (self.device["devNo"], cardNo) TempValues.set(key=tempKey, value=json.dumps(CardRechargeInfo)) if card.frozen: asyncMoney = 0 else: asyncMoney = str(coins) try: CardRechargeOrder.objects.filter(orderNo__in=cardOrderNos).update(status="finished") except Exception as e: logger.debug("lz_%s" % e) else: self.deviceAdapter.recharge_ic_card(cardNo, asyncMoney) logger.info("send recharge cmd is done,wait 1F return cardNo:%s asyncMoney:%s tempKey:%s" % ( cardNo, asyncMoney, tempKey)) elif cmd == "1F": cardNo = str(self.event_data["cardNo"]) cardType = self.event_data["cardType"] ayscMoney = RMB(self.event_data["ayscMoney"]) nowBalance = RMB(self.event_data["cardBalance"]) status = self.event_data["status"] card = self.update_card_dealer_and_type(cardNo, cardType) # type: Card if not card: return if card.frozen: logger.debug("lz_{} has been frozen.".format(repr(card))) return # 明确接收到了主板同步失败的情况下,将订单的状态回传 if status != "01": CardRechargeInfoKey = "%s-%s" % (self.device["devNo"], cardNo) CardRechargeInfo = TempValues.get(CardRechargeInfoKey) cardRechargeOrders = CardRechargeInfo.get("cardRechargeOrder") logger.info("lz_card recharge receive fail status from device, card is <{}>".format(cardNo)) try: CardRechargeOrder.objects.filter(orderNo__in=cardRechargeOrders).update(status="finishedPay") except Exception as e: logger.debug("lz_%s" % e) return else: self.update_card_dealer_and_type(cardNo, cardType=cardType, balance=nowBalance) logger.info("IcCard recharge completed cardNo:%s asyncMoney:%s nowBalance%s" % ( cardNo, str(ayscMoney), str(nowBalance))) elif cmd == "F1": self.deviceAdapter.send_F1_heartbeat() def do_elec_finish(self, devNo, port, lineInfo, msgDict=None): leftElec = float(self.event_data.get("leftElec", 0)) reasonStr = self.event_data.get("reason") cardNo = self.event_data.get("cardNo") startTime = lineInfo.get("startTime") startTime = to_datetime(startTime) nowTime = datetime.datetime.now() coins = VirtualCoin(lineInfo.get("coins")) needElec = lineInfo.get("needElec") if leftElec == 65535: leftElec = needElec elif leftElec > needElec: logger.error("lz_left elec is bigger than need elec. something is wrong") leftElec = 0 spendElec = needElec - leftElec if startTime > nowTime: usedTime = 0 else: usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0))) # 获取组信息 group = Group.get_group(self.device["groupId"]) consumeTypeCode = self.event_data["consumeTypeCode"] if consumeTypeCode == "01": # 投币结束上报 记录到表中 CoinConsumeRcd = ConsumeRecord.objects.get(orderNo=lineInfo["orderNo"]) CoinConsumeRcd.finishedTime = datetime.datetime.now() consumeDict = { "chargeIndex": port, "reason": reasonStr, "leftElec": leftElec, "leftMoney": self.event_data["backMoney"], DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime, DEALER_CONSUMPTION_AGG_KIND.ELEC: spendElec, } servicedInfo = CoinConsumeRcd.servicedInfo servicedInfo.update(consumeDict) servicedInfo["rechargeCode"] = self.event_data["rechargeCode"] CoinConsumeRcd.servicedInfo = servicedInfo CoinConsumeRcd.save() valueDict = { DEALER_CONSUMPTION_AGG_KIND.TOTAL_COUNT: servicedInfo.get("totalCount"), DEALER_CONSUMPTION_AGG_KIND.DURATION: servicedInfo.get("duration") } status = CoinConsumeRcd.update_agg_info(valueDict) if status: record_consumption_stats(CoinConsumeRcd) ServiceProgress.objects(device_imei=self.device.devNo, port=int(port), isFinished=False).update_one( upsert=False, isFinished=True, expireAt = datetime.datetime.now()) elif consumeTypeCode == "04": # 扫码的结束 refundCoins = VirtualCoin(0) consumeDict = { "reason": reasonStr, "chargeIndex": port, "duration": usedTime, "leftElec": leftElec, DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: coins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.ELEC: spendElec, } refundSwitch = self.device.is_auto_refund refundProtection = int(lineInfo.get("refundProtection", 0)) refundProtectionTime = int(lineInfo.get("refundProtectionTime", 5)) if refundSwitch: refundCoins = VirtualCoin(self.event_data["backMoney"]) if (refundProtection == 1 and usedTime < refundProtectionTime) and refundCoins != VirtualCoin(0): refundCoins = coins if refundCoins > coins: refundCoins = coins if "openId" in lineInfo: # 扫码使用金币启动 openId = lineInfo["openId"] extra = [] extra.append({u"消费金额": "{}(金币)".format(coins)}) try: if refundCoins > VirtualCoin(0): consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: refundCoins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (coins - refundCoins).mongo_amount }) refund_money(self.device, refundCoins, openId) extra.append({u"退款金额": "{}(金币)".format(refundCoins)}) ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { "open_id": lineInfo["openId"], "port": int(port), "device_imei": self.device.devNo, "isFinished": False }, consumeDict ) finally: user = MyUser.objects(openId=lineInfo["openId"], groupId=self.device.groupId).first() self.notify_user_service_complete( service_name="充电", openid=user.managerialOpenId if user else "", port=port, address=group["address"], reason=self.event_data["reason"], finished_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), extra=extra ) else: logger.error("lz_not net pay rather user virtual card pay. something is wrong.") # 离线卡结束 直接结束服务进程 elif consumeTypeCode == "02": # 离线卡结束 consumeDict = { "chargeIndex": port, "reason": self.event_data["reason"], "leftElec": leftElec, "duration": usedTime, # "finishedTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "cardNo": cardNo, DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: coins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: coins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.ELEC: spendElec, } backMoney = VirtualCoin(self.event_data.get("backMoney", 0)) if backMoney > VirtualCoin(0): consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backMoney.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (coins - backMoney).mongo_amount, }) card = self.update_card_dealer_and_type(cardNo) if not card: logger.info("end charge but no cardNo!!! cardNo=%s" % cardNo) openId = lineInfo.get("openId", cardNo) ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { "open_id": openId, "port": int(port), "device_imei": self.device.devNo, "isFinished": False, }, consumeDict ) # 未绑定用户的离线卡 if card.cardNo == card.openId: return extra = [{u"实体卡号": cardNo}] if backMoney > VirtualCoin(0): extra.append({ u"等待靠卡返回金额": u"{}(金币)".format(backMoney.mongo_amount) }) else: extra.append({ u"消耗金额": u"{}(金币)".format(lineInfo.get("coins",0)) }) self.notify_user_service_complete( service_name=u"充电", openid=self.get_managerialOpenId_by_openId(lineInfo.get("openId")), port=port, address=group["address"], reason=self.event_data["reason"], finished_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), extra=extra ) def do_time_finish(self, devNo, port, lineInfo, msgDict=None): try: refundProtection = lineInfo.get("refundProtection", 0) refundProtectionTime = int(lineInfo.get("refundProtectionTime", 5)) startTime = to_datetime(lineInfo["startTime"]) nowTime = datetime.datetime.now() if startTime > nowTime: logger.error("lz_start time is bigger than now time,devNo={}".format(devNo)) usedTime = 0 else: usedTime = (((nowTime - startTime).total_seconds() + 59) / 60) leftTime = int(self.event_data["leftTime"]) actualNeedTime = usedTime + leftTime group = self.device.group # type: GroupDict coins = VirtualCoin(lineInfo.get("coins")) consumeTypeCode = self.event_data["consumeTypeCode"] if consumeTypeCode == "01": # 投币结束上报 记录到表中 CoinConsumeRcd = ConsumeRecord.objects.get(orderNo=lineInfo["orderNo"]) CoinConsumeRcd.finishedTime = datetime.datetime.now() consumeDict = { "reason": self.event_data["reason"], "leftTime": leftTime, "duration": usedTime, # "finishedTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "leftMoney": self.event_data["backMoney"], } servicedInfo = CoinConsumeRcd.servicedInfo servicedInfo.update(consumeDict) servicedInfo["rechargeCode"] = self.event_data["rechargeCode"] CoinConsumeRcd.servicedInfo = servicedInfo CoinConsumeRcd.save() valueDict = { DEALER_CONSUMPTION_AGG_KIND.TOTAL_COUNT: servicedInfo.get("totalCount"), DEALER_CONSUMPTION_AGG_KIND.DURATION: servicedInfo.get("duration") } status = CoinConsumeRcd.update_agg_info(valueDict) if status: record_consumption_stats(CoinConsumeRcd) ServiceProgress.objects(device_imei=self.device.devNo, port=int(port), isFinished=False).update_one( upsert=False, isFinished=True) elif consumeTypeCode == "02": # 离线卡 # 服务消息 consumeDict = { "reason": self.event_data["reason"], "leftTime": leftTime, "chargeIndex": port, "duration": usedTime, "cardNo": self.event_data["cardNo"], DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: lineInfo['coins'], DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: lineInfo['coins'], } card = Card.objects.filter(cardNo=lineInfo["cardNo"], agentId=self.dealer.agentId).first() if not card: logger.error("lz_not exist this card no.") return openId = lineInfo.get("openId", card.cardNo) backMoney = VirtualCoin(self.event_data.get("backMoney")) if backMoney > VirtualCoin(0): consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: VirtualCoin(self.event_data["backMoney"]).mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (coins-backMoney).mongo_amount }) ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId, {"open_id": openId, "port": int(port), "device_imei": self.device.devNo, "isFinished": False}, consumeDict) # 判断是否绑卡 绑卡就推送,不绑卡就不推送 if card.cardNo == card.openId: return extra = [{ u"实体卡号": lineInfo["cardNo"] }] if VirtualCoin(self.event_data["backMoney"]) > VirtualCoin(0): extra.append({ u"等待靠卡返回金额": u"{}(金币)".format(self.event_data["backMoney"]) }) self.notify_user_service_complete( service_name="充电", openid=card.managerialOpenId if card else "", port=port, address=group["address"], reason=self.event_data["reason"], finished_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), extra=extra) elif consumeTypeCode == "04": # 扫码支付 extra = [] consumeDict = { "reason": self.event_data["reason"], "leftTime": leftTime, "chargeIndex": port, "duration": usedTime, DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: coins.mongo_amount, } coins = VirtualCoin(lineInfo["coins"]) backCoins = VirtualCoin(0) if self.device.is_auto_refund: backCoins = VirtualCoin(self.event_data.get("backMoney", 0)) if (refundProtection == 1 and usedTime < refundProtectionTime) and backCoins != VirtualCoin(0): backCoins = coins if backCoins > coins: backCoins = coins logger.debug( "lz_lefttime = {}, usedTime = {}, need time = {}, back coins = {}".format(leftTime, usedTime, actualNeedTime, backCoins)) if "openId" in lineInfo: try: if backCoins > VirtualCoin(0): consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: backCoins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (coins- backCoins).mongo_amount }) refund_money(self.device, backCoins, lineInfo["openId"]) extra.append({u"消费金额": "{}(金币)".format(coins)}) extra.append({u"退款金额": "{}(金币)".format(backCoins)}) else: extra.append({u"消费金额": "{}(金币)".format(coins)}) ServiceProgress.update_progress_and_consume_rcd(self.device.ownerId, {"open_id": lineInfo["openId"], "port": int(port), "device_imei": self.device.devNo, "isFinished": False}, consumeDict) user = MyUser.objects(openId=lineInfo["openId"], groupId=self.device.groupId).first() self.notify_user_service_complete( service_name="充电", openid=user.managerialOpenId if user else "", port=port, address=group["address"], reason=self.event_data["reason"], finished_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), extra=extra ) except Exception as e: logger.info(e) else: # 后续在线卡或是其他 pass except Exception as e: logger.exception(e) def do_billAsService_finish(self,devNo, port, lineInfo, msgDict=None): serviceFee = float(self.event_data.get("serviceFee", 0)) reasonStr = self.event_data.get("reason") cardNo = self.event_data.get("cardNo") startTime = lineInfo.get("startTime") startTime = to_datetime(startTime) nowTime = datetime.datetime.now() coins = VirtualCoin(lineInfo.get("coins")) if serviceFee == 65535: serviceFee = 0 usedElec = 0 usedElecFee = 0 else: usedElec = float(serviceFee) / float(self.device.devTypeFeatures.get("billAsService").get("serviceCharge")) usedElecFee = float(str(coins)) - float(self.event_data.get("backMoney")) - serviceFee if startTime > nowTime: usedTime = 0 else: usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0))) # 获取组信息 group = Group.get_group(self.device["groupId"]) consumeTypeCode = self.event_data["consumeTypeCode"] if consumeTypeCode == "01": # 投币结束上报 记录到表中 CoinConsumeRcd = ConsumeRecord.objects.get(orderNo=lineInfo["orderNo"]) CoinConsumeRcd.finishedTime = datetime.datetime.now() consumeDict = { "chargeIndex": port, "reason": reasonStr, "leftMoney": self.event_data["backMoney"], DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime, } servicedInfo = CoinConsumeRcd.servicedInfo servicedInfo.update(consumeDict) servicedInfo["rechargeCode"] = self.event_data["rechargeCode"] CoinConsumeRcd.servicedInfo = servicedInfo CoinConsumeRcd.save() valueDict = { DEALER_CONSUMPTION_AGG_KIND.TOTAL_COUNT: servicedInfo.get("totalCount"), DEALER_CONSUMPTION_AGG_KIND.DURATION: servicedInfo.get("duration"), DEALER_CONSUMPTION_AGG_KIND.ELECFEE: usedElecFee, DEALER_CONSUMPTION_AGG_KIND.SERVICEFEE: serviceFee, } status = CoinConsumeRcd.update_agg_info(valueDict) if status: record_consumption_stats(CoinConsumeRcd) ServiceProgress.objects(device_imei=self.device.devNo, port=int(port), isFinished=False).update_one( upsert=False, isFinished=True, expireAt = datetime.datetime.now()) elif consumeTypeCode == "02": # 离线卡结束 consumeDict = { "chargeIndex": port, "reason": self.event_data["reason"], "duration": usedTime, "cardNo": cardNo, DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: VirtualCoin(coins).mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: VirtualCoin(coins).mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SERVICEFEE: serviceFee, DEALER_CONSUMPTION_AGG_KIND.ELECFEE: usedElecFee, } backMoney = VirtualCoin(self.event_data.get("backMoney", 0)) if backMoney > VirtualCoin(0): consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backMoney.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (coins - backMoney).mongo_amount, }) card = self.update_card_dealer_and_type(cardNo) if not card: logger.info("end charge but no cardNo!!! cardNo=%s" % cardNo) openId = lineInfo.get("openId", cardNo) ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { "open_id": openId, "port": int(port), "device_imei": self.device.devNo, "isFinished": False, }, consumeDict ) # 未绑定用户的离线卡 if card.cardNo == card.openId: return extra = [{u"实体卡号": cardNo}] if backMoney > VirtualCoin(0): extra.append({ u"等待靠卡返回金额": u"{}(金币)".format(backMoney.mongo_amount) }) else: extra.append({ u"消耗金额": u"{}(金币)".format(lineInfo.get("coins",0)), u"服务费金额": "{}(金币)".format(serviceFee), u"电费金额": "{}(金币)".format(float(lineInfo.get("coins",0)) - serviceFee) }) self.notify_user_service_complete( service_name=u"充电", openid=self.get_managerialOpenId_by_openId(lineInfo.get("openId")), port=port, address=group["address"], reason=self.event_data["reason"], finished_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), extra=extra ) elif consumeTypeCode == "03": pass elif consumeTypeCode == "04": # 扫码的结束 refundCoins = VirtualCoin(0) consumeDict = { "reason": reasonStr, "chargeIndex": port, "duration": usedTime, DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.ELEC: usedElec, DEALER_CONSUMPTION_AGG_KIND.ELECFEE: usedElecFee, DEALER_CONSUMPTION_AGG_KIND.SERVICEFEE: serviceFee } refundSwitch = self.device.is_auto_refund refundProtection = int(lineInfo.get("refundProtection", 0)) refundProtectionTime = int(lineInfo.get("refundProtectionTime", 5)) if refundSwitch: refundCoins = VirtualCoin(self.event_data["backMoney"]) if (refundProtection == 1 and usedTime < refundProtectionTime) and refundCoins != VirtualCoin(0): refundCoins = coins if refundCoins > coins: refundCoins = coins if "openId" in lineInfo: # 扫码使用金币启动 openId = lineInfo["openId"] extra = [] extra.append({u"消费金额": "{}(金币)".format(coins)}) extra.append({u"服务费金额": "{}(金币)".format(serviceFee)}) extra.append({u"电费金额": "{}(金币)".format(usedElecFee)}) try: if refundCoins > VirtualCoin(0): consumeDict.update({ DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: refundCoins.mongo_amount, DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (coins - refundCoins).mongo_amount }) refund_money(self.device, refundCoins, openId) extra.append({u"退款金额": "{}(金币)".format(refundCoins)}) ServiceProgress.update_progress_and_consume_rcd( self.device.ownerId, { "open_id": lineInfo["openId"], "port": int(port), "device_imei": self.device.devNo, "isFinished": False }, consumeDict ) finally: user = MyUser.objects(openId=lineInfo["openId"], groupId=self.device.groupId).first() self.notify_user_service_complete( service_name="充电", openid=user.managerialOpenId if user else "", port=port, address=group["address"], reason=self.event_data["reason"], finished_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), extra=extra ) else: logger.error("lz_not net pay rather user virtual card pay. something is wrong.") # 离线卡结束 直接结束服务进程 class LVZHIFaultEvent(FaultEvent): def do(self, **args): group = Group.get_group(self.device["groupId"]) port = self.event_data.get("port") faultContent = self.event_data.get("statusInfo") if port: if self.event_data.get("FaultCode") == "01": faultContent = "当前设备第%s号端口警告:发生非法充电" % (port) else: faultContent = "当前设备第%s号端口发生故障: %s" % (port, faultContent) if self.event_data.get("FaultCode") == "04": self.notify_dealer( templateName="device_fault", title="注意!设备火警预告!", device=u"{groupNumber}组-{logicalCode}".format(groupNumber=self.device["groupNumber"], logicalCode=self.device["logicalCode"]), location=u"{address}-{groupName}".format(address=group["address"], groupName=group["groupName"]), fault=faultContent, notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) self.record( faultCode=self.event_data.get("FaultCode"), description=faultContent, title="注意!设备火警预告!", # detail=self.event_data.get("statusInfo"), ) elif self.event_data.get("FaultCode") == "01": self.notify_dealer( templateName="device_fault", title="注意!非法充电警告!", device=u"{groupNumber}组-{logicalCode}".format(groupNumber=self.device["groupNumber"], logicalCode=self.device["logicalCode"]), location=u"{address}-{groupName}".format(address=group["address"], groupName=group["groupName"]), fault=faultContent, notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) self.record( faultCode=self.event_data.get("FaultCode"), description=faultContent, title="注意!非法充电警告!", ) # 端口管理页面需要看到非法充电端口的端口状态,所以需要在非法充电信息报上来的时候将状态记录到缓存中 if port: portInfo = { "port": str(int(port)), "billingType": "faultCharge", "startTime" : datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "statusErrorInfo": "非法充电" } Device.update_port_control_cache(self.device.devNo,portInfo) else: self.notify_dealer( templateName="device_fault", title="注意!您的设备当前发生故障!", device=u"{groupNumber}组-{logicalCode}".format(groupNumber=self.device["groupNumber"], logicalCode=self.device["logicalCode"]), location=u"{address}-{groupName}".format(address=group["address"], groupName=group["groupName"]), fault=faultContent, notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) self.record( faultCode=self.event_data.get("FaultCode"), description=faultContent, title="注意!您的设备当前发生故障!", # detail=self.event_data.get("statusInfo"), ) class LVZHIOnline(WorkEvent): def do(self, **args): ctrInfo = Device.get_dev_control_cache(self.device.devNo) if ctrInfo: for k , v in ctrInfo.items(): if isinstance(v,dict): if 'statusErrorInfo' in v: if v['statusErrorInfo'] == "非法充电": Device.clear_port_control_cache(self.device.devNo, str(k))