# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import random import time import simplejson as json from bson import ObjectId from mongoengine import DoesNotExist, ValidationError from typing import TYPE_CHECKING from apilib.monetary import RMB, VirtualCoin, Ratio from apilib.utils_datetime import to_datetime from apilib.utils_sys import memcache_lock from apps import serviceCache from apps.web.agent.models import Agent from apps.web.common.models import TempValues from apps.web.constant import FAULT_CODE, FAULT_LEVEL, Const, DEALER_CONSUMPTION_AGG_KIND, USER_RECHARGE_TYPE from apps.web.core.accounting import Accounting from apps.web.core.payment import WithdrawGateway from apps.web.dealer.models import Dealer from apps.web.device.models import Group, Device from apps.web.eventer import EventBuilder from apps.web.eventer.base import WorkEvent, FaultEvent from apps.web.report.ledger import Ledger from apps.web.user.models import CardRechargeOrder, Card, RechargeRecord, CardRechargeRecord, ServiceProgress, \ ConsumeRecord, CardConsumeRecord, MyUser, UserVirtualCard if TYPE_CHECKING: from apps.web.device.models import GroupDict logger = logging.getLogger(__name__) class PayTypeEnum(object): COUNT_CARD = '00' NET_PAY = '01' OFFLINE_COIN = '02' PREPAID_CARD = '03' class builder(EventBuilder): def __getEvent__(self, device_event): eventData = self.deviceAdapter.analyze_event_data(device_event.get('data')) if eventData is None or 'cmdCode' not in eventData: return None if "ack_id" in device_event: eventData["ack_id"] = device_event["ack_id"] if eventData['cmdCode'] == 'D7': return ChangYuanFaultEventer(self.deviceAdapter, eventData) else: return ChangYuanWorkEventer(self.deviceAdapter, eventData) class ChangYuanFaultEventer(FaultEvent): def do(self, **args): if "ack_id" in self.event_data: self.deviceAdapter._ack(self.event_data["ack_id"]) self.event_data.update({ 'faultName': u'设备火灾预警', 'faultCode': FAULT_CODE.FIRE_ALARM, 'level': FAULT_LEVEL.CRITICAL, 'desc': u'主板上报设备火警' }) warningData = { "warningStatus": 2, "warningDesc": "设备温度超限警告", "warningTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") } # 整机告警 Device.update_dev_warning_cache(self.device.devNo, {"0": warningData}) super(ChangYuanFaultEventer, self).do(**args) class ChangYuanWorkEventer(WorkEvent): def do(self, **args): if "ack_id" in self.event_data: self.deviceAdapter._ack(self.event_data['ack_id']) cmdCode = self.event_data.get('cmdCode') cacheKey = '{}-{}-event'.format(self.device.devNo, cmdCode) with memcache_lock(key=cacheKey, value='1', expire=120) as acquired: if acquired: if cmdCode == 'D3': self._do_recharge_card_result() elif cmdCode == 'D4': self._do_recharge_card() elif cmdCode == 'D9': self._do_start_charge() elif cmdCode == 'DA': self._do_finish() elif cmdCode == 'DE': self._do_card_refund() else: logger.warning( 'cyp_event is doing!, dev is <{}>, cacheKey is <{}>, cmd is <{}>, data is <{}>'.format( self.device.devNo, cacheKey, cmdCode, self.event_data ) ) def _do_card_refund(self): beforeRefund = self.event_data.get('beforeRefund') refund = self.event_data.get('refund') afterRefund = self.event_data.get('afterRefund') cardNo = str(self.event_data.get('cardNo')) # 指令上传错误 if VirtualCoin(beforeRefund) + VirtualCoin(refund) != VirtualCoin(afterRefund): logger.info('bad refund event, beforeRefund is {}, refund is {} afterRefund is {}'.format( beforeRefund, refund, afterRefund )) return # 查找卡的消息 一定要是预付费卡 card = self._update_card_dealer_and_type(cardNo, "01") if not card: return # 查看返费前的金额是否是相等的 if VirtualCoin(card.balance) != VirtualCoin(beforeRefund): logger.info( 'beforeRefund is not equal card balance, cardNo is {}, beforeRefund is {}, card balance is {}'.format( cardNo, beforeRefund, card.balance )) return # 退费 self.refund_money_for_card(RMB(refund), str(card.id)) # 通知用户 self.notify_user( card.managerialOpenId or "", 'refund_coins', **{ 'title': u'预付卡充电桩返费', 'backCount': u'%s' % refund, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') } ) @staticmethod def _do_update_ConsumeRecord_CardConsumeRecord_service_progress(portCache, updateMoney): portCache['payCount'] = portCache.get('payCount') + 1 portCache['allPayMoney'] = updateMoney portCache['coins'] = updateMoney orderNo = portCache.get('orderNo') cardOrderNo = portCache.get('cardOrderNo') try: order = ConsumeRecord.objects.get(orderNo=orderNo) card_order = CardConsumeRecord.objects.get(orderNo=cardOrderNo) service_pogress = ServiceProgress.objects(__raw__={'consumeOrder.orderNo': orderNo}).first() order.coin = updateMoney order.money = updateMoney card_order.money = updateMoney service_pogress.consumeOrder['money'] = updateMoney service_pogress.consumeOrder['coin'] = updateMoney order.save() card_order.save() service_pogress.save() except Exception as e: logger.debug('%s' % e) finally: pass def _do_recharge_card(self): """ 同步卡的请求 :return: """ cardNo = self.event_data.get('cardNo') cardBalance = self.event_data.get('cardBalance') cardType = self.event_data.get('cardType') # 查询卡 包括卡的类型 card = self._update_card_dealer_and_type(cardNo, billing_method=cardType) if not card: return # 更新卡的余额 以设备侧的为准 if RMB(cardBalance) != card.balance: logger.info('Card<{}> balance<{}> needs to be sync !!!'.format(cardNo, card.balance)) card.balance = RMB(cardBalance) card = card.save() # orderNos 表示充值的订单 cardOrderNos 表示卡充值的订单 money, coins, orderNos, cardOrderNos = CardRechargeOrder.get_to_do_list(str(card.id)) # 一旦卡被冻结 立即下发 创建一张为 负数的金额订单 将卡的余额清空 if card.frozen: group = Group.get_group(card.groupId) CardRechargeOrder.new_one( openId=card.openId, cardId=str(card.id), cardNo=card.cardNo, money=RMB(0), coins=VirtualCoin(0) - VirtualCoin(coins) - VirtualCoin(card.balance), group=group, rechargeId=ObjectId(), rechargeType='sendCoin' ) money, coins, orderNos, cardOrderNos = CardRechargeOrder.get_to_do_list(str(card.id)) # 没有需要同步的订单的情况下 直接退出 if not orderNos: logger.info('Not card recharge record!, card is <{}>'.format(cardNo)) # self._do_offline_recharge_by_dealer(cardNo, card, cardType) return orderNos = [str(item) for item in orderNos] sid = str(random.randint(0, 0xFFFF)) TempValues.set('%s-%s' % (self.device.devNo, sid), value=json.dumps(orderNos)) TempValues.set('%s-%s-%s' % (self.device.devNo, sid, cardNo), value=json.dumps(cardOrderNos)) TempValues.set('%s-%s' % (self.device.devNo, cardNo), value=str(sid)) # 计算总的需要同步的金额 asyncMoney = RMB(cardBalance) + RMB(coins) logger.info('ready to recharge card, card is <{}>, money is <{}>'.format(cardNo, coins)) # 已经下发金额后,先将订单的状态改为结束。如果主板上报失败,再将订单状态迁移回来否则就不再变化订单状态了 try: CardRechargeOrder.update_card_order_has_finished(str(card.id)) except Exception as e: logger.debug('%s' % e) else: self.deviceAdapter._async_card_balance(cardType, cardNo, asyncMoney) def _do_recharge_card_result(self): """ 确认卡的同步结果 :return: """ asyncStatus = self.event_data.get('result') answerSid = self.event_data.get('sid') cardBalance = self.event_data.get('cardBalance') cardNo = str(self.event_data.get('cardNo')) cardType = self.event_data.get('cardType') # 先找卡 卡都不存在的话 直接推掉 card = self._update_card_dealer_and_type(cardNo, cardType) if not card: return sid = TempValues.get('{}-{}'.format(self.device.devNo, cardNo)) if sid != answerSid: logger.error('answer sid is not equal sid <{}>-<{}>'.format(sid, answerSid)) return # 根据sid 以及卡号 查询出此次充值的所有的订单 orderNos = TempValues.get('{}-{}'.format(self.device.devNo, sid)) cardOrderNos = TempValues.get('{}-{}-{}'.format(self.device.devNo, sid, cardNo)) # 明确接收到了主板同步失败的情况下 直接退出 不在转换充值订单的问题 防止出错 if not asyncStatus: logger.error("card async not success! event data is <{}>".format(self.event_data)) return # 下面的都不会更改订单的状态 最多走售后 money, coins = RMB(0), VirtualCoin(0) # 校验金额是否是相等的 orderNos = [ObjectId(item) for item in orderNos] rds = RechargeRecord.objects.filter(ownerId=card.dealerId, id__in=orderNos) for item in rds: money += item.money coins += item.coins # 这个地方就是异常值处理了 if VirtualCoin(coins + card.balance) != VirtualCoin(cardBalance): logger.error('card pre balance not equal now balance! event is <{}>'.format(self.event_data)) return # 依次更改卡充值的订单 并创建充值订单 cardOrders = CardRechargeOrder.objects.filter(orderNo__in=cardOrderNos) for _order in cardOrders: # type: CardRechargeOrder _order.update_after_recharge_ic_card( device=self.device, sendMoney=RMB(_order.coins), preBalance=card.balance ) preBalance = card.balance card.balance = card.balance + _order.coins # 创建充值记录 CardRechargeRecord.add_record( card=card, group=Group.get_group(_order.groupId), order=_order, device=self.device ) # 保存 card.save() # 完成之后将TempValue 的key value 清空 TempValues.remove('%s-%s' % (self.device['devNo'], sid)) TempValues.remove('%s-%s' % (self.device['devNo'], cardNo)) TempValues.remove("%s-%s-%s" % (self.device["devNo"], sid, cardNo)) def _do_start_charge(self): ''' 充电开始指令, 主要是更新各种缓存等等, 对于扫码的启动基本在adapter缓存已经处理完成,主要需要处理的是刷卡的启动 根据 需求方要求 刷卡的可以做合单处理 :return: ''' logger.info( 'do_start_charge() is run!! event_data:{}'.format(self.event_data)) portStr = str(self.event_data.get('port')) ctrInfo = Device.get_dev_control_cache(self.device.devNo) lineInfo = ctrInfo.get(portStr, {'port': portStr}) payType = self.event_data.get('payType') if payType == PayTypeEnum.NET_PAY: # 线上支付 if lineInfo.get('status', Const.DEV_WORK_STATUS_IDLE) == Const.DEV_WORK_STATUS_IDLE: lineInfo['power'] = self.event_data.get('power') lineInfo['payType'] = self.event_data.get('payType') lineInfo['needTime'] = self.event_data.get('needTime') logger.info("NET_PAY is ok!!") else: lineInfo['power'] = self.event_data.get('power') lineInfo['needTime'] = self.event_data.get('needTime') logger.info("NET_PAY is ok!!") Device.update_port_control_cache(self.device.devNo, lineInfo) return elif payType == PayTypeEnum.OFFLINE_COIN: Accounting.recordOfflineCoin(self.device, int(time.time()), int(self.event_data['coins'])) orderNo = self.record_consume_for_coin(RMB(self.event_data["coins"])) Device.update_port_control_cache( self.device["devNo"], {'port': portStr, "isStart": True, "coins": self.event_data["coins"], "needTime": self.event_data["needTime"], "power": self.event_data["power"], "payType": self.event_data["payType"], "startTime": datetime.datetime.now().strftime(Const.DATETIME_FMT), "status": Const.DEV_WORK_STATUS_WORKING, "consumeOrderNo": orderNo, "payInfo": [{ "coins": float(self.event_data["coins"]), "price": float(self.event_data["coins"]), "needTIme": self.event_data["needTime"], "consumeOrderNo": orderNo }] }) else: cardNo = self.event_data.get('cardNo') if cardNo == '00000000': # 可能是虚拟卡 暂不处理 return cardBalance = RMB(self.event_data.get('cardBalance')) coins = self.event_data.get('coins') card = self._update_card_dealer_and_type(cardNo, billing_method=self.event_data["cardType"]) needTime = self.event_data.get('needTime') needBindCard = self.device['otherConf'].get('needBindCard', True) if not card: if needBindCard: # 需要绑卡却没有绑卡 直接停止 return self.deviceAdapter.stop_charging_port(portStr) else: return if card.frozen: self.notify_invalid_card_to_dealer(cardNo, card) # 停止此离线卡的充电行为 self.deviceAdapter.stop_charging_port(portStr) return if not Group.is_currency_mode_group(card.groupId, self.device.groupId): # 地址组通用校验 logger.info( 'is_currency_mode_group is fail <{}> card_group=<{}> dev_group=<{}>'.format(cardNo, card.groupId, self.device.groupId)) return self.deviceAdapter.stop_charging_port(portStr) # 离线卡 以设备上报过来的数据为准 card.balance = cardBalance.mongo_amount card.save() card.reload() if lineInfo.get('status', Const.DEV_WORK_STATUS_IDLE) != Const.DEV_WORK_STATUS_IDLE and cardNo == lineInfo.get( 'cardNo'): logger.info('Card<{}> Swipe to pay again!!'.format(cardNo)) orderNo = lineInfo.get('orderNo') cardOrderNo = lineInfo.get('cardOrderNo') lineInfo['coins'] += coins lineInfo['payCount'] += 1 if not needTime: needTime = 0 # lineInfo['needTime'] = needTime ConsumeRecord.objects.filter(orderNo=orderNo).update_one(inc__coin=coins, inc__money=coins) CardConsumeRecord.objects.filter(orderNo=cardOrderNo).update_one(inc__money=coins, dec__balance=coins) ServiceProgress.objects.filter(device_imei=self.device.devNo, port=int(portStr), consumeOrder__orderNo=orderNo, isFinished=False).update_one( inc__consumeOrder__coin=coins, inc__finished_time=(time.time() + needTime * 60)) # 第一次刷卡 else: logger.info('Card<{}> start charge the once!!'.format(cardNo)) # 记录ID卡的消费 attachParas = { 'chargeIndex': portStr } servicedInfo = { 'cardNo': cardNo, 'chargeIndex': portStr } orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(coins), servicedInfo=servicedInfo, attachParas=attachParas) # 记录缓存信息 可以在个人中心以及经销商的端口管理显示 lineInfo = { 'port': portStr, 'cardNo': cardNo, 'openId': card.openId, 'payCount': 1, 'coins': coins, 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'orderNo': orderNo, 'cardOrderNo': cardOrderNo, 'payType': payType, 'consumeType': 'card', } finishedTime = None if needTime: finishedTime = int(time.time()) + needTime * 60 # lineInfo['needTime'] = needTime ServiceProgress.register_card_service( self.device, int(portStr), card, { 'orderNo': orderNo, 'coin': VirtualCoin(coins).mongo_amount, 'cardOrderNo': cardOrderNo }, finishedTime) logger.info('port:{} is running, order:{} cardOrder:{}'.format(portStr, orderNo, cardOrderNo)) # 更新端口缓存 Device.update_port_control_cache(self.device.devNo, lineInfo) # 通知卡消费成功 self.notify_balance_has_consume_for_card(card, coins) def _do_finish(self): ''' 充电结束的指令 :return: ''' portStr = str(self.event_data.get('port')) FINISHED_COUNT_KEY = 'device_port_finish_{}_{}'.format(self.device.devNo, portStr) count = serviceCache.get(FINISHED_COUNT_KEY, 0) ctrInfo = Device.get_dev_control_cache(self.device.devNo) lineInfo = ctrInfo.get(portStr) if not lineInfo or lineInfo.get('payType') is None: logger.info('cache is missing ,DA is over') return duration = ((datetime.datetime.now() - to_datetime(lineInfo.get('startTime'))).total_seconds() + 59) // 60 if duration < 3: count += 1 serviceCache.set(FINISHED_COUNT_KEY, count, 60 * 60 * 24) if count >= 3: self.notify_fault_to_dealer() serviceCache.delete(FINISHED_COUNT_KEY) payType = lineInfo.get('payType') try: if payType == PayTypeEnum.NET_PAY: self._do_netpay_finish(portStr, lineInfo) elif payType == PayTypeEnum.OFFLINE_COIN: self._do_offline_coin_finish(portStr, lineInfo) else: self._do_card_finish(portStr, lineInfo) except Exception as e: logger.error('DA is over error:{}'.format(e)) Device.clear_port_control_cache(self.device.devNo, portStr) def _do_card_finish(self, portStr, lineInfo): logger.info('do card finished lineInfo={} ||| event_data={}'.format(lineInfo, self.event_data)) extra = [] coins = lineInfo.get('coins') cardNo = lineInfo.get('cardNo') card = self.update_card_dealer_and_type(cardNo, cardType='IC') if not card: logger.debug('server no find card!!! cardNo=<{}>'.format(cardNo)) return extra.append({u'使用卡片': u'{}--{}'.format(card.cardName, cardNo)}) consumeDict = { 'port': portStr, 'cardNo': cardNo, 'elec': self.event_data.get('usedElec'), 'reason': self.event_data.get('reason'), } payType = lineInfo.get('payType') if payType == PayTypeEnum.COUNT_CARD: # leftTime = self.event_data.get('left') now = datetime.datetime.now() # consumeDict['leftTime'] = leftTime consumeDict['duration'] = ((now - to_datetime(lineInfo.get('startTime'))).total_seconds() + 59) // 60 # consumeDict['actualNeedTime'] = '动态计算时间为{}分钟'.format(consumeDict['duration'] + leftTime) # extra.append({u"使用详情": u"本次使用{}分钟,剩余{}分钟".format(consumeDict['duration'], consumeDict['leftTime'])}) extra.append({u"使用详情": u"本次使用{}分钟".format(consumeDict['duration'])}) elif payType == PayTypeEnum.PREPAID_CARD: leftMoney = self.event_data.get('leftMoney') if leftMoney: leftMoney = float(leftMoney) coins = float(coins) if leftMoney > coins: leftMoney = coins refundedMoney = round(leftMoney, 2) consumeDict['spendMoney'] = round(coins - leftMoney, 2) extra.append( {u"消费明细": u"消费{}金币,剩余{}金币(等待靠卡退费)".format(consumeDict['spendMoney'], refundedMoney)}) else: consumeDict['spendMoney'] = round(coins, 2) extra.append( {u"消费明细": u"消费{}金币".format(coins)}) ServiceProgress.update_progress_and_consume_rcd( self.device['ownerId'], { 'device_imei': self.device['devNo'], 'cardId': str(card.id), 'port': int(portStr), 'isFinished': False }, consumeDict ) self.notify_to_user(card.managerialOpenId, extra) logger.info('do_card_finish is finished!!') def _do_netpay_finish(self, portStr, lineInfo): logger.info('netpay_finish is running !! event_data:{}'.format( json.dumps(self.event_data, ensure_ascii=False))) usedElec = self.event_data.get('spendElec') reason = self.event_data.get('reason') leftMoney = self.event_data.get('leftMoney') extra = [] openId = lineInfo.get('openId') coins = VirtualCoin(lineInfo.get('coins', 0)) money = RMB(lineInfo.get('price', 0)) payInfo = lineInfo.get('payInfo') vCardId = lineInfo.get('vCardId') now = datetime.datetime.now() duration = (now - to_datetime(lineInfo.get('startTime'))).total_seconds() // 60 refundMoney = RMB(leftMoney) if duration <= 5: refundMoney = money # 如果没有openId则为经销商远程上分 if not openId: logger.info('Remote activation by dealer') return else: user = MyUser.objects.filter(openId=openId, groupId=self.device['groupId']).first() consumeDict = { 'port': portStr, 'elec': usedElec, 'duration': duration, 'reason': reason, } logger.info('ChangYuanPower net pay finish and start to notify user! {}-{}'.format(self.device['devNo'], portStr)) if duration > 5: extra.append({u'充电时长': u'{}分钟'.format(duration)}) else: extra.append({u'充电时长': u'0分钟'}) if self.device.is_auto_refund or duration <= 5: if payInfo: # 先做现金分账 for item in payInfo: self.do_ledger(item['rechargeRcdId']) # 现金退款 self.refund_net_pay(user, lineInfo, refundedMoney=refundMoney, refundCoins=VirtualCoin(0), consumeDict=consumeDict, is_cash=True) extra.append({u'消费明细': u'支付{}元,退款{}元'.format(money, refundMoney)}) elif vCardId: try: vCard = UserVirtualCard.objects.get(id=vCardId) extra.append({u'虚拟卡券': u'{}--{}'.format(vCard.cardName, vCard.cardNo)}) except DoesNotExist: logger.info('can not find the vCard id = %s' % vCardId) pass pass else: self.refund_net_pay(user, lineInfo, refundedMoney=RMB(0), refundCoins=VirtualCoin(refundMoney), consumeDict=consumeDict, is_cash=False) extra.append({u'消费明细': u'消费{}金币,退款{}金币'.format(coins, VirtualCoin(refundMoney))}) else: extra.append({u'消费明细': u'消费{}金币'.format(coins)}) if payInfo: for item in payInfo: self.do_ledger(item['rechargeRcdId']) ServiceProgress.update_progress_and_consume_rcd( self.device['ownerId'], { 'open_id': openId, 'device_imei': self.device['devNo'], 'port': int(portStr), 'isFinished': False }, consumeDict ) self.notify_to_user(openId=user.managerialOpenId, extra=extra) logger.info('do_netpay_finish() is over !!') def _update_card_dealer_and_type(self, cardNo, billing_method): """ 昌原的都是IC卡 并且需要标注卡类型 :param cardNo: 卡号 :param billing_method: 卡类型 :return: """ card = self.update_card_dealer_and_type(cardNo, "IC") # type: Card if not card: logger.error("not found card <{}>, event is <{}>".format(cardNo, self.event_data)) return None # 没有卡的计费类型的 说明是经销商新添加的卡 添加上计费类型 有了卡计费类型的 需要比较卡计费类型是否正确 如果不正确的 说明卡不正确 if not card.billing_method: card.billing_method = billing_method if not card.billing_method_equal(billing_method): logger.error("card <{}> billing_method not equal!, event is <{}>".format(cardNo, self.event_data)) return None return card def update_card_dealer_and_type(self, cardNo, cardType='ID', isHaveBalance=True, balance=None): """ 更新卡的状态 重写目的 如果卡不存在 立即下发停止充电指令 而不是新建一张卡 :param cardNo: :param cardType: :param isHaveBalance: :param balance: :return: """ dealer = Dealer.objects.get(id=self.device['ownerId']) agent = Agent.objects.get(id=dealer.agentId) if not agent: logger.error('agent is not found, agentId=%s' % dealer.agentId) return try: card = Card.objects.filter(cardNo=cardNo, agentId=dealer.agentId).first() if not card: return None # 如果卡没有被绑定,这个时候检查下绑定关系。如果卡已经被某个经销商认领了,就不要刷新,不要动了 if card.cardType and card.dealerId and card.devNo and (card.dealerId == self.device['ownerId']): return card else: card.dealerId = self.device['ownerId'] card.devNo = self.device['devNo'] card.cardType = cardType card.devTypeCode = self.device['devType']['code'] card.isHaveBalance = isHaveBalance card.save() return card except Exception as e: logger.exception(e) return def notify_to_user(self, openId, extra): group = Group.get_group(self.device['groupId']) self.notify_user_service_complete( service_name='充电', openid=openId, port=self.event_data['port'], address=group['address'], reason=self.event_data.get('reason'), finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), extra=extra) def notify_invalid_card_to_dealer(self, cardNo, card): logger.info('Illegal card <{}>, charging is about to stop'.format(cardNo)) group = Group.get_group(self.device['groupId']) self.notify_dealer( 'device_fault', title=u'注意!注意!您当前的设备已被非法卡使用!', device=u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']), location=u'组名称:%s, 地址:%s' % (group['groupName'], group['address']), fault=u'在%s编号为%s的设备被非法卡卡启动,启动卡号为:%s 卡联系人 %s 卡联系电话 %s' % ( group['address'], self.device['logicalCode'], card.cardNo if card else '', card.phone if card else '', card.cardName if card else ''), notifyTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') ) def _do_offline_coin_finish(self, portStr, lineInfo): CoinConsumeRcd = ConsumeRecord.objects.get(orderNo=lineInfo.get('consumeOrderNo')) startTime = lineInfo.get('startTime') startTime = to_datetime(startTime) nowTime = datetime.datetime.now() if startTime > nowTime: usedTime = 0 else: usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0))) consumeDict = { 'chargeIndex': portStr, 'reason': self.event_data.get('reason'), 'leftTime': self.event_data.get('left', 0), 'actualNeedTime': usedTime + self.event_data.get('left', 0), DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime, DEALER_CONSUMPTION_AGG_KIND.ELEC: self.event_data.get('usedElec'), DEALER_CONSUMPTION_AGG_KIND.TOTAL_COUNT: lineInfo.get('coins'), } CoinConsumeRcd.update_service_info(consumeDict) CoinConsumeRcd.update(status='finished', finishedTime=nowTime) def notify_fault_to_dealer(self): group = self.device.group self.notify_dealer( templateName='device_fault', title=u'端口连续停止超过三次', device=u'{groupNumber}组-{logicalCode}-端口{port}'.format(groupNumber=self.device['groupNumber'], logicalCode=self.device['logicalCode'], port=self.event_data.get('port')), location=u'{address}-{groupName}'.format(address=group['address'], groupName=group['groupName']), fault=u'端口连续停止超过三次', notifyTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') ) def anonymous_user_start(self, lineInfo): coins = self.event_data.get('coins') cardNo = self.event_data.get('cardNo') port = self.event_data.get('port') needTime = self.event_data.get('needTime') cardBalance = self.event_data.get('cardBalance') payType = self.event_data.get('payType') if lineInfo.get('status', Const.DEV_WORK_STATUS_IDLE) != Const.DEV_WORK_STATUS_IDLE and cardNo == lineInfo.get( 'cardNo'): logger.info('anonymous_user card<{}> Swipe to pay again!!'.format(cardNo)) orderNo = lineInfo.get('orderNo') cardOrderNo = lineInfo.get('cardOrderNo') lineInfo['coins'] += coins lineInfo['payCount'] += 1 if not needTime: needTime = 0 # lineInfo['needTime'] = needTime ConsumeRecord.objects.filter(orderNo=orderNo).update_one(inc__coin=coins, inc__money=coins) CardConsumeRecord.objects.filter(orderNo=cardOrderNo).update_one(inc__money=coins, dec__balance=coins) ServiceProgress.objects.filter(device_imei=self.device.devNo, port=port, consumeOrder__orderNo=orderNo, isFinished=False).update_one( inc__consumeOrder__coin=coins, inc__finished_time=(time.time() + needTime * 60)) # 第一次刷卡 else: logger.info('anonymous_user card<{}> start charge the once!!'.format(cardNo)) card = Card( cardNo=cardNo, dealerId=self.device.ownerId, agentId=self.device.owner.agentId, groupId=self.device.groupId, openId=Const.DEFAULT_CARD_OPENID, balance=RMB(cardBalance), ).save() # 记录ID卡的消费 attachParas = { 'chargeIndex': port } servicedInfo = { 'cardNo': cardNo, 'chargeIndex': port, } orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(coins), servicedInfo=servicedInfo, attachParas=attachParas) # 记录缓存信息 可以在个人中心以及经销商的端口管理显示 lineInfo = { 'port': port, 'cardNo': cardNo, 'openId': card.openId, 'payCount': 1, 'coins': coins, 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'orderNo': orderNo, 'cardOrderNo': cardOrderNo, 'payType': payType, 'consumeType': 'card', } finishedTime = None if needTime: finishedTime = int(time.time()) + (needTime + 5) * 60 # lineInfo['needTime'] = needTime ServiceProgress.register_card_service( self.device, port, card, { 'orderNo': orderNo, 'coin': VirtualCoin(coins).mongo_amount, 'cardOrderNo': cardOrderNo }, finishedTime) logger.info('port:{} is running, order:{} cardOrder:{}'.format(port, orderNo, cardOrderNo)) # 更新端口缓存 Device.update_port_control_cache(self.device.devNo, lineInfo)