# coding=utf-8 import json import logging import datetime,time from mongoengine import DoesNotExist from apilib.monetary import VirtualCoin,RMB from django.views.decorators.http import require_POST from apilib.utils_datetime import to_datetime from apilib.utils_json import JsonResponse from apps.web.api.jn_north.constant import RESPONSE_CODE from apps.web.api.utils import AES_CBC_PKCS5padding_encrypt, AES_CBC_PKCS5padding_decrypt, generate_json_token, parse_json_token from apps.web.device.models import Group, Device, SwapGroup,Part from apps.web.south_intf.swap_carcharger import SwapContract from apps.web.dealer.models import Dealer from apps.web.agent.models import Agent from apps.web.core.helpers import ActionDeviceBuilder from apps.web.core.utils import async_operation from apps.web.user.models import ConsumeRecord, RechargeRecord,ServiceProgress from apps.web.user.utils import RechargeRecordBuilder logger = logging.getLogger(__name__) def queryToken(request): """ 通过账号密码获取token """ logger.debug("[queryToken] request body = {}".format(request.body)) if not request.body: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误(1001)"}) # 根据路径获取norther swapLabel = request.path.split('/')[3] norther = SwapContract.get_norther_by_label(swapLabel) if not norther: return None, JsonResponse({"Ret": RESPONSE_CODE.ERROR_PARAM, "Msg": u"请求的URL路径错误"}) try: Data = json.loads(request.body).get("Data") data = json.loads(AES_CBC_PKCS5padding_decrypt(Data,norther.dataSecret2Us,norther.dataSecretIV2Us)) except Exception as e: logger.exception(e) return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误(1002)"}) OperatorID = data.get("OperatorID") OperatorSecret = data.get("OperatorSecret") logger.debug("[queryToken] OperatorID = {}, OperatorSecret = {}".format(OperatorID, OperatorSecret)) if not all((OperatorID, OperatorSecret)): return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误(1003)"}) try: norther = SwapContract.objects.filter(operatorId2Us=OperatorID, secret2Us=OperatorSecret).first() # type: SwapContract except DoesNotExist: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误(1004)"}) except Exception as e: return JsonResponse({"Ret": RESPONSE_CODE.SYS_ERROR, "Msg": u"系统错误"}) expire = 60 * 60 * 24 * 7 result = { "OperatorID": norther.OperatorId, "SuccStat": 0, "AccessToken": norther.generate_json_token(data=norther.get_token_data(), expire=expire), "TokenAvailableTime": expire, "FailReason": None } logger.debug("[queryToken] return result = {}".format(result)) # 拉取的时候加密 显式指明加密秘钥为 pull resultData = AES_CBC_PKCS5padding_encrypt( json.dumps(result), dataSecret=norther.dataSecret2Us, dataSecretIV=norther.dataSecretIV2Us ) sig = norther.get_sig(resultData) return JsonResponse({ "Ret": RESPONSE_CODE.SUCCESS, "Msg": u"请求成功", "Data": resultData, "Sig": sig }) def check_and_get_norther(request): token = request.META.get('HTTP_AUTHORIZATION', "").replace("Bearer", "").strip() logger.info('[queryStationsInfo] , token = {}'.format(token)) # 根据路径获取norther swapLabel = request.path.split('/')[3] norther = SwapContract.get_norther_by_label(swapLabel) if not norther: return None, JsonResponse({"Ret": RESPONSE_CODE.ERROR_PARAM, "Msg": u"请求的URL路径错误"}) # 验证身份 tokenData = norther.parse_json_token(token) if not tokenData: return None,JsonResponse({"Ret": RESPONSE_CODE.ERROR_TOKEN, "Msg": u"请求参数错误(1001)"}) # 获取这个平台下面的所有的northers记录 northers = SwapContract.get_norther(**tokenData) if not northers: return None,JsonResponse({"Ret": RESPONSE_CODE.ERROR_PARAM, "Msg": u"请求参数错误(1002)"}) # 准备token所获取的参数信息 if norther.id != northers.first().id: return None,JsonResponse({"Ret": RESPONSE_CODE.ERROR_TOKEN, "Msg": u"根据token获取数据和实际请求路径不一致(1002)"}) return norther, None def get_request_data(request,norther): dataSecret2Us = norther.dataSecret2Us dataSecretIV2Us = norther.dataSecretIV2Us # 验证参数 logger.debug("[queryStationsInfo] request body = {}".format(request.body)) if not request.body: return None,JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误(1003)"}) try: Data = json.loads(request.body).get("Data") data = json.loads(AES_CBC_PKCS5padding_decrypt( Data, dataSecret=dataSecret2Us, dataSecretIV=dataSecretIV2Us )) except Exception as e: logger.exception(e) return None,JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误(1004)"}) return data,None def get_reply_reponse(result,norther): resultData = AES_CBC_PKCS5padding_encrypt( json.dumps(result), dataSecret=norther.dataSecret2Us, dataSecretIV=norther.dataSecretIV2Us ) sig = norther.get_sig(resultData) return JsonResponse({"Ret": 0,"Msg": u"请求成功","Data": resultData,"Sig": sig}) def queryStationsInfo(request): """ 查询充电站的信息 """ logger.info('function into [queryStationsInfo]') norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response # 分页以及查询参数 pageNo = int(data.get('PageNo', 1)) pageSize = int(data.get('PageSize', 10)) lastQueryTime = data.get("LastQueryTime") logger.info('[queryStationsInfo],pageNo=%s,pageSize=%s,lastQueryTime=%s' % (pageNo,pageSize,lastQueryTime)) # 查找出所有符合条件的信息 dealerIds = [] if norther.operatorType == 'dealer': dealerIds = [norther.operatorInnerId] elif norther.operatorType == 'agent': dealerIds = [str(dealer.id) for dealer in Dealer.objects(agentId = norther.operatorInnerId) ] elif norther.operatorType == 'manager': agentIds = [str(agent.id) for agent in Agent.objects(managerId = norther.operatorInnerId)] dealerIds = [str(dealer.id) for dealer in Dealer.objects(agentId__in = agentIds) ] if lastQueryTime: dateTime = to_datetime(lastQueryTime) swaps = SwapGroup.objects.filter(ownerId__in=dealerIds,swapFlag=True,deviceChangedTime__gte = dateTime,deviceNum__gt = 0) else: swaps = SwapGroup.objects.filter(ownerId__in=dealerIds,swapFlag=True,deviceNum__gt = 0) StationInfos = [] for swap in swaps[(pageNo - 1) * pageSize:pageNo * pageSize]: StationInfos.append(norther.get_station(swap)) result = { "PageNo": pageNo, "ItemSize": pageSize, "PageCount": swaps.count(), "StationInfos": StationInfos } logger.debug("[queryStationsInfo] return result = {}".format(result)) return get_reply_reponse(result,norther) def queryStationStatus(request): logger.info('function into [queryStationStatus]') norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response stationIDs = data.get("StationIDs") logger.info('[queryStationStatus],stationIDs=%s' % (','.join(stationIDs))) if not isinstance(stationIDs, list): return JsonResponse({"Ret": 4004, "Msg": u"系统错误"}) StationStatusInfos = [] for stationID in stationIDs: StationStatusInfos.append( { "StationID": stationID, "ConnectorStatusInfos": norther.get_connector_status_infos(stationID) } ) result = { "StationStatusInfos": StationStatusInfos } logger.debug("[queryStationStatus] return result = {}".format(result)) return get_reply_reponse(result, norther) def queryStationStats(request): """ 取每个充电站在某个周期内的统计信息 :param request: :return: """ logger.info('function into [queryStationStats]') norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response stationID = data.get("StationID") startTime = data.get("StartTime") endTime = data.get("EndTime") logger.info('[queryStationStats],stationID=%s,startTime=%s,endTime=%s' % (stationID,startTime,endTime)) startTimeObj = datetime.datetime.strptime(startTime, "%Y-%m-%d") endTimeObj = datetime.datetime.strptime(endTime, "%Y-%m-%d") res = norther.get_station_state(stationID,startTimeObj, endTimeObj) res.update({ "StationID": stationID, "StartTime": startTime, "EndTime": endTime }) result = {"StationStats": res} logger.debug("[queryStationStats] return result = {}".format(result)) return get_reply_reponse(result, norther) def queryEquipAuth(request): logger.info('function into [queryEquipAuth]') norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response EquipAuthSeq = data.get('EquipAuthSeq') ConnectorID = data.get('ConnectorID') logger.info('[queryEquipAuth],EquipAuthSeq=%s,ConnectorID=%s' % (EquipAuthSeq,ConnectorID)) part = Part.objects(id = ConnectorID).first() if not part: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) dev = Device.get_dev_by_l(part.logicalCode) box = ActionDeviceBuilder.create_action_device(dev) FailReason = 0 SuccStat = 0 try: devInfo = box.get_port_status_from_dev() portInfo = devInfo.get(str(part.partNo),{}) if portInfo['isPlugin'] == 'no': FailReason = 1 except Exception,e: FailReason = 2 if FailReason != 0: SuccStat = 1 result = { 'EquipAuthSeq':EquipAuthSeq, 'ConnectorID':ConnectorID, 'SuccStat':SuccStat, 'FailReason':FailReason } logger.debug("[queryEquipAuth] return result = {}".format(result)) return get_reply_reponse(result, norther) def queryEquipBusinessPolicy(request): """ 用于查询运营商的充电设备接口计费模型信息 :param request: :return: """ logger.info('function into [queryEquipBusinessPolicy]') norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response equipBizSeq = data.get("EquipBizSeq") connectorID = data.get("ConnectorID") logger.info('[queryEquipBusinessPolicy],equipBizSeq=%s,connectorID=%s' % (equipBizSeq,connectorID)) part = Part.objects(id = connectorID).first() if not part: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) dev = Device.get_dev_by_l(part.logicalCode) devObj = Device.objects.get(devNo = dev['devNo']) feeMode = devObj.otherConf.get('feeMode',{}) shiduan = feeMode.get('shiduan','000000000000000000000000000000000000000000000000') elecFeeDict = {'0':feeMode.get('jianFee',0),'1':feeMode.get('fengFee',0),'2':feeMode.get('pingFee',0),'3':feeMode.get('guFee',0)} serveFeeDict = {'0':feeMode.get('jianServeFee',0),'1':feeMode.get('fengServeFee',0),'2':feeMode.get('pingServeFee',0),'3':feeMode.get('guServeFee',0)} PolicyInfos = [] for ii in range(48): startHour = 0 + ii/2 startMin = '00' if ii%2==0 else '30' startTime = '%02d%s00' % (startHour,startMin) if (ii == 0) or (ii > 0 and shiduan[ii] != shiduan[ii-1]): PolicyInfos.append({'StartTime':startTime,'ElecPrice':elecFeeDict.get(shiduan[ii]),'SevicePrice':serveFeeDict.get(shiduan[ii])}) result = { "EquipBizSeq": equipBizSeq, "ConnectorID": connectorID, "SuccStat": 0 if PolicyInfos else 1, "FailReason": 0 if PolicyInfos else 1, "SumPeriod": 1, "PolicyInfos": PolicyInfos } logger.debug("[queryEquipBusinessPolicy] return result = {}".format(result)) return get_reply_reponse(result, norther) def query_start_charge(request): logger.info('function into [query_start_charge]' ) norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response StartChargeSeq = data.get("StartChargeSeq") connectorID = data.get("ConnectorID") logger.info('[query_start_charge],StartChargeSeq=%s,connectorID=%s' % (StartChargeSeq,connectorID)) part = Part.objects(id = connectorID).first() if not part: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) dev = Device.get_dev_by_l(part.logicalCode) if not dev: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) group = Group.get_group(dev['groupId']) # 启动设备,这里以能湃的 box = ActionDeviceBuilder.create_action_device(dev) SuccStat,FailReason,orderNo = box.start_device_swap(part.partNo) if SuccStat != 0: result = { "StartChargeSeq": StartChargeSeq, "StartChargeSeqStat": 5, "connectorID": connectorID, "SuccStat": SuccStat, "FailReason": FailReason, } # 异步通知北向 async_operation(norther.notification_start_charge_result,result) logger.debug("[query_start_charge] return result = {}".format(result)) return get_reply_reponse(result, norther) # 新建一条充值订单 rechargeOrder = RechargeRecordBuilder.new_swap_recharge(norther.swapLabel,dev,group,part.partNo,StartChargeSeq,orderNo) # 记录consume rcd newRecord = { 'orderNo': orderNo, 'openId': '', 'nickname': '', 'coin': VirtualCoin(0), 'money': RMB(0), 'devNo': dev['devNo'], 'logicalCode': dev['logicalCode'], 'groupId': dev['groupId'], 'ownerId': dev['ownerId'], 'address': group['address'], 'groupNumber': dev['groupNumber'], 'groupName': group['groupName'], 'devTypeName': dev.devTypeName, 'devTypeCode': dev.devTypeCode, 'startKey': '', 'isNormal': True, 'errorDesc': '', 'sequanceNo': orderNo, 'status': ConsumeRecord.Status.CREATED, 'package': {}, 'remarks':u'互联互通', 'rechargeRcdId':str(rechargeOrder.id) } consumeOrder = ConsumeRecord(**newRecord) consumeOrder.save() # type: ConsumeRecord result = { "StartChargeSeq": StartChargeSeq, "StartChargeSeqStat": 2, "connectorID": connectorID, "SuccStat": SuccStat, "FailReason": FailReason, } new_service_progress = ServiceProgress( device_imei = dev['devNo'], devTypeCode = dev['devType']['code'], port = part.partNo, attachParas = {'StartChargeSeq':StartChargeSeq,'connectorID':connectorID}, start_time = int(time.time()), finished_time = int(time.time()) + 3600*24, status = 'waiting', # 等充电事件上报后,再刷新此状态 consumeOrder = {}, weifuleOrderNo = orderNo, expireAt = datetime.datetime.now() + datetime.timedelta(days = 91)) new_service_progress.save() # 异步通知北向 async_operation(norther.notification_start_charge_result,result) logger.debug("[query_start_charge] return result = {}".format(result)) return get_reply_reponse(result, norther) def query_equip_charge_status(request): logger.info('function into [query_equip_charge_status]' ) norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response StartChargeSeq = data.get("StartChargeSeq") logger.info('[query_equip_charge_status],StartChargeSeq=%s' % (StartChargeSeq)) rechargeRcd = RechargeRecord.objects(wxOrderNo = StartChargeSeq).first() if not rechargeRcd: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) part = Part.objects(logicalCode = rechargeRcd.logicalCode,partNo = rechargeRcd.extraInfo['portNo']).first() if not part: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) dev = Device.get_dev_by_l(part.logicalCode) if not dev: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) box = ActionDeviceBuilder.create_action_device(dev) result = box.get_charge_status_for_swap(part.partNo,str(part.id)) result.update({ 'StartChargeSeq':StartChargeSeq, 'ConnectorId':str(part.id), 'StartTime':rechargeRcd.time, 'EndTime':datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) logger.debug("[query_equip_charge_status] return result = {}".format(result)) return get_reply_reponse(result, norther) def query_stop_charge(request): logger.info('function into [query_stop_charge]' ) norther,response = check_and_get_norther(request) if not norther: return response data,response = get_request_data(request, norther) if not data: return response StartChargeSeq = data.get("StartChargeSeq") connectorID = data.get("ConnectorID") logger.info('[query_stop_charge],StartChargeSeq=%s,connectorID=%s' % (StartChargeSeq,connectorID)) part = Part.objects(id = connectorID).first() if not part: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) dev = Device.get_dev_by_l(part.logicalCode) if not dev: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_POST, "Msg": u"请求参数错误,没有找到对应的设备接口"}) group = Group.get_group(dev['groupId']) # 首先检查下数据库订单情况,是否已经停止了 rechargeRcd = RechargeRecord.objects(wxOrderNo = StartChargeSeq).first() if not rechargeRcd: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_PARAM, "Msg": u"请求参数错误,没有找到对应的充值订单"}) consumeRcd = ConsumeRecord.objects(orderNo = rechargeRcd.extraInfo['consumeOrderNo']).first() if not consumeRcd: return JsonResponse({"Ret": RESPONSE_CODE.ERROR_PARAM, "Msg": u"请求参数错误,没有找到对应的消费订单"}) if consumeRcd.status == ConsumeRecord.Status.FINISHED: result = { "StartChargeSeq": StartChargeSeq, "StartChargeSeqStat": 4, # 已经结束 "connectorID": connectorID, "SuccStat": 0, "FailReason": 0, } # 启动异步,通知启动设备成功 async_operation(norther.notification_stop_charge_result,result) return get_reply_reponse(result, norther) box = ActionDeviceBuilder.create_action_device(dev) SuccStat,FailReason = box.stop_device_swap(part.partNo) result = { "StartChargeSeq": StartChargeSeq, "StartChargeSeqStat": 4, "connectorID": connectorID, "SuccStat": SuccStat, "FailReason": FailReason, } # 启动异步,通知启动设备成功 async_operation(norther.notification_stop_charge_result,result) logger.debug("[query_stop_charge] return result = {}".format(result)) return get_reply_reponse(result, norther)