# -*- 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 apilib.utils_string import make_title_from_dict from apps.web.constant import DEALER_CONSUMPTION_AGG_KIND, Const from apps.web.device.models import Group, Device from apps.web.eventer import EventBuilder from apps.web.eventer.base import FaultEvent, WorkEvent from apps.web.user.models import Card, CardRechargeOrder, CardConsumeRecord, MyUser, ServiceProgress, \ UserVirtualCard, ConsumeRecord 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: return None if event_data.has_key('status') and event_data.get('isFaultClass'): return LSHBFaultEvent(self.deviceAdapter, event_data) elif event_data.has_key('funCode') and event_data['funCode'] in ['15', '16', '17', '1B']: # 沥森环保的卡消费,需要记录一下 return LSHBRechargeEvent(self.deviceAdapter, event_data) elif event_data.has_key('funCode') and event_data['funCode'] in ['19','20']: # 在线卡流程 return LSHBonlineCardEvent(self.deviceAdapter, event_data) else: return WorkEvent(self.deviceAdapter, event_data) class LSHBRechargeEvent(WorkEvent): def support_playback(self): return self.event_data.get('funCode') == '1B' def do(self, **args): if self.event_data.get('funCode') == '15': cardNo = self.event_data['cardNo'] card = self.update_card_dealer_and_type(cardNo, 'IC') # type: Card if not card: return if card.frozen: logger.debug('{} has been frozen.'.format(repr(card))) return preBalance = RMB(self.event_data['money']) Card.update_balance(card.id, preBalance) card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) self.recharge_ic_card(card = card, preBalance = preBalance, rechargeType = 'append', order = card_recharge_order, need_verify = False) if self.event_data.get('funCode') == '16': cardNo = self.event_data['cardNo'] card = self.update_card_dealer_and_type(cardNo, 'IC') if not card: return group = Group.objects.get(id = self.device['groupId']) newRcd = CardConsumeRecord( openId = card.openId, cardId = str(card.id), money = RMB(self.event_data['money']), devNo = self.device['devNo'], devType = self.device['devType']['name'], logicalCode = self.device['logicalCode'], groupId = str(group.id), address = group.address, groupNumber = self.device['groupNumber'], groupName = group.groupName ) try: newRcd.save() Card.update_balance(card.id, card.balance - self.event_data['money']) except Exception, e: logger.error('save card consume rcd error=%s' % e) elif self.event_data.get('funCode') == '17': cardNo = self.event_data['cardNo'] card = self.update_card_dealer_and_type(cardNo, 'IC') if not card: return if self.event_data.has_key('money'): # 如果有余额,先更新余额 Card.update_balance(card.id, RMB(self.event_data['money'])) elif self.event_data.get('funCode') == '1B': # 在线付款的用完后,需要根据实际消费,退还金币 devNo = self.device['devNo'] sequanceNo = self.event_data['sequanceNo'] devCtrInfo = Device.get_dev_control_cache(devNo) if sequanceNo != devCtrInfo.get('sequanceNo'): logger.info('do finish event sequanceNo is error') return LeftMoney = float(self.event_data['money']) coins = float(devCtrInfo['coins']) backCoins = LeftMoney price = float(devCtrInfo['price']) refundRMB = RMB(price * (backCoins / coins)) logger.debug( 'refund money is: {}; refund rmb is: {}'.format(str(backCoins), str(refundRMB.mongo_amount))) extra = [] consumeDict = {} openId = devCtrInfo.get('openId', None) if not openId: logger.warning('open is null. devNo = {}, sequanceNo = {}'.format(self.device.devNo, sequanceNo)) return user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first() group = Group.get_group(self.device['groupId']) if refundRMB == RMB(0) or backCoins > coins or not self.device.is_auto_refund: extra.append({u'消费金额': u'{}(元)'.format(price)}) else: try: if devCtrInfo.get('rechargeRcdId'): self.refund_net_pay(user, devCtrInfo, refundRMB, VirtualCoin(0), consumeDict, True) extra.append({u"消费金额": u"{}(元)".format(RMB(price) - refundRMB)}) extra.append({u"退款金额": u"{}(元)".format(refundRMB)}) elif devCtrInfo.get('vCardId'): vCard = UserVirtualCard.objects.filter(id=devCtrInfo['vCardId']).first() extra.append({u'优惠卡券': u'{}--{}'.format(vCard.cardName, vCard.cardNo)}) extra.append({u"消费金额": u"使用优惠卡券抵扣"}) else: self.refund_net_pay(user, devCtrInfo, RMB(0), VirtualCoin(backCoins), consumeDict, False) extra.append({u"消费金币": u"{}(金币)".format(VirtualCoin(coins-backCoins))}) extra.append({u"退款金币": u"{}(金币)".format(refundRMB)}) except Exception, e: logger.error('feedback coins error=%s' % e) return ServiceProgress.update_progress_and_consume_rcd( self.device['ownerId'], { 'open_id': openId, 'device_imei': self.device['devNo'], 'port': devCtrInfo.get('port', 0), 'isFinished': False }, consumeDict) self.notify_user_service_complete( service_name='使用设备', openid=user.managerialOpenId if user.managerialOpenId else '', port='', address=group.address, reason='当前服务已完成,谢谢您的使用,祝您生活愉快!!', finished_time=to_datetime(self.recvTime).strftime('%Y-%m-%d %H:%M:%S'), extra=extra) Device.invalid_device_control_cache(self.device['devNo']) class LSHBFaultEvent(FaultEvent): def do(self, **args): cmd = self.event_data.pop('cmd', None) if self.event_data['funCode'] != '01' or not cmd: return if cmd == '01' or cmd == '02': # 缺液或者缺货 Device.update_dev_control_cache(self.device['devNo'], self.event_data) group = Group.get_group(self.device["groupId"]) faultContent = self.event_data.get("statusInfo") if self.is_notify_dealer: self.notify_dealer( templateName="device_fault", title=u'注意!您的设备发生告警!', device=u'{}-{}'.format(self.device.devTypeName, self.device.logicalCode), fault=faultContent, location=u'{address}-{groupName}-{groupNumber}号设备({logicalCode})'.format(address=group["address"], groupName=group[ "groupName"], groupNumber=self.device[ "groupNumber"], logicalCode=self.device[ "logicalCode"]), notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) self.record( faultCode=self.event_data.get("FaultCode"), description=faultContent, title="注意!您的设备发生告警!", ) logger.info('devNo=<{}> Report failure!!'.format(self.device.devNo)) elif cmd == '04': # 上报工作中 Device.update_dev_control_cache(self.device['devNo'], self.event_data) elif cmd == '00': # 消除故障 ctrInfo = Device.get_dev_control_cache(self.device['devNo']) ctrInfo.update({'status': self.event_data.get('status')}) ctrInfo.pop('funCode', None) ctrInfo.pop('statusInfo', None) Device.update_dev_control_cache(self.device['devNo'], ctrInfo) logger.info('devNo=<{}> Fault removal!!'.format(self.device.devNo)) class LSHBonlineCardEvent(WorkEvent): def do(self, **args): if self.event_data.get('funCode') == '19': # 在线卡请求余额 cardNo = self.event_data.get('cardNo', None) cardNoHex = self.event_data.get('cardNoHex', None) occupyData = self.event_data.get('occupyData') card = self.update_card_dealer_and_type(cardNo) if not card: logger.info('no bind card!! cardNo=<{}>'.format(cardNo)) balance = 0 else: #: 首先检查订单,并进行充值 #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来 card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id)) if card_recharge_order: result = self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order) card.reload() if card.frozen: balance = 0 else: balance = card.balance self.deviceAdapter.response_card_money(cardNoHex, balance, occupyData) elif self.event_data.get('funCode') == '20': # 在线卡请求更新卡余额 cardNo = self.event_data.get('cardNo', None) cardNoHex = self.event_data.get('cardNoHex', None) occupyData = self.event_data.get('occupyData', None) card = self.update_card_dealer_and_type(cardNo) if not card: return else: card_left = RMB(card.balance) cardBalance = RMB(self.event_data.get('cardBalance', 0)) if cardBalance >= card_left: # 处理充值的情况 oper_money = cardBalance - card_left # 建立卡充值订单 openId = card.cardNo cardId = card.id money = RMB(0) coins = RMB(oper_money) group = Group.get_group(self.device["groupId"]) rechangeOrder = None cardRechangeOrder = CardRechargeOrder.new_one(openId, cardId, cardNo, money, coins, group, rechangeOrder, rechargeType="rewrite") cardRechangeOrder.update(remarks="经销商线下复写卡金额", status='finished') # 更新卡余额 card.update(balance=cardBalance) # 充值必然是结算 if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB_NOTIFY: extra = [] cacheInfo = Device.get_dev_control_cache(self.device.devNo) orderNo = cacheInfo.get('orderNo') order = ConsumeRecord.objects.get(orderNo=orderNo) # type:ConsumeRecord oldBalance = RMB(cacheInfo.get('oldBalance')) actualRefund = cardBalance - oldBalance spendMoney = order.money usedMoney = spendMoney - actualRefund newCard = self.update_card_dealer_and_type(cardNo) extra.append({"实体卡": u"{}--No:{}".format(card.cardName or card.nickName, card.cardNo)}) extra.append({"使用金额": u"{} 元".format(usedMoney)}) extra.append({"卡余额": u"{} 元".format(RMB(newCard.balance))}) self.notify_user_service_complete( service_name='', openid=card.managerialOpenId, port=None, address=group['address'], reason=None, finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), extra=extra ) # 结束 logger.info( 'devNo=<{}> cardNo=<{}> offline_recharge=<{}> last_balance=<{}> now_balance=<{}>'.format( self.device.devNo, cardNo, oper_money, card_left, cardBalance)) elif cardBalance < card_left: # 处理扣费的情况 # 如果是扣费,必然是刷卡启动 if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB_NOTIFY: self.notify_user( managerialOpenId=card.managerialOpenId, templateName="service_start", title=u'亲,您绑定的卡:%s(名称:%s),正在%s启动服务。\\n' % (card.cardNo,card.cardName,self.device.group.address), service=u"卡内余额{}元".format(card_left), time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), remark="" ) oper_money = card_left - cardBalance servicedInfo = { DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: oper_money.mongo_amount, 'cardNo': cardNo, 'cardBalance': cardBalance.mongo_amount } # 建立卡消费订单 orderNo, cardOrderNo = self.record_consume_for_card(card, oper_money, servicedInfo=servicedInfo) # 更新卡余额 card.update(balance=cardBalance) Device.update_dev_control_cache(self.device.devNo,{'orderNo':orderNo,'oldBalance':cardBalance}) # 结束 logger.info( 'devNo=<{}> cardNo=<{}> consume_balance=<{}> last_balance=<{}> now_balance=<{}>'.format( self.device.devNo, cardNo, oper_money, card_left, cardBalance)) pass else: # 不处理 logger.info('cardNo=<{}> no change return !!!') self.deviceAdapter.response_card_change_sucess(cardNoHex, cardBalance, occupyData)