12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- import time
- from decimal import Decimal
- from mongoengine import DoesNotExist
- 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.agent.models import Agent
- from apps.web.api.models import APIStartDeviceRecord
- from apps.web.api.ykt_north.models import YiKaTongCard
- from apps.web.common.models import TempValues
- from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND
- from apps.web.core.device_define.jndz import CMD_CODE, SWIPE_CARD_PARAM_OP, SWIPE_CARD_RES, RESULT_CODE, CARD_TYPE, \
- CARD_DEDUCTTYPE,CARD_REFUNDTYPE
- from apps.web.core.exceptions import ServiceException
- from apps.web.dealer.models import Dealer
- from apps.web.device.models import Group, Device, DeviceDict
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import FaultEvent, WorkEvent
- from apps.web.eventer.errors import InvalidOption, NoCommandHandlerAvailable, RequestInvalid
- from apps.web.south_intf.platform import notify_event_to_north, notify_event_to_north_v2
- from apps.web.south_intf.zhejiang_fire import send_event_to_zhejiang
- from apps.web.south_intf.zhongtian import report_zhongtian_service_complete, report_zhongtian_refund
- from apps.web.user.models import ServiceProgress, CardRechargeOrder, MyUser, \
- UserVirtualCard, Card, ConsumeRecord, VCardConsumeRecord, Redpack
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- event_data = self.deviceAdapter.analyze_event_data(device_event)
- if event_data is None or 'cmdCode' not in event_data:
- return None
- if event_data['cmdCode'] in [
- CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06,
- CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16
- ]:
- return ChargingJNDZWorkEvent(self.deviceAdapter, event_data)
- if event_data['cmdCode'] == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20:
- # 如果支持一卡通,走一卡通的流程
- if self.device.support_dev_type_features('support_wvtiykt'):
- return JNDZYKTCardChargeEvent(self.deviceAdapter, event_data)
- else:
- return ChargingJNDZWorkEvent(self.deviceAdapter, event_data)
- if event_data['cmdCode'] in [
- # todo 0A的告警不要了,先注释掉,后续删除
- # CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A,
- CMD_CODE.DEVICE_FAULT_TEMPERATURE,
- CMD_CODE.DEVICE_FAULT_POWER,
- CMD_CODE.DEVICE_FAULT_SMOKE,
- CMD_CODE.DEVICE_ELEC,
- CMD_CODE.DEVICE_FAULT_ALTER
- ]:
- return JNDZEventerFailure(self.deviceAdapter, event_data)
- # 只有和动的新的刷卡流程才支持此指令
- if event_data['cmdCode'] in [CMD_CODE.DEVICE_CARD_CHARGE_2D]:
- if self.device.support_dev_type_features('support_wvtiykt'):
- return JNDZYKTCardChargeEvent(self.deviceAdapter, event_data)
- else:
- return JNDZNewCardChargeEvent(self.deviceAdapter, event_data)
- # 对于0x10指令 新旧的处理流程是完全不一样的
- if event_data['cmdCode'] in [CMD_CODE.SWIPE_CARD_10]:
- if self.deviceAdapter.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_HD:
- return JNDZNewCardChargeEvent(self.deviceAdapter, event_data)
- elif self.deviceAdapter.device.driverCode == Const.DEVICE_TYPE_CODE_CHARGE_DOUBLE_SERIAL_JH:
- return JNDZDoubleSerialCardChargeEvent(self.deviceAdapter, event_data)
- elif self.device.support_dev_type_features('support_wvtiykt'):
- return JNDZYKTCardChargeEvent(self.deviceAdapter, event_data)
- else:
- return ChargingJNDZWorkEvent(self.deviceAdapter, event_data)
- if event_data['cmdCode'] in [CMD_CODE.DEVICE_REAL_TIME_REPORT_21]:
- return ChargingJNDZReportEvent(self.deviceAdapter, event_data)
- if event_data['cmdCode'] in [CMD_CODE.SWIPE_CARD_50,CMD_CODE.SWIPE_CARD_52,CMD_CODE.SWIPE_CARD_56]:
- return JNDZVirtualCardWorkEvent(self.deviceAdapter, event_data)
- class JNDZEventerFailure(FaultEvent):
- def do(self, **args):
- cmdCode = self.event_data.get("cmdCode")
- faultType = self.event_data.get(u"fault")
- desc = self.event_data.get("desc", "")
- # todo 0A的告警不要了,先注释掉,后续删除
- # 保证原有的故障处理逻辑不变
- # if cmdCode == CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A:
- # return self.handler_0A_fault()
- # 这些都是整机告警
- part = "0"
- warningData = {
- "warningStatus": 2,
- "warningDesc": desc,
- "warningTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- }
- Device.update_dev_warning_cache(self.device.devNo, {part: warningData})
- group = Group.get_group(self.device.groupId)
- titleList = [
- {u"告警名称": faultType},
- {u"地址名称": group["groupName"]}
- ]
- title = make_title_from_dict(titleList)
- # 接下来的都是整机告警,这个地方需要通知到经销商
- self.notify_dealer(
- "device_fault",
- title=title,
- device=u"{}号设备".format(self.device.logicalCode),
- fault=faultType,
- notifyTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- location=u"{}".format(group["groupName"])
- )
- # 记录错误故障
- fault_record = self.record(
- faultCode=cmdCode,
- description=desc,
- title=faultType,
- detail={"faultType": faultType, "errorCode": self.event_data.get("errorCode")}
- )
- self.north_to_liangxi(fault_record)
- # todo 0A的告警不要了,先注释掉,后续删除
- # def handler_0A_fault(self):
- # faultContent = self.event_data.get('faultContent', '')
- # level = self.event_data.get('level', '')
- # errCode = self.event_data.get('errCode')
- #
- # port = self.event_data.get('port')
- # if port and port != 255:
- # title = u'注意!您的设备{}号端口发出告警!'.format(port)
- # part = str(port)
- # else:
- # title = u'注意!您的设备发出告警!'
- # part = "0"
- #
- # if errCode in ['A3']: # 空载 无需显示在经销商后台
- # return
- #
- # elif errCode in ['00']: # 老设备上报继电器粘连 100206 不上报!!
- # return
- #
- # # 设备告警打入缓存
- # elif errCode in ['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'AA']:
- # warningData = {
- # "warningStatus": 2,
- # "warningDesc": faultContent,
- # "warningTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- # }
- # Device.update_dev_warning_cache(self.device.devNo, {part: warningData})
- #
- # # 设备告警清除
- # elif errCode in ['20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2A']: # 恢复信号 不操作
- # Device.clear_part_warning_cache(self.device.devNo, part)
- # # ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- # # if 'statusInfo' in ctrInfo and 'errCode' in ctrInfo:
- # # if ctrInfo['errCode'][-1] == errCode[-1]:
- # # ctrInfo['status'] = None
- # # ctrInfo['errCode'] = None
- # # ctrInfo['faultContent'] = None
- # # ctrInfo['level'] = None
- # # ctrInfo['statusInfo'] = None
- # # ctrInfo['cmdCode'] = None
- # # Device.update_dev_control_cache(self.device['devNo'], ctrInfo)
- #
- # else:
- # pass
- # # Device.update_dev_control_cache(self.device['devNo'], self.event_data)
- #
- # # 记录错误故障
- # self.record(
- # title=title,
- # description=faultContent,
- # level=level
- # )
- #
- # group = Group.get_group(self.device.groupId)
- #
- # if self.is_notify_dealer:
- # self.notify_dealer(
- # templateName="device_fault",
- # title=title,
- # device=u'{}-{}'.format(self.device.devTypeName, self.device.logicalCode),
- # fault=faultContent,
- # location=u'{}-{}-{}号设备({})'.format(group["address"], group["groupName"], self.device["groupNumber"],
- # self.device["logicalCode"]),
- # notifyTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- # )
- def is_server_refund(billingType, dev, dealer, agent):
- # type:(str, DeviceDict, Dealer, Agent)->bool
- if billingType != 'time':
- if "jhCardElecRefund" in dealer.features:
- return False
- if dev.is_auto_refund:
- return True
- else:
- return False
- else:
- if 'huopo_card_time_refund' in agent.features:
- return True
- else:
- support_server_refund = dev.devType.get('features', {}).get(
- 'support_server_refund', False)
- if not support_server_refund:
- return False
- if dev.is_auto_refund:
- return True
- else:
- return False
- swipe_card_cache_key = lambda devNo: "swipe_card_{}".format(devNo)
- class ChargingJNDZWorkEvent(WorkEvent):
- def support_playback(self):
- return self.event_data['cmdCode'] in [
- CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06,
- CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16
- ]
- def __get_swipe_card_cache(self):
- return TempValues.get(swipe_card_cache_key(self.device.devNo))
- def __set_swipe_card_cache(self, cache_info):
- logger.debug('swipe cache info is: {}'.format(cache_info))
- return TempValues.set(swipe_card_cache_key(self.device.devNo), cache_info, 900)
- def __can_used_virtual_card(self, card, package):
- dealer = self.device.owner
- agent = Agent.objects.get(id=dealer.agentId)
- features = agent.features
- billingType = self.device.my_obj.otherConf.get('billingType', 'time')
- if not is_server_refund(billingType, self.device, self.device.owner, agent):
- return False, None
- else:
- if "vCardNeedBind" in features:
- virtual_card = card.bound_virtual_card
- else:
- virtual_card = card.related_virtual_card
- if not virtual_card:
- return False, None
- if virtual_card.can_use_today(package):
- return True, virtual_card
- else:
- return False, virtual_card
- def __do_new_card_proc_10(self):
- """
- 刷卡扣费的 新流程 预扣费 实际只是检查扣费 并没有真正的扣除
- :return:
- """
- cardNo = self.event_data['cardNo']
- preFee = RMB(self.event_data['preFee'])
- card = self.update_card_dealer_and_type(cardNo) # type: Card
- if not card:
- return self.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- result = self.recharge_id_card(
- card=card,
- rechargeType='append',
- order=card_recharge_order
- )
- card.reload()
- logger.info('JingNengDianZi cmdNo(10) - cardNo=%s, openId=%s, result=%s, preFee=%s, curinfo=%s' % (
- cardNo, card.openId, result, preFee, self.event_data))
- if card.openId == '' or card.frozen:
- return self.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- once_coins = float(preFee)
- once_time = int(self.device.my_obj.otherConf.get('cardMin', 180))
- # 获取上一次的刷卡缓存
- swipe_cache_info = self.__get_swipe_card_cache()
- # 对比刷卡缓存的卡ID 更新金额
- if swipe_cache_info and swipe_cache_info['cardId'] == str(card.id):
- ts = swipe_cache_info['ts']
- if ts >= (int(time.time()) - 600):
- total_coins = once_coins + swipe_cache_info['coins']
- total_time = once_time + swipe_cache_info['time']
- else:
- total_coins = once_coins
- total_time = once_time
- else:
- total_coins = once_coins
- total_time = once_time
- # 判断当前的支付金额 是否能被虚拟卡支付
- is_enough, virtual_card = self.__can_used_virtual_card(card, {
- 'coins': float(total_coins),
- 'unit': u'分钟',
- 'time': total_time
- })
- if not is_enough:
- if card.balance >= RMB(total_coins):
- is_enough = True
- leftBalance = max(float(card.balance) - total_coins, 0)
- else:
- leftBalance = 0
- if is_enough:
- rv = {
- 'cardId': str(card.id),
- 'coins': total_coins,
- 'ts': int(time.time()),
- 'time': total_time
- }
- self.__set_swipe_card_cache(rv)
- logger.debug(
- '[card deduct]cardNo = {}; coins = {}; total time = {}'.format(
- card.cardNo, total_coins, total_time))
- return self.response_use_card(SWIPE_CARD_RES.SUCCESS_00, leftBalance)
- else:
- return self.response_use_card(SWIPE_CARD_RES.BALANCE_NOT_ENOUGH_01, leftBalance)
- def __do_new_card_proc_20(self):
- """
- 刷卡新流程真正扣费的地方
- :return:
- """
- swipe_cache_info = self.__get_swipe_card_cache()
- if not swipe_cache_info or 'cardId' not in swipe_cache_info:
- logger.warning('not find card id. ignore it.')
- return
- # 这一步暂时 不明白用意
- self.__set_swipe_card_cache({'cardId': swipe_cache_info['cardId'], 'ts': 0})
- card = Card.objects(id=str(swipe_cache_info['cardId'])).first() # type: Card
- if not card:
- logger.warning('card<id={}> is not exist.'.format(str(card.id)))
- return
- port = str(self.event_data['port'])
- package = {
- 'coins': self.event_data['coins'],
- 'unit': u'分钟',
- 'time': self.event_data['needTime'],
- }
- is_enough, virtual_card = self.__can_used_virtual_card(card, package)
- if virtual_card and is_enough:
- # 记录卡消费记录以及消费记录
- orderNo, cardConsumeOrderNo = self.record_consume_for_card(
- card=card,
- money=RMB(0.0),
- attachParas={
- 'chargeIndex': port
- },
- servicedInfo={
- 'needTime': self.event_data['needTime'],
- 'needElec': self.event_data['elec'],
- 'startUart': self.event_data.get('uartData', '')
- })
- vCardConsumeRecord = virtual_card.consume(openId=card.openId, group=self.device.group, dev=self.device,
- package=package, attachParas={}, nickname=card.cardName)
- if not vCardConsumeRecord:
- logger.error('use virtual card to consume failure. id = {}'.format(str(virtual_card.id)))
- return
- # 插入虚拟卡的ID 退费的时候使用
- self.event_data.update({'vCardId': str(virtual_card.id)})
- self.event_data.update({"consumeRcdId": str(vCardConsumeRecord.id)})
- self.notify_balance_has_consume_for_card(card, self.event_data['coins'], desc=u'使用绑定的虚拟卡')
- else:
- orderNo, cardConsumeOrderNo = self.record_consume_for_card(
- card=card,
- money=RMB(self.event_data['coins']),
- attachParas={
- "chargeIndex": port
- },
- servicedInfo={
- 'needTime': self.event_data['needTime'],
- 'needElec': self.event_data['elec'],
- 'startUart': self.event_data.get('uartData', '')
- })
- res, _ = self.consume_money_for_card(
- card=card,
- money=RMB(self.event_data['coins']))
- if res != 1:
- logger.warning("consume error!!!, cardNo is {}".format(card.cardNo))
- return
- self.notify_balance_has_consume_for_card(card, self.event_data['coins']) # 通知微信,已经扣费
- # 注册服务
- ServiceProgress.register_card_service(
- self.device,
- int(port),
- card,
- {
- 'orderNo': orderNo,
- 'money': self.event_data['coins'],
- 'coin': self.event_data['coins'],
- 'needTime': self.event_data['needTime'],
- 'cardOrderNo': cardConsumeOrderNo
- })
- #
- billingType = self.device.get("otherConf", dict()).get('billingType', 'time')
- self.event_data.update({'billingType': billingType})
- self.event_data.update({'cardId': str(card.id)})
- self.event_data.update({'openId': card.openId})
- cInfo = Device.get_dev_control_cache(self.device.devNo)
- lastPortInfo = cInfo.get(str(port), {})
- # 钱需要累计
- lastCoins = lastPortInfo.get('coins', 0.0)
- self.event_data.update({'coins': self.event_data['coins'] + lastCoins})
- # 电量需要累加
- lastNeedElec = lastPortInfo.get('needElec', 0.0)
- self.event_data.update({'needElec': self.event_data['elec'] + lastNeedElec})
- # 时间需要累加
- lastNeedTime = lastPortInfo.get('needTime', 0.0)
- self.event_data.update({'needTime': self.event_data['needTime'] + lastNeedTime})
- self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
- self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
- Device.update_dev_control_cache(self.device['devNo'], {port: self.event_data})
- # self.__set_swipe_card_cache({})
- def __do_fault_record(self):
- """
- TODO 梁溪消防的 紧急处理 后续需要统一这个流程
- :return:
- """
- if self.event_data["reasonCode"] == "03":
- desc = u"设备超功率运行,当前已停止充电"
- title = u"端口功率超限"
- elif self.event_data["reasonCode"] == "0B":
- desc = u"设备或是端口出现问题,当前已停止充电"
- title = u"设备端口故障"
- else:
- return
- from apps.web.device.models import FaultRecord
- faultRecord = FaultRecord(
- logicalCode=self.device.logicalCode,
- imei=self.device.devNo,
- portNo=str(self.event_data["port"]),
- faultCode=self.event_data["reasonCode"],
- title=title,
- description="",
- dealerId=self.device.ownerId,
- groupName=self.device.group.get('groupName', ''),
- address=self.device.group.get('address', ''),
- detail={"faultType": desc, "errorCode": "16{}".format(self.event_data["reasonCode"])}
- ).save()
- from taskmanager.mediator import task_caller
- task_caller(
- 'send_to_xf_falut',
- devNo=self.device.devNo,
- faultId=str(faultRecord.id)
- )
- def do(self, **args):
- devNo = self.device.devNo
- logger.info('JingNengDianZi charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
- cmdCode = self.event_data['cmdCode']
- #: 刷卡消费的,分为扣费和退费两种
- if cmdCode == CMD_CODE.SWIPE_CARD_10:
- # 简易配置 如果配置了新卡流程特性的 并且是扣费的指令的 走新的流程 这个判断的优先级 低于设备的特性
- if self.event_data['oper'] == SWIPE_CARD_PARAM_OP.DECR_00:
- if "support_new_card_proc" in self.dealer.features:
- return self.__do_new_card_proc_10()
- cardNo = self.event_data['cardNo']
- preFee = RMB(self.event_data['preFee'])
- #: 操作符,是充值还是减少 <- (00, 01)
- oper = self.event_data['oper']
- card = self.update_card_dealer_and_type(cardNo)
- #: 经销商限制ID卡, 如果满足直接return
- if not card:
- self.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- return
- self.event_data['openId'] = card.openId
- self.event_data['cardId'] = str(card.id)
- self.event_data['startTime'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- Device.update_dev_control_cache(devNo, self.event_data)
- #: 首先检查订单,并进行充值
- #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- result = self.recharge_id_card(card=card,
- rechargeType='append',
- order=card_recharge_order)
- card.reload()
- logger.info('JingNengDianZi cmdNo(10) - cardNo=%s, openId=%s, result=%s, preFee=%s, curinfo=%s' % (
- cardNo, card.openId, result, preFee, self.event_data))
- # TODO 这个地方为了同时满足劲能电子和霍珀的需求 先使用特性 vCardNeedBind 后续需要统一规则
- try:
- dealer = Dealer.get_dealer(card.dealerId)
- agent = Agent.objects.get(id=dealer.get("agentId"))
- features = agent.features
- except Exception as e:
- features = list()
- if "vCardNeedBind" in features:
- virtual_card = card.bound_virtual_card
- else:
- virtual_card = card.related_virtual_card
- # 如果虚拟卡已经绑定,需要检查下今天是否可用,如果可用,有限使用虚拟卡
- vCardCanUse = False
- package = {'coins': float(preFee), 'unit': u'分钟', 'time': 180}
- if virtual_card is not None and card.openId is not None:
- devObj = Device.objects.get(devNo=devNo)
- cardMin = devObj.otherConf.get('cardMin', None)
- if cardMin is not None:
- package = {'coins': float(preFee), 'unit': u'分钟', 'time': int(cardMin)}
- vCardCanUse = virtual_card.can_use_today(package)
- #: 扣费
- if oper == SWIPE_CARD_PARAM_OP.DECR_00:
- if card.openId == '' or card.frozen:
- res = SWIPE_CARD_RES.INVALID_CARD_02
- leftBalance = RMB(0)
- return self.response_use_card(res, leftBalance)
- # 如果虚拟卡可用,卡的费用不要扣掉,仅仅做记录,但是虚拟卡的额度需要扣掉
- elif vCardCanUse:
- # 记录卡消费记录以及消费记录
- orderNo, cardOrderNo = self.record_consume_for_card(card, money=RMB(0.0), desc=u'使用绑定的虚拟卡')
- group = Group.get_group(self.device['groupId'])
- consumeRcd = virtual_card.consume(openId=card.openId, group=group, dev=self.device,
- package=package,
- attachParas={}, nickname=card.cardName)
- # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
- ServiceProgress.register_card_service(self.device, -1, card,
- {
- 'orderNo': orderNo,
- 'money': self.event_data['preFee'],
- 'coin': self.event_data['preFee'], 'needTime': 0,
- 'cardOrderNo': cardOrderNo,
- 'consumeRcdId': str(consumeRcd.id)
- })
- self.consume_money_for_card(card, money=RMB(0.0))
- if consumeRcd is None: # 如果额度没有扣除成功,就用卡
- pass
- else:
- self.response_use_card(SWIPE_CARD_RES.SUCCESS_00, leftBalance=999)
- # 通知微信,已经扣费
- # self.notify_balance_has_consume_for_card(card, preFee, desc = u'使用绑定的虚拟卡')
- return
- elif result['balance'] < preFee:
- res = SWIPE_CARD_RES.BALANCE_NOT_ENOUGH_01
- leftBalance = result['balance']
- return self.response_use_card(res, leftBalance)
- else:
- # 记录卡消费记录以及消费记录
- orderNo, cardOrderNo = self.record_consume_for_card(card, preFee)
- # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
- ServiceProgress.register_card_service(self.device, -1, card,
- {
- 'orderNo': orderNo,
- 'money': self.event_data['preFee'],
- 'coin': self.event_data['preFee'], 'needTime': 0,
- 'cardOrderNo': cardOrderNo
- })
- res = SWIPE_CARD_RES.SUCCESS_00
- leftBalance = result['balance']
- self.consume_money_for_card(card, preFee)
- leftBalance -= preFee
- self.response_use_card(res, leftBalance)
- # 通知微信,已经扣费
- self.notify_balance_has_consume_for_card(card, preFee)
- # 退费.卡的退费比较特殊:如果需要按照电量进行扣费退费,需要在设备管理后台,设置成按电量方式计费。然后把卡的余额回收关闭掉。
- # 充电结束后,上报事件,然后把钱退到卡里。如果是按照时间计费(霍柏的特殊),完全由设备决定,设备告诉我退费,我就退。针对霍柏
- # 绑定虚拟卡的情况下,按照时间退费,需要直接取消掉余额回收,靠结束事件触发结束
- elif oper == SWIPE_CARD_PARAM_OP.INCR_01:
- if virtual_card:
- logger.debug('virtual card is not do device refund.')
- return
- devObj = Device.objects.get(devNo=self.device['devNo'])
- dealer = self.device.owner
- if not dealer:
- logger.error('dealer is not found, dealerId=%s' % self.device.ownerId)
- return
- agent = Agent.objects(id=dealer.agentId).first()
- if not agent:
- logger.error('agent is not found, agentId=%s' % dealer.agentId)
- return
- res = SWIPE_CARD_RES.SUCCESS_00
- device_refund = False
- billingType = devObj.otherConf.get('billingType', 'time')
- if is_server_refund(billingType, self.device, dealer, agent):
- logger.debug('{} in {} has card refund by server refund.'.format(repr(card), repr(self.device)))
- self.response_use_card(res, card.balance)
- return
- logger.debug('{} card refund by {}.'.format(repr(card), repr(self.device)))
- self.response_use_card(res, card.balance + preFee)
- self.refund_money_for_card(preFee, str(card.id))
- self.notify_user(card.managerialOpenId, 'refund_coins', **{
- 'title': u'退币完成!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
- 'backCount': u'金币:%s' % preFee,
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- else:
- raise InvalidOption('oper has be to 00 or 01, %s was given' % (oper,))
- #: 结束的命令
- elif cmdCode in [CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06, CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16]:
- # 结束的时候故障的上报 如果结束的原因是故障导致的 记录一条故障告警
- if self.event_data.get("reasonCode") in ["03", "0B"]:
- self.__do_fault_record()
- port = str(self.event_data['port'])
- lineInfo = Device.clear_port_control_cache(devNo, port)
- if not lineInfo:
- logger.debug('port<{}> of device<l={}> cache is null.'.format(port, self.device.logicalCode))
- return
- logger.debug('port<{}> of device<l={}> cache is: {}'.format(port, self.device.logicalCode, str(lineInfo)))
- # 红包退费的判断处理
- if 'redpackInfo' in lineInfo:
- for _info in lineInfo['redpackInfo']:
- redpack = Redpack.get_one(_info['redpackId'])
- redpackCoins = VirtualCoin(redpack['redpackCoins'])
- lineInfo['coins'] = float(VirtualCoin(lineInfo['coins']) - redpackCoins)
- redpackMoney = RMB(redpack['redpackMoney'])
- lineInfo['price'] = float(RMB(lineInfo['price']) - redpackMoney)
- logger.debug(
- 'redpack is <{}> redpack money is: {}; redpack coins is: {}'.format(redpack.get('id'),
- str(redpackMoney.amount),
- str(redpackCoins.amount)))
- recvTime = to_datetime(self.recvTime)
- group = Group.get_group(self.device['groupId'])
- dealer = Dealer.objects(id=group['ownerId']).first()
- if not dealer:
- logger.error('dealer is not found, dealerId=%s' % group['ownerId'])
- return
- agent = Agent.objects(id=dealer.agentId).first()
- if not agent:
- logger.error('agent is not found, agentId=%s' % dealer.agentId)
- return
- if 'coins' not in lineInfo:
- logger.debug('port cache has no coins. no order in port {}'.format(port))
- return
- if 'startTime' not in lineInfo:
- logger.debug('startTime is not in lineInfo')
- return
- startTime = to_datetime(lineInfo['startTime'])
- refundProtectionTime = int(self.device.get_other_conf_item('refundProtectionTime', 5))
- if startTime > recvTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
- logger.warning(
- 'finished event of dev<{}> error: start time<{}> is bigger than recv time<{}>'.format(
- self.device.devNo, startTime, recvTime))
- if startTime > (recvTime + refundProtectionTime):
- return
- else:
- recvTime = startTime
- usedTime = int(round(((recvTime - startTime).total_seconds() / 60.0)))
- if usedTime <= 0:
- usedTime = 1
- cardId = lineInfo.get('cardId', '')
- vCardId = lineInfo.get('vCardId', None)
- money = VirtualCoin(lineInfo['coins'])
- backCoins = VirtualCoin(0.0)
- price = RMB(lineInfo.get('price', 0.0))
- refundRMB = RMB('0.0')
- leftTime = self.event_data['leftTime']
- billingType = lineInfo.get('billingType', 'time')
- consumeType = lineInfo.get('consumeType', '')
- minUsedTime = self.device.get_other_conf_item('minUsedTime', 0)
- isTempPackage = lineInfo.get('isTempPackage', False)
- orderPower = self.event_data.get("orderPower")
- needTime = 0
- leftTimeStr = ''
- spendElec = 0.0
- leftElec = self.event_data.get('elec', 0.0)
- needElec = lineInfo.get('needElec', 0.0)
- try:
- #: 刷卡或者万一缓存重启了,出现needElec为空的,作为1000度电吧,就会一定使用设备上报的电量
- if leftElec < needElec:
- spendElec = round(needElec - leftElec, 2)
- backCoins_by_elec = round(leftElec / needElec * float(money), 2)
- else:
- spendElec = 0.0
- backCoins_by_elec = money
- if leftTime == 65535:
- actualNeedTime = 0
- backCoins = money
- refundRMB = price
- usedTime = 0
- spendElec = 0.0
- else:
- actualNeedTime = usedTime + leftTime
- leftTimeStr = leftTime
- if ('alt_tech_refund_mode' in agent.features or 'alt_tech_refund_mode' in dealer.features) and \
- billingType == 'time':
- needTime = lineInfo['needTime']
- # 剩余时间不满 60 按照 0 算, 不满 120 按照 60 算...
- calcleftTime = (int(leftTime) // 60) * 60
- backCoins = money * (float(calcleftTime) / float(actualNeedTime))
- elif billingType == 'time':
- needTime = lineInfo['needTime']
- backCoins = money * (float(leftTime) / float(actualNeedTime))
- if refundProtectionTime < usedTime < minUsedTime: # 最小使用时长判断(不足改时长 按该时常算)
- backCoins = money * (float(actualNeedTime - minUsedTime) / float(actualNeedTime))
- logger.info(
- 'usedTime less then minUsedTime (usedTime<{}> ==> minUsedTime<{}>) devNo=<{}>, port=<{}>, backCoins=<{}>'.format(
- usedTime, minUsedTime, devNo, port, backCoins))
- else:
- needElec, elec = Decimal(lineInfo.get('needElec', 1000)), Decimal(
- str(self.event_data.get('elec')))
- ratio = (needElec - elec) / needElec
- backCoins = VirtualCoin(money.amount - money.amount * ratio)
- if 'jiuheng_double_judgment_of_time_and_elec' in dealer.features:
- backCoins = money * (float(leftTime) / float(actualNeedTime))
- backCoins = VirtualCoin(min(float(backCoins), float(backCoins_by_elec)))
- isRefundProtection = False
- if usedTime <= refundProtectionTime:
- backCoins = money
- isRefundProtection = True
- logger.info(
- 'exec protection refund devNo=<{}>, port=<{}>, backCoins=<{}>'.format(devNo, port, backCoins))
- if backCoins > money:
- backCoins = money
- refundRMB = price * (float(backCoins) / float(money)) if money != VirtualCoin(0) else RMB(0)
- logger.debug(
- 'refund money is: {}; refund rmb is: {}'.format(str(backCoins.amount), str(refundRMB.amount)))
- #: 扫码的方式
- if consumeType == 'server' and (not vCardId):
- logger.info("finished with netPay")
- #: 这里需要考虑API调用的和普通使用场景
- if 'extOrderNo' in lineInfo:
- record = APIStartDeviceRecord.get_api_record(self.device['logicalCode'], lineInfo['extOrderNo'])
- if not record:
- logger.debug('cannot find api start device record')
- return
- if record.postActionTriggered:
- logger.debug('api({}) post action has done.'.format(lineInfo['extOrderNo']))
- return
- # 中天的结束状态匹配
- reasonCode = self.event_data['reasonCode']
- if reasonCode == '0B':
- reasonCode = '03'
- elif reasonCode == '03':
- reasonCode = '04'
- else:
- pass
- # 中天空载需要这样写
- if leftTime == 65535:
- leftTime = lineInfo['needTime']
- report_zhongtian_service_complete(
- event_code='16',
- record=record,
- orderNo=lineInfo['extOrderNo'],
- deviceCode=self.device['logicalCode'],
- groupName=group['groupName'],
- address=group['address'],
- actualNeedTime=lineInfo['needTime'],
- leftTime=leftTime,
- finishedState=reasonCode
- )
- record.update(servicedInfo={'spendElec': str(spendElec), 'backCoins': '0'})
- if self.device.is_auto_refund:
- coins = VirtualCoin(lineInfo['coins'])
- money = RMB(lineInfo['price'])
- backCoins = self.get_backCoins(coins=coins, leftTime=leftTime,
- actualNeedTime=lineInfo['needTime'])
- backMoney = self.get_backMoney(money=money, leftTime=leftTime,
- actualNeedTime=lineInfo['needTime'])
- report_zhongtian_refund(
- eventCode='16',
- record=record,
- orderNo=lineInfo['extOrderNo'],
- deviceCode=self.device['logicalCode'],
- groupName=group['groupName'],
- address=group['address'],
- backMoney=str(backMoney),
- backCoins=str(backCoins),
- actualNeedTime=lineInfo['needTime'],
- leftTime=leftTime,
- finishedState=reasonCode
- )
- record.update(servicedInfo={'spendElec': str(spendElec), 'backCoins': str(backCoins)})
- else:
- if 'openId' not in lineInfo or not lineInfo['openId']:
- logger.warning(
- 'openId not in cache of port<{}> in device<{}>'.format(port, self.device.devNo))
- return
- openId = lineInfo['openId']
- user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
- extra = []
- consumeDict = {
- 'chargeIndex': port,
- 'reason': self.event_data['reason'],
- 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
- 'duration': usedTime,
- 'endUart': self.event_data.get('uartData', ''),
- }
- orderPower and consumeDict.update({"orderPower": orderPower})
- if billingType == 'time':
- leftTimeStr = leftTime if leftTime != 65535 else lineInfo['needTime']
- consumeDict.update(
- {'leftTime': leftTimeStr, 'needTime': u'扫码订购%s分钟' % lineInfo['needTime']})
- consumeDict.update({'elec': spendElec})
- else:
- consumeDict.update({'needElec': lineInfo['needElec']})
- consumeDict.update({'elec': spendElec})
- consumeDict.update({'elecFee': self.calc_elec_fee(spendElec)})
- # 判断是否需要退款 个人感觉目前的退款判断是有问题的 if 与 elif 之间非互斥条件
- # 这个地方 建议抽象出公共方法 ,做分层处理 避免相互之间有矛盾
- # 顺序如下: 经销商全局经营策略 < 地址经营策略 < 小于设备经营策略 < 订单经营策略
- # 也就是说 优先判断经销商总开关(目前没有)然后判断地址组的免费,地址组的免费开关(目前没有) 然后判断设备退费开关,设备特性 ,最后是订单相关(套餐等)
- # 这样的话 业务退款逻辑 大部分就可以放在device 的features里面进行处理
- """
- 伪代码
- if not dealer.support_refund: ---> switch true or false / features.support_refund
- return false
- if not group.support_refund: ---> group.isFree / switch true or false / features.support_refund
- return false
- if not device.support_refund: ---> device.is_auto_refund / device.features.support_refund
- return false
- if not order.support_refund: ---> isTempPackage / refund_production enable / ic or id card
- return false
-
- return true
- """
- need_refund = False
- if not group.get('isFree', False):
- if isTempPackage is True:
- if isRefundProtection is True:
- need_refund = True
- else:
- pass
- elif self.device.is_auto_refund:
- need_refund = True
- elif isRefundProtection is True:
- need_refund = True
- else:
- pass
- else:
- pass
- logger.info("netPay need refund is {}".format(need_refund))
- if not need_refund:
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'open_id': openId, 'device_imei': self.device['devNo'],
- 'port': int(port), 'isFinished': False
- },
- consumeDict
- )
- extra.append({u'消费明细': u'消费{}(金币)'.format(money)})
- else:
- if isTempPackage:
- backCoins = VirtualCoin(0)
- self.refund_net_pay(user, lineInfo, refundRMB, backCoins, consumeDict, True)
- else:
- self.refund_net_pay(user, lineInfo, refundRMB, backCoins, consumeDict,
- ('refundRMB_device_event' in dealer.features))
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'open_id': openId, 'device_imei': self.device['devNo'],
- 'port': int(port), 'isFinished': False
- },
- consumeDict)
- if billingType == 'elec':
- billAsService = self.device.bill_as_service_feature
- billAsServiceSwitch = billAsService.on
- else:
- billAsService = None
- billAsServiceSwitch = False
- if DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS in consumeDict:
- extra.append({u'消费明细': u'消费{}金币,退款{}金币'.format(money - backCoins, backCoins)})
- if billAsServiceSwitch:
- elecExpense, serviceExpense = self.calc_service_fee(
- VirtualCoin(money - backCoins), billAsService.elec_charge,
- billAsService.service_charge)
- extra.append({u'电费': u'{}金币'.format(elecExpense)})
- extra.append({u'服务费': u'{}金币'.format(serviceExpense)})
- elif DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH in consumeDict:
- extra.append({u'消费金额': u'消费{}元,退款{}元'.format(price - refundRMB, refundRMB)})
- if billAsServiceSwitch:
- elecExpense, serviceExpense = self.calc_service_fee(
- RMB(price - refundRMB), billAsService.elec_charge, billAsService.service_charge)
- extra.append({u'电费': u'{}元'.format(elecExpense)})
- extra.append({u'服务费': u'{}元'.format(serviceExpense)})
- self.notify_to_user(self.get_managerialOpenId_by_openId(openId), extra)
- elif consumeType in ['server', 'card'] and vCardId:
- # 使用的是虚拟卡
- logger.info("finished with vCard!")
- try:
- vCard = UserVirtualCard.objects.get(id=vCardId)
- except DoesNotExist:
- logger.info('can not find the vCard id = %s' % vCardId)
- return
- billingType = lineInfo.get('billingType', 'time')
- extra = []
- extra.append({u'虚拟卡券': u'{}--{}'.format(vCard.cardName, vCard.cardNo)})
- if billingType == 'time':
- extra.append({u'消费明细': u'消费{}分钟'.format(usedTime)})
- else:
- extra.append({u'消耗明细': u'消费{}度'.format(spendElec)})
- self.notify_to_user(self.get_managerialOpenId_by_openId(lineInfo["openId"]), extra)
- consumeDict = {
- 'chargeIndex': port,
- 'reason': self.event_data['reason'],
- 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
- 'duration': usedTime,
- }
- orderPower and consumeDict.update({"orderPower": orderPower})
- consumeDict.update({'elec': spendElec})
- if billingType != 'time':
- consumeDict.update({'elec': spendElec})
- consumeDict.update({'elecFee': self.calc_elec_fee(spendElec)})
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {'open_id': lineInfo['openId'], 'device_imei': self.device['devNo'],
- 'port': int(port), 'isFinished': False}, consumeDict
- )
- consumeRcdId = lineInfo.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)
- else:
- vCard.refund_quota(vCardConsumeRcd, usedTime, spendElec, backCoins.mongo_amount)
- elif consumeType == 'card':
- # 刷的实体卡
- logger.info("finished with card")
- if not cardId:
- logger.warning('{} finished with card, but no cardId.'.format(self.device))
- return
- try:
- cardRefundProtectionTime = self.device.get('otherConf', {}).get('cardRefundProtectionTime', 0)
- if cardRefundProtectionTime > 0:
- if usedTime < cardRefundProtectionTime:
- backCoins = money
- logger.info(
- 'exec protection refund devNo=<{}>, port=<{}>, backCoins=<{}>'.format(devNo, port,
- backCoins))
- if backCoins > money:
- backCoins = money
- except Exception as e:
- logger.exception(e)
- card = Card.objects.get(id=cardId)
- virtual_card = card.bound_virtual_card # type: UserVirtualCard
- extra = []
- extra.append({u'实体卡': u'{}--{}'.format(card.cardName, card.cardNo)})
- if billingType == 'time':
- logger.info("billingType is time.")
- consumeDict = {
- 'chargeIndex': port,
- 'leftTime': leftTimeStr,
- 'needTime': u'刷卡订购%s分钟' % needTime if virtual_card is None else u'绑定虚拟卡订购%s分钟' % needTime,
- 'reason': self.event_data['reason'],
- 'duration': usedTime,
- 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
- 'elec': spendElec,
- 'elecFee': self.calc_elec_fee(spendElec),
- 'cardId': cardId,
- 'endUart': self.event_data.get('uartData', '')
- }
- orderPower and consumeDict.update({"orderPower": orderPower})
- try:
- if virtual_card:
- self.refund_virtual_card(backCoins, cardId, consumeDict, lineInfo, spendElec, usedTime,
- virtual_card)
- extra.append({u'虚拟卡券': u'{}--{}'.format(virtual_card.cardName, virtual_card.cardNo)})
- extra.append({u'消费明细': u'消费{}分钟'.format(usedTime)})
- else:
- if self.device.support_dev_type_features('support_wvtiykt'):
- tradeFare = str(int((money - backCoins) * 100))
- extra.append({u'消费明细': u'消费{}金币'.format(money)})
- teradeDate = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
- orderNo = lineInfo.get('orderNo', '')
- if (datetime.datetime.now() - startTime).total_seconds() < 24 * 60 * 60:
- resrult = self.notify_to_ykt_norther(card.cardNo, orderNo, tradeFare, teradeDate)
- if resrult.get("resultCode") != "000000":
- raise RequestInvalid('卡扣费失败,失败编号%s,失败原因%s' % (
- resrult.get("resultCode"), resrult.get("resultMsg")))
- card.balance = RMB(float(str(card.balance)) - int(money - backCoins))
- card.save()
- elif is_server_refund(billingType, self.device, dealer, agent):
- logger.info(
- 'ready to server refund money <{}> for user card <{}> in device<{}>'.format(
- backCoins, str(card.id), self.device.devNo))
- consumeDict.update(
- {DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backCoins.mongo_amount})
- self.refund_money_for_card(backCoins, str(card.id))
- extra.append({u'消费明细': u'消费{}金币,退款{}金币'.format(money - backCoins, backCoins)})
- else:
- extra.append({u'消费明细': u'消费{}金币'.format(money)})
- finally:
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'cardId': cardId,
- 'device_imei': self.device['devNo'],
- 'port': int(port),
- 'isFinished': False
- }, consumeDict)
- else:
- logger.info("billingType is elec")
- consumeDict = {
- 'chargeIndex': port,
- 'leftTime': leftTimeStr,
- 'reason': self.event_data['reason'],
- 'elec': spendElec,
- 'elecFee': self.calc_elec_fee(spendElec),
- 'duration': usedTime,
- 'needElec': lineInfo['needElec'],
- 'cardId': cardId,
- 'endUart': self.event_data.get('uartData', '')
- }
- orderPower and consumeDict.update({"orderPower": orderPower})
- try:
- if virtual_card:
- self.refund_virtual_card(backCoins, cardId, consumeDict, lineInfo, spendElec, usedTime,
- virtual_card)
- extra = [
- {
- u'虚拟卡券': u'{}--{}'.format(virtual_card.cardName, virtual_card.cardNo)
- }, {
- u'消费明细': u'消费{}度'.format(spendElec)
- }
- ]
- elif is_server_refund(billingType, self.device, dealer, agent):
- logger.info(
- 'ready to server refund money <{}> for user card <{}> in device<{}>'.format(
- backCoins,
- str(card.id),
- self.device.devNo))
- self.refund_money_for_card(backCoins, str(card.id))
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backCoins.mongo_amount})
- extra.append({u'消费明细': u'消费{}金币,退款{}金币'.format(money - backCoins, backCoins)})
- billAsServiceByCard = self.device.bill_as_service_feature
- if billAsServiceByCard:
- billAsServiceCardSwitch = billAsServiceByCard.on
- else:
- billAsServiceCardSwitch = False
- if billAsServiceCardSwitch:
- elecExpense, serviceExpense = self.calc_service_fee(
- VirtualCoin(money - backCoins), billAsServiceByCard.elec_charge,
- billAsServiceByCard.service_charge)
- extra.append({u'电费': u'{}金币'.format(elecExpense)})
- extra.append({u'服务费': u'{}金币'.format(serviceExpense)})
- else:
- extra.append({u'消费明细': u'消费{}金币'.format(money)})
- finally:
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {'cardId': cardId, 'device_imei': self.device['devNo'],
- 'port': int(port), 'isFinished': False}, consumeDict
- )
- self.notify_to_user(card.managerialOpenId, extra)
- elif consumeType == 'coin': #: 消费类型为金币,则
- logger.info("finished with coin")
- CoinConsumeRcd = ConsumeRecord.objects.get(
- orderNo=lineInfo['consumeOrderNo']) # type: ConsumeRecord
- CoinConsumeRcd.update_for_end(serviceInfo={
- DEALER_CONSUMPTION_AGG_KIND.ELEC: spendElec,
- DEALER_CONSUMPTION_AGG_KIND.ELECFEE: self.calc_elec_fee(spendElec),
- 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
- 'needTime': u'投币订购%s分钟' % needTime,
- 'reason': self.event_data['reason'],
- 'chargeIndex': str(port),
- DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime
- }, finishedTime=recvTime.strftime('%Y-%m-%d %H:%M:%S'))
- else:
- logger.warning('{} has not invalid consume type<{}>'.format(self.device, consumeType))
- return
- except Exception as e:
- logger.exception('deal with jingneng devNo=%s event e=%s' % (devNo, e))
- finally:
- dataDict = {'backMoney': str(refundRMB.mongo_amount), 'backCoins': str(backCoins.mongo_amount)}
- 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)
- self.event_data.update({'deviceCode': self.device["logicalCode"]})
- self.event_data.update({'spendElec': spendElec})
- notify_event_to_north_v2(self.device["devNo"], self.event_data)
- send_event_to_zhejiang(self.dealer, self.device, self.event_data)
- if self.device.owner.supports("supportBeiJingFengTai"):
- orderNo = lineInfo.get('orderNo')
- from apps.web.south_intf.bj_north.api import post_charging_record_info,delete_port_info,post_charging_meta_info
- post_charging_record_info(orderNo)
- delete_port_info(self.device.devNo,port)
- post_charging_meta_info(self.device.devNo,port)
- #: 启动了端口,主要记录下投币数据
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20:
- consumeType = self.event_data['consumeType']
- # 简易配置 如果配置了新卡流程特性的 并且是扣费的指令的 走新的流程 这个判断的优先级 低于设备的特性
- if consumeType == "card":
- if "support_new_card_proc" in self.device.owner.features:
- return self.__do_new_card_proc_20()
- if consumeType == 'coin':
- service_info = {
- 'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT),
- 'needTime': self.event_data['needTime'],
- 'needElec': self.event_data['elec'],
- 'consumeType': consumeType,
- 'coins': self.event_data['coins']
- }
- consume_order_no = self.record_consume_for_coin(
- money=RMB(self.event_data['coins']), remarks=u'投币或者刷卡消费', servicedInfo=service_info)
- service_info.update({'consumeOrderNo': consume_order_no})
- Device.update_dev_control_cache(self.device.devNo, {str(self.event_data['port']): service_info})
- elif consumeType == 'card':
- port = self.event_data['port']
- consumeDict = {'chargeIndex': port, 'elec': self.event_data['elec'],
- 'money': self.event_data['coins'], 'needTime': u'刷卡订购%s分钟' % self.event_data['needTime']}
- queryDict = {'device_imei': self.device['devNo'],
- 'port': -1, 'isFinished': False,
- 'cardId': {'$ne': ''}, 'start_time': {'$gte': int(time.time()) - 3600}}
- progressDict = {'port': port}
- ServiceProgress.update_progress_and_consume_rcd(ownerId=self.device['ownerId'], queryDict=queryDict,
- consumeDict=consumeDict, updateConsume=True,
- progressDict=progressDict)
- # 找出对应的卡的ID记录到端口内存数据
- queryDict.update(progressDict)
- rcds = ServiceProgress.get_collection().find(queryDict, {'cardId': 1, 'open_id': 1, "consumeOrder": 1},
- sort=[('start_time', -1)])
- if rcds.count() == 0:
- return
- rcd = rcds[0]
- devObj = Device.objects.get(devNo=self.device['devNo'])
- billingType = devObj.otherConf.get('billingType', 'time')
- # 刷卡虚拟卡启动的时候,将consumeRcd 写入到缓存 退费的时候使用
- consumeRcdId = rcd.get("consumeOrder", dict()).get("consumeRcdId")
- if consumeRcdId:
- self.event_data.update({"consumeRcdId": consumeRcdId})
- try:
- vRcd = VCardConsumeRecord.objects(id=consumeRcdId).first()
- self.event_data.update({'vCardId': vRcd.cardId})
- except Exception as e:
- # 防止报错退钱给实体卡, 强制添加vCardId
- self.event_data.update({'vCardId': 'true'})
- self.event_data.update({'billingType': billingType})
- self.event_data.update({'cardId': rcd['cardId']})
- self.event_data.update({'openId': rcd['open_id']})
- cInfo = Device.get_dev_control_cache(devNo)
- lastPortInfo = cInfo.get(str(port), {})
- # 钱需要累计
- lastCoins = lastPortInfo.get('coins', 0.0)
- self.event_data.update({'coins': self.event_data['coins'] + lastCoins})
- # 电量需要累加
- lastNeedElec = lastPortInfo.get('needElec', 0.0)
- self.event_data.update({'needElec': self.event_data['elec'] + lastNeedElec})
- # 时间需要累加
- lastNeedTime = lastPortInfo.get('needTime', 0.0)
- self.event_data.update({'needTime': self.event_data['needTime'] + lastNeedTime})
- self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
- self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
- #: 记录该端口累计需要的时间和钱,cardId
- Device.update_port_control_cache(self.device['devNo'], self.event_data)
- elif consumeType == 'server':
- port = self.event_data['port']
- #: 记录该端口累计需要的时间和钱
- Device.update_port_control_cache(self.device['devNo'], self.event_data)
- consumeDict = {'chargeIndex': self.event_data['port'], 'elec': self.event_data['elec'],
- 'needTime': u'订购%s分钟' % self.event_data['needTime']}
- queryDict = {'device_imei': self.device['devNo'],
- 'port': port, 'isFinished': False,
- 'start_time': {'$gte': int(time.time()) - 3600}}
- progressDict = {'port': self.event_data['port']}
- ServiceProgress.update_progress_and_consume_rcd(ownerId=self.device['ownerId'],
- queryDict=queryDict, consumeDict=consumeDict,
- updateConsume=True, progressDict=progressDict)
- else:
- raise NoCommandHandlerAvailable(
- '[JNDZ]] no command handler for cmd %s, curDevInfo=%s' % (cmdCode, self.event_data))
- def refund_virtual_card(self, backCoins, cardId, consumeDict, lineInfo, spendElec, usedTime, virtual_card):
- logger.debug('server refund for virtual card<{}> in device<{}>'.format(str(virtual_card.id), self.device.devNo))
- consumeRcdId = lineInfo.get('consumeRcdId', None)
- # 不是虚拟卡启动的直接结束掉
- if consumeRcdId:
- # 尝试进行虚拟卡退费
- try:
- vCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRcdId)
- except DoesNotExist, e:
- logger.info('can not find the consume rcd id = %s' % consumeRcdId)
- else:
- virtual_card.refund_quota(vCardConsumeRcd, usedTime, spendElec,
- backCoins.mongo_amount)
- else:
- logger.info('can not find consume rcd id')
- def response_use_card(self, res, leftBalance):
- try:
- self.deviceAdapter.response_use_card(res, leftBalance)
- except ServiceException as e:
- logger.exception(e)
- def _get_virtual_card_by_card(self, card):
- if not card.openId or float(card.balance) != 0:
- return
- try:
- dealer = self.device.owner
- agent = Agent.objects.get(id=dealer.agentId)
- features = agent.features
- except Exception as e:
- features = []
- return card.bound_virtual_card if "vCardNeedBind" in features else card.related_virtual_card
- def _check_virtual_card_can_use_today(self, virtual_card, fee):
- # 如果虚拟卡已经绑定,需要检查下今天是否可用,如果可用,有限使用虚拟卡
- if virtual_card:
- unit = self.device['washConfig'].get('1', {}).get('unit', '分钟')
- if unit == '分钟':
- cardMin = self.device["otherConf"].get('cardMin', 180)
- package = {'coins': float(fee), 'unit': unit, 'time': int(cardMin)}
- elif unit == '度':
- cardMin = self.device["otherConf"].get('cardMin', 180)
- package = {'coins': float(fee), 'unit': unit, 'time': int(cardMin)}
- else:
- return 0
- if virtual_card.can_use_today(package):
- dayKey = datetime.datetime.now().strftime("%Y-%m-%d")
- leftDayQuota = virtual_card.calc_left_day_quota(dayKey)
- left_count = virtual_card.find_match_unit_and_can_use_count(leftDayQuota, package)
- return left_count
- def _check_card_balance_can_use_today(self, card, fee):
- if float(card.balance) >= fee:
- return True
- else:
- return False
- 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
- )
- class JNDZNewCardChargeEvent(WorkEvent):
- """
- 和动主板新的刷卡流程,设备类型不同,同时 协议流程也不相同
- 这个新的流程基本是:
- 1.用户刷卡,查询卡的余额,不进行扣费
- 2.用户按下相应的端口按钮,进行启动设备,设备启动后上报20指令,同时服务器对卡进行扣费,然后回复主板,否则主板会一直报
- """
- def do(self, **args):
- # 上传的失败指令
- devNo = self.device.devNo
- logger.info('JNDZNewCardChargeEvent charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
- cmdCode = self.event_data.get('cmdCode')
- if cmdCode == CMD_CODE.SWIPE_CARD_10:
- self._do_card_balance()
- elif cmdCode == CMD_CODE.DEVICE_CARD_CHARGE_2D:
- self._do_charge_consume()
- else:
- logger.info("undefined JNDZNewCardChargeEvent cmd <{}>".format(cmdCode))
- def _do_card_balance(self):
- """
- 查询卡的余额
- :return:
- """
- cardNo = self.event_data.get("cardNo", "")
- cardCst = self.event_data.get("preFee", 25.6)
- card = self.update_card_dealer_and_type(cardNo)
- if not card or not card.openId or card.frozen:
- return self.deviceAdapter.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- # 是否存在没有到账的余额 进行充值
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- self.recharge_id_card(
- card=card,
- rechargeType='append',
- order=card_recharge_order
- )
- card.reload()
- # 检查卡的余额是否足够
- if RMB(card.balance) >= RMB(cardCst):
- res = SWIPE_CARD_RES.SUCCESS_00
- else:
- res = SWIPE_CARD_RES.BALANCE_NOT_ENOUGH_01
- return self.deviceAdapter.response_use_card(res, card.balance)
- def _do_charge_consume(self):
- if self.event_data.get("result", RESULT_CODE.FAILURE) == RESULT_CODE.FAILURE:
- logger.info("receive failure card charge data <{}>".format(self.event_data.get("sourceData", '')))
- return
- # 回复主板是正常的2D指令
- sessionId = self.event_data.get("sessionId")
- self.deviceAdapter._response_to_2D("{:0>10}".format(sessionId))
- # 判断是否这个 sessionId 是否已经被执行 判断方式是该端口中是否有这个 sessionId
- portStr = self.event_data.get("portStr")
- if not portStr:
- logger.info("receive card charge data <{}> without port !".format(self.event_data.get("sourceData", '')))
- return
- portCache = Device.get_dev_control_cache(self.device.devNo).get(portStr, dict())
- if portCache.get("status", Const.DEV_WORK_STATUS_WORKING) == Const.DEV_WORK_STATUS_WORKING and portCache.get(
- "sessionId") == sessionId:
- logger.info(
- "receive card charge data <{}> has been handle, <{}>!".format(self.event_data.get("sourceData", ''),
- sessionId))
- return
- # 接下来判断上传成功启动的类别 由硬币/卡类型决定
- chargeType = self.event_data.get("chargeType")
- if chargeType == "00":
- self._charge_with_coin()
- elif chargeType == "01":
- self._charge_with_card()
- elif chargeType == "02":
- self._charge_with_remote()
- else:
- logger.info("card recharge type <{}> undefined! <{}>".format(chargeType, self.event_data.get("sourceData")))
- def _charge_with_card(self):
- """
- 充值卡 的充值
- :return:
- """
- cardType = self.event_data.get("cardType")
- if cardType == CARD_TYPE.OFFLINE_CARD:
- self._charge_with_offline_card()
- elif cardType == CARD_TYPE.ONLINE_CARD:
- self._charge_with_online_card()
- elif cardType == CARD_TYPE.MONTHLY_CARD:
- self._charge_with_monthly_card()
- elif cardType == CARD_TYPE.FULL_CARD:
- self._charge_with_full_card()
- else:
- logger.info(
- "card recharge card type <{}> undefined! <{}>".format(cardType, self.event_data.get("sourceData")))
- def _charge_with_coin(self):
- """
- 投币的上报
- :return:
- """
- pass
- def _charge_with_remote(self):
- logger.info("not supper charge type! {}".format(self.event_data))
- def _charge_with_online_card(self):
- """
- 在线卡启动充值
- :return:
- """
- portStr = self.event_data.get("portStr")
- needElec = self.event_data.get("elec", 0)
- cardNo = self.event_data.get("cardNo")
- cardCst = self.event_data.get("cardCst")
- card = self.update_card_dealer_and_type(cardNo)
- if not card or not card.openId or card.frozen:
- logger.warning("error card, cardNo is {}".format(cardNo))
- return
- res, cardBalance = self.consume_money_for_card(card, RMB(cardCst))
- if res != 1:
- logger.warning("consume error!!!, cardNo is {}".format(cardNo))
- return
- consumeDict = {
- "chargeIndex": portStr,
- "needElec": needElec
- }
- orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(cardCst), servicedInfo=consumeDict)
- portCache = {
- "isStart": True,
- "status": Const.DEV_WORK_STATUS_WORKING,
- "openId": card.openId,
- "price": cardCst,
- "coins": cardCst,
- "needElec": needElec,
- "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- "startTimeStamp": int(time.time()),
- "consumeType": "card",
- }
- Device.update_dev_control_cache(self.device.devNo, {portStr: portCache})
- ServiceProgress.register_card_service(
- self.device,
- int(portStr),
- card,
- consumeOrder={
- "orderNo": orderNo,
- "cardOrderNo": cardOrderNo,
- }
- )
- def _charge_with_offline_card(self):
- """
- 离线卡启动充值
- :return:
- """
- pass
- def _charge_with_monthly_card(self):
- """
- 包月在线卡启动
- :return:
- """
- logger.info("not supper card charge type! {}".format(self.event_data))
- def _charge_with_full_card(self):
- """
- 充满自停卡
- :return:
- """
- logger.info("not supper card charge type! {}".format(self.event_data))
- class JNDZDoubleSerialCardChargeEvent(ChargingJNDZWorkEvent):
- def response_use_card(self, res, leftBalance):
- sourceData = self.event_data.get("sourceData", "")
- # 与模块驱动约定 最后两个字节为uart_id
- uartId = sourceData[-2:]
- # 发送指令使用221 主要考虑的是帧头的问题
- self.deviceAdapter.response_use_card(res, leftBalance, uartId)
- class ChargingJNDZReportEvent(WorkEvent):
- def do(self, **args):
- if self.device.owner.supports("supportBeiJingFengTai"):
- from apps.web.south_intf.bj_north.api import get_update_port_num
- get_update_port_num(self.device.devNo)
- class JNDZVirtualCardWorkEvent(WorkEvent):
- """
- 处理新增的在线卡和虚拟卡指令
- """
- def _do_52(self):
- # 回复ak
- ackId = self.event_data['ack_id']
- self.deviceAdapter.response_ak_5X(ackId)
- # 解析参数
- cardNo = self.event_data['cardNo']
- coins = self.event_data['coins']
- needTime = self.event_data['needTime']
- port = self.event_data['port']
- deductType = self.event_data['deductType']
- # 组装package
- package = {
- 'coins': coins,
- 'unit': u'分钟',
- 'time': needTime,
- }
- # 找卡 虚拟卡
- card = self.update_card_dealer_and_type(cardNo) # type: Card
- virtual_card = card.bound_virtual_card # type: UserVirtualCard
- # 非使用虚拟卡的逻辑
- if deductType == CARD_DEDUCTTYPE.DEDUCT_BALANCE:
- # 不需要组装package 直接card 扣除balance
- orderNo, cardConsumeOrderNo = self.record_consume_for_card(
- card=card,
- money=RMB(coins),
- attachParas={
- "chargeIndex": port
- },
- servicedInfo={
- 'needTime': needTime
- })
- res, _ = self.consume_money_for_card(
- card=card,
- money=RMB(coins))
- # 记录开始充电时间
- self.event_data.update({'startTime': time.time()})
- if res != 1:
- logger.warning("consume error!!!, cardNo is {}".format(card.cardNo))
- return
- elif deductType == CARD_DEDUCTTYPE.DEDUCT_TIME:
- # 使用虚拟卡的逻辑
- # 建立订单
- orderNo, cardConsumeOrderNo = self.record_consume_for_card(
- card=card,
- money=RMB(0.0),
- attachParas={
- 'chargeIndex': port
- },
- servicedInfo={
- 'needTime': needTime
- })
- # 进行扣费
- vCardConsumeRecord = virtual_card.consume(openId=card.openId, group=self.device.group, dev=self.device,
- package=package, attachParas={}, nickname=card.cardName)
- # 记录开始充电时间
- self.event_data.update({'startTime': time.time()})
- if not vCardConsumeRecord:
- logger.error('use virtual card to consume failure. id = {}'.format(str(virtual_card.id)))
- return
- # 记录开始充电时间
- self.event_data.update({'startTime':time.time()})
- # 插入虚拟卡的ID 退费的时候使用
- self.event_data.update({'vCardId': str(virtual_card.id)})
- self.event_data.update({"consumeRcdId": str(vCardConsumeRecord.id)})
- # 建立sp 建立缓存
- # 注册服务
- ServiceProgress.register_card_service(
- self.device,
- int(port),
- card,
- {
- 'orderNo': orderNo,
- 'money': coins,
- 'coin': coins,
- 'needTime': needTime,
- 'cardOrderNo': cardConsumeOrderNo
- })
- billingType = self.device.get("otherConf", dict()).get('billingType', 'time')
- self.event_data.update({'billingType': billingType})
- self.event_data.update({'cardId': str(card.id)})
- self.event_data.update({'openId': card.openId})
- Device.update_port_control_cache(self.device['devNo'],self.event_data)
- # 通知用户卡启动
- self.notify_user(card.managerialOpenId,'start_device', **{
- 'title': u'启动成功!您的卡号是%s,卡别名:%s' % (card.cardNo, card.nickName),
- 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- self.deviceAdapter.response_use_card_52(cardNo)
- def do(self, **args):
- devNo = self.device.devNo
- logger.info('JingNengDianZi charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
- cmdCode = self.event_data['cmdCode']
- if cmdCode == CMD_CODE.SWIPE_CARD_50:
- cardNo = self.event_data['cardNo']
- card = self.update_card_dealer_and_type(cardNo)
- virtual_card = card.bound_virtual_card
- if card == None:
- status = '00'
- balance = '0000'
- leftDayQuota = '0000'
- self.deviceAdapter.response_balance_inquiry_50(balance, leftDayQuota, cardNo, status)
- return
- if virtual_card:
- dayKey = datetime.datetime.now()
- leftDayQuota = None
- leftDayQuotaList = virtual_card.calc_left_day_quota(dayKey.strftime("%Y-%m-%d"))
- for leftDayQuotaDict in leftDayQuotaList:
- if leftDayQuotaDict['unit'] == u'分钟':
- leftDayQuota = leftDayQuotaDict['count']
- if leftDayQuota > 0:
- status = '01'
- else:
- leftTotalQuotaList = virtual_card.calc_left_total_quota()
- for leftTotalQuotaDict in leftTotalQuotaList:
- if leftTotalQuotaDict['unit'] == u'分钟':
- leftTotalQuota = leftTotalQuotaDict['count']
- if leftTotalQuota > 0:
- status = '04'
- else:
- status = '05'
- if leftDayQuota == None:
- logger.debug('leftDayQuota not have unit 分钟')
- status = '00'
- balance = '0000'
- leftDayQuota = '0000'
- power = virtual_card.power
- self.deviceAdapter.response_balance_inquiry_50(balance, leftDayQuota, cardNo, status,power)
- return
- if dayKey > virtual_card.expiredTime:
- status = '06'
- elif virtual_card.status == 'freeze':
- status = '03'
- power = virtual_card.power
- self.deviceAdapter.response_balance_inquiry_50('0000', leftDayQuota, cardNo, status,power)
- else:
- if int(card.balance) > 0:
- status = '02'
- else:
- status = '07'
- if card.status == 'freeze':
- status = '03'
- power = '0000'
- self.deviceAdapter.response_balance_inquiry_50(max(float(card.balance),0), '0000', cardNo, status,power)
- elif cmdCode == CMD_CODE.SWIPE_CARD_52:
- self._do_52()
- elif cmdCode == CMD_CODE.SWIPE_CARD_56:
- # 回复ak
- ackId = self.event_data['ack_id']
- self.deviceAdapter.response_ak_5X(ackId)
- if self.event_data.get("reasonCode") in ["03", "0B"]:
- self.__do_fault_record()
- # 解析参数
- port = self.event_data['port']
- leftTime = self.event_data['usedTime']
- leftElec = self.event_data['usedElec']
- refundMoney = RMB(self.event_data['refundMoney']) * 0.1
- refundTime = self.event_data['refundTime']
- refundType = self.event_data['refundType']
- # 找到缓存
- lineInfo = Device.get_port_control_cache(devNo, port)
- # 找到卡
- cardId = lineInfo.get('cardId', '')
- if not cardId:
- logger.error('cardId is not found')
- return
- card = Card.objects.get(id=cardId)
- virtualCard = card.related_virtual_card
- money = RMB(lineInfo['coins'])
- logger.debug('port<{}> cache is: {}'.format(port, str(lineInfo)))
- group = Group.get_group(self.device['groupId'])
- dealer = Dealer.objects(id=group['ownerId']).first()
- if not dealer:
- logger.error('dealer is not found, dealerId=%s' % group['ownerId'])
- return
- agent = Agent.objects(id=dealer.agentId).first()
- if not agent:
- logger.error('agent is not found, agentId=%s' % dealer.agentId)
- return
- if 'coins' not in lineInfo:
- logger.debug('port cache has no coins. no order in port {}'.format(port))
- return
- extra = []
- consumeDict = {
- 'chargeIndex': port,
- 'leftTime': leftTime,
- 'leftElec': leftElec,
- 'reason': self.event_data['reason'],
- }
- if self.device.is_auto_refund:
- # 非使用虚拟卡的逻辑
- if refundType == CARD_REFUNDTYPE.REFUND_BALANCE:
- self.refund_money_for_card(refundMoney, str(card.id))
- usedTime = int((time.time() - int(lineInfo['startTime'])) / 60)
- consumeDict.update({"usedTime":usedTime})
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: refundMoney.mongo_amount})
- extra.append({u'消费明细': u'消费{}金币,退款{}金币'.format(money - refundMoney, refundMoney)})
- # 使用虚拟卡的逻辑
- elif refundType == CARD_REFUNDTYPE.REFUND_TIME:
- vCardId = lineInfo['vCardId']
- spendElec = 0
- consumeRcdId = lineInfo.get('consumeRcdId', None)
- if consumeRcdId is None:
- logger.info('can not find consume rcd id')
- return
- usedTime = int(lineInfo['needTime']) - int(refundTime)
- consumeDict.update({'usedTime':usedTime})
- extra.append({u'虚拟卡券': u'{}--{}'.format(virtualCard.cardName, virtualCard.cardNo)})
- extra.append({u'消费明细': u'消费{}分钟'.format(usedTime)})
- try:
- virtualCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRcdId)
- vCard = UserVirtualCard.objects.get(id=vCardId)
- except DoesNotExist, e:
- logger.info('can not find the consume rcd id = %s' % consumeRcdId)
- else:
- vCard.refund_quota(virtualCardConsumeRcd, usedTime, spendElec, RMB(refundMoney).mongo_amount)
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {'open_id': lineInfo['openId'], 'device_imei': self.device['devNo'],
- 'port': int(port), 'isFinished': False}, consumeDict
- )
- self.notify_user(self.get_managerialOpenId_by_openId(lineInfo["openId"]), extra)
- self.deviceAdapter.respone_use_card_finished_56(card.cardNo)
- if self.device.owner.supports("supportBeiJingFengTai"):
- orderNo = lineInfo.get('orderNo')
- from apps.web.south_intf.bj_north import post_charging_record_info
- post_charging_record_info(orderNo)
- Device.clear_port_control_cache(self.device.devNo, port)
- class JNDZYKTCardChargeEvent(WorkEvent):
- def __get_swipe_card_cache(self):
- return TempValues.get(swipe_card_cache_key(self.device.devNo))
- def __set_swipe_card_cache(self, cache_info):
- logger.debug('swipe cache info is: {}'.format(cache_info))
- return TempValues.set(swipe_card_cache_key(self.device.devNo), cache_info, 900)
- def do(self, **args):
- devNo = self.device.devNo
- logger.info('JNDZNewCardChargeEvent charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
- cmdCode = self.event_data.get('cmdCode')
- if cmdCode == CMD_CODE.SWIPE_CARD_10:
- self._do_YKT_card_proc_10()
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20:
- self._do_YKT_card_start_20()
- def _do_YKT_card_proc_10(self):
- cardNo = hex(int(self.event_data['cardNo'])).upper()[2:]
- preFee = RMB(self.event_data['preFee'])
- devNo = self.device.devNo
- cardYKT = self.query_to_ykt_norther(cardNo)
- if cardYKT["code"] != "000000":
- return self.deviceAdapter.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- if cardYKT["cardInfo"].get("custStatus") != 1:
- return self.deviceAdapter.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- # 先把卡信息更新到YiKaTongCard
- cardInfo = cardYKT.get('cardInfo')
- YiKaTongCard.update_card(cardInfo)
- card = self.update_card_dealer_and_type(cardNo)
- if not card:
- pastCardNo = YiKaTongCard.get_cardNo(cardNo)
- card = self.update_card_dealer_and_type(pastCardNo)
- if not card:
- return self.deviceAdapter.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, 0)
- card.cardNo = cardNo
- card.save()
- card.reload()
- balance = cardYKT['cardInfo']['oddFare'] * 0.01
- if balance <= 0:
- return self.deviceAdapter.response_use_card(SWIPE_CARD_RES.BALANCE_NOT_ENOUGH_01, balance)
- card.balance = RMB(balance)
- card.save()
- if card.openId == '' or card.frozen:
- return self.response_use_card(SWIPE_CARD_RES.INVALID_CARD_02, RMB(0))
- # 记录卡消费记录以及消费记录
- orderNo, cardOrderNo = self.record_consume_for_card(card, preFee)
- # 记录当前服务的progress.没有上报端口号,所以先用-1标记,表示端口未知。端口等消费的时候会报上来
- ServiceProgress.register_card_service(self.device, -1, card,
- {
- 'orderNo': orderNo,
- 'money': self.event_data['preFee'],
- 'coin': self.event_data['preFee'], 'needTime': 0,
- 'cardOrderNo': cardOrderNo
- })
- self.consume_money_for_card(card, preFee)
- self.deviceAdapter.response_use_card(SWIPE_CARD_RES.SUCCESS_00, balance)
- self.notify_balance_has_consume_for_card(card, preFee)
- def _do_YKT_card_start_20(self):
- """
- 启动设备
- :return:
- """
- port = self.event_data['port']
- consumeDict = {'chargeIndex': port, 'elec': self.event_data['elec'],
- 'money': self.event_data['coins'], 'needTime': u'刷卡订购%s分钟' % self.event_data['needTime']}
- queryDict = {'device_imei': self.device['devNo'],
- 'port': -1, 'isFinished': False,
- 'cardId': {'$ne': ''}, 'start_time': {'$gte': int(time.time()) - 3600}}
- progressDict = {'port': port}
- ServiceProgress.update_progress_and_consume_rcd(ownerId=self.device['ownerId'], queryDict=queryDict,
- consumeDict=consumeDict, updateConsume=True,
- progressDict=progressDict)
- # 找出对应的卡的ID记录到端口内存数据
- queryDict.update(progressDict)
- rcds = ServiceProgress.get_collection().find(queryDict, {'cardId': 1, 'open_id': 1, "consumeOrder": 1},
- sort=[('start_time', -1)])
- if rcds.count() == 0:
- return
- rcd = rcds[0]
- devObj = Device.objects.get(devNo=self.device['devNo'])
- billingType = devObj.otherConf.get('billingType', 'time')
- # 刷卡虚拟卡启动的时候,将consumeRcd 写入到缓存 退费的时候使用
- consumeRcdId = rcd.get("consumeOrder", dict()).get("consumeRcdId")
- if consumeRcdId:
- self.event_data.update({"consumeRcdId": consumeRcdId})
- try:
- vRcd = VCardConsumeRecord.objects(id=consumeRcdId).first()
- self.event_data.update({'vCardId': vRcd.cardId})
- except Exception as e:
- # 防止报错退钱给实体卡, 强制添加vCardId
- self.event_data.update({'vCardId': 'true'})
- self.event_data.update({'billingType': billingType})
- self.event_data.update({'cardId': rcd['cardId']})
- self.event_data.update({'openId': rcd['open_id']})
- cInfo = Device.get_dev_control_cache(self.device.devNo)
- lastPortInfo = cInfo.get(str(port), {})
- # 钱需要累计
- lastCoins = lastPortInfo.get('coins', 0.0)
- self.event_data.update({'coins': self.event_data['coins'] + lastCoins})
- # 电量需要累加
- lastNeedElec = lastPortInfo.get('needElec', 0.0)
- self.event_data.update({'needElec': self.event_data['elec'] + lastNeedElec})
- # 时间需要累加
- lastNeedTime = lastPortInfo.get('needTime', 0.0)
- self.event_data.update({'needTime': self.event_data['needTime'] + lastNeedTime})
- self.event_data.update({'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
- self.event_data.update({'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING})
- #: 记录该端口累计需要的时间和钱,cardId
- Device.update_port_control_cache(self.device['devNo'], self.event_data)
|