# -*- coding: utf-8 -*- # !/usr/bin/env python """ web.user.views ~~~~~~~~~ 关于扫码终端用户的一切视图 """ import base64 import datetime import logging import random import re import time import uuid from copy import deepcopy from math import radians, fabs, cos, asin, sqrt, sin, isnan import simplejson as json from bson.objectid import ObjectId from django.conf import settings from mongoengine.errors import DoesNotExist from mongoengine.queryset.visitor import Q from typing import TYPE_CHECKING, cast, Optional, Union, Tuple, Dict from voluptuous.error import MultipleInvalid from apilib.monetary import VirtualCoin, RMB from apilib.utils_datetime import to_datetime, timestamp_to_dt from apilib.utils_json import JsonResponse from apilib.utils_string import cn #: ad from apilib.utils_sys import memcache_lock from apilib.utils_url import add_query, before_frag_add_query from apps import serviceCache from apps.common.utils import coordinateHandler from apps.web.ad.models import AdRecord, DevRegToAli from apps.web.agent.models import Agent, MoniApp from apps.web.common.proxy import ClientRechargeModelProxy, ClientConsumeModelProxy from apps.web.common.transaction.pay import OrderCacheMgr, PayManager from apps.web.common.transaction.refund import RefundManager from apps.web.common.utils import UserConsumeFilter from apps.web.common.validation import check_phone_number, check_entity_name from apps.web.constant import Const, GPS_TYPE, START_DEVICE_STATUS, ErrorCode, RECHARGE_CARD_TYPE, APP_TYPE, \ AppPlatformType, DeviceOnlineStatus, support_policy_weifule, \ support_policy_device, RechargeRecordVia from apps.web.core import PayAppType, ROLE from apps.web.core.auth.ali import AlipayAuthBridge from apps.web.core.auth.wechat import WechatAuthBridge from apps.web.core.bridge.wechat import WechatClientProxy from apps.web.core.exceptions import ServiceException, InvalidParameter, InvalidFileSize, \ InvalidFileName, InterceptException from apps.web.core.file import AliOssFileUploader from apps.web.core.helpers import ActionDeviceBuilder from apps.web.core.messages.sms import userMobileVerifySMSProvider from apps.web.core.models import WechatPayApp, BoundOpenInfo, WechatAuthApp from apps.web.core.sysparas import SysParas from apps.web.core.utils import DefaultJsonErrorResponse from apps.web.core.utils import JsonErrorResponse, JsonOkResponse from apps.web.dealer.models import Dealer, OnSale, OnSaleRecord, VirtualCard, Complaint, \ DealerMessage from apps.web.device.define import DeviceChannelType from apps.web.device.models import Device, Group, FeedBack, Comment, Cell, DeviceType, SwapGroup from apps.web.device.models import DeviceDict from apps.web.device.models import GroupDict from apps.web.device.utils import device_control_cache_key from apps.web.exceptions import UserServerException from apps.web.helpers import get_ali_auth_bridge, get_wx_config, get_wechat_auth_bridge, \ get_user_manager_agent, get_app, start_device_lock_key from apps.web.management.models import Manager from apps.web.services.bluetooth.service import ActionBtDeviceBuilder #: user from apps.web.south_intf.yuchuanApi import YuChuanApi from apps.web.user import UserAuthState, MoniUserAuthState from apps.web.user.auth import response_with_login from apps.web.user.conf import USER_AUTH_REDIRECT_URL, PAY_NOTIFY_URL from apps.web.user.models import MyUser, ConsumeRecord, RechargeRecord, ServiceProgress, Card, CardRechargeRecord, \ CardConsumeRecord, CardRechargeOrder, UserVirtualCard, VCardConsumeRecord, \ RefundMoneyRecord, MoniUser, VirtualCardRechargeRecord, SwapCardRecord, MonthlyPackage, \ EndUserLocation, Redpack, MyUserDetail from apps.web.user.transaction import post_pay from apps.web.user.transaction_deprecated import refund_post_pay from apps.web.user.utils import ( get_homepage_response, auth_wechat_pay_app, auth_wechat_manager_app, login_required, user_last_time_use_ended_cache, parse_auth_payload, batteryInfo, is_need_renew, check_user_tel, check_black_user, PayParam, BUILDER_MAP, RedpackBuilder) from apps.web.user.utils2 import get_user_not_complete_order from apps.web.user.validation import feedbackSchema from apps.web.utils import ( detect_alipay_client, detect_wechat_client, permission_required, error_tolerate, ErrorResponseRedirect, NotSupportedPlatformResponseRedirect, get_start_key_status, set_start_key_status, NetDeviceResponseRedirect, AdAccessResponseRedirect, ExternalResponseRedirect, FrontEndResponseRedirect, concat_server_end_url, concat_user_cardTicketList_entry_url, record_operation_behavior, get_client_ip, WechatAuthDummyRedirect, trace_call, concat_user_recharge_url) from apps.web.wrapper import request_limit_by_user from library.alipay.exceptions import AliException from library.wechatbase.exceptions import WechatOAuthDummyException from taskmanager.mediator import task_caller if TYPE_CHECKING: from django.core.handlers.wsgi import WSGIRequest from django.http import HttpResponse, HttpResponseRedirect from apps.web.common.proxy import QuerySetProxy from apps.web.core.db import CustomQuerySet from apps.web.core.models import PayAppBase logger = logging.getLogger(__name__) # 报错页面 defaultErrorResponseRedirect = ErrorResponseRedirect(error = cn(u'系统错误,请重试')) def checkAdClick(request): # type: (WSGIRequest)->HttpResponse """ :param request: :return: """ adId = request.GET.get('adId', None) logger.debug('get adId success adId = %s' % adId) if not adId: return ErrorResponseRedirect(error = cn(u'无效的链接,无此广告')) return AdAccessResponseRedirect(adId = str(adId)) @error_tolerate(nil = defaultErrorResponseRedirect) @login_required(error_response = ErrorResponseRedirect(error = cn(u'您未登陆,请扫码登录'))) def adAccess(request): # type: (WSGIRequest)->HttpResponse """ 减少cookie依赖, 参数全部通过state封装 用户领取广告效果奖励 :param request: :return: """ adId = request.GET.get('state', None) return ErrorResponseRedirect(error = cn(u'该广告不可用')) @trace_call(logger = logger) @error_tolerate(nil = defaultErrorResponseRedirect) def userLogin(request): # type: (WSGIRequest)->HttpResponse """ 用户扫码-> 登陆渲染的首屏页面 扫码的读取分配入口,同时兼容老式设备号和新式逻辑码 .. 2017/10/30 加入对支付宝识别的兼容。 :param request: :return: """ def by_agent(request, agentId, href): # type: (WSGIRequest, str, str)->(basestring, str) return UserAuthState.by_agent(agentId=agentId, href=href, productAgentId=agentId) def by_dev(request, devNo, logicalCode, port=None): # type: (WSGIRequest, str, str, str)->(basestring, str) logger.debug('user login. device = (logicalCode=%s), port = %s' % (logicalCode, port)) if (logicalCode is not None) and (devNo is None): logicalCode = logicalCode.strip() devNo = Device.get_devNo_by_logicalCode(logicalCode) if not devNo: raise UserServerException(u'该设备未开通网络支付,请投币或者联系客服(1002)') devNo = devNo.strip() dev = Device.get_dev(devNo) # type: Optional[DeviceDict] if dev is None: raise UserServerException(u'该设备未开通网络支付,请投币或者联系客服(1003)') if not dev.is_registered or 'groupId' not in dev or 'washConfig' not in dev: raise UserServerException(u'该设备未开通网络支付,请投币或者联系客服(1005)') if dev.is_expired: raise UserServerException( u'设备({})的物联网卡已经过期,目前离线,无法扫码支付。请您联系提醒设备运营商进行充值,以便尽快恢复使用。'.format( dev.logicalCode)) if dev.is_fault: raise UserServerException(u'设备故障中,正在等师傅过来维修,您试试看其他设备吧') if dev.is_DND_now: raise UserServerException(u'设备处于禁用时段,暂不支持扫码使用') if dev.ban: raise UserServerException(u'该设备暂时不可使用,请联系经销商') if port and dev.channelType != DeviceChannelType.Channel_BT: isFree = Group.get_group(dev.groupId).get('isFree', False) if not isFree: box = ActionDeviceBuilder.create_action_device(dev) isCanAdd = dev['devType'].get('payableWhileBusy', False) canUse, desc = box.is_port_can_use(port, isCanAdd) if not canUse: raise UserServerException(desc) dealer = dev.owner # type: Dealer # 平台agent必须配置自定义公众号, 否则普通扫码用户无法获取 product_agent = get_user_manager_agent(dealer) state = UserAuthState.by_dev(devNo=devNo, chargeIndex=port, agentId=str(dealer.agentId), productAgentId=str(product_agent.id)) logger.debug('initial user state = {}'.format(repr(state))) return dev, product_agent, state def generate_card_recharge_href(_cardNo, _product_agent_id): # type:(str, str) -> Optional[str] _baseHref = "/user/index.html#/chargeCard?cardNo={}&cardId={}" try: card = Card.objects.get(cardNo=_cardNo, agentId=str(_product_agent_id)) except DoesNotExist: logger.error('card is not exist, cardNo=%s' % _cardNo) return None except Exception as e: logger.error(e) return None return _baseHref.format(_cardNo, str(card.id)) def login_context(request): if 'devNo' not in request.GET and 'l' not in request.GET and 'agentId' not in request.GET: return ErrorResponseRedirect(error=cn(u'错误的二维码或者二维码损坏,请联系工作人员进行维修')) href = request.GET.get('redirect', '/user/index.html#/user/me') if 'agentId' in request.GET: # 个人中心登录 dev = None # type: Optional[DeviceDict] product_agent_id = str(request.GET.get("agentId")) product_agent = Agent.objects(id = product_agent_id).get() # type: Agent cardNo = request.GET.get("cardNo") if cardNo: href = generate_card_recharge_href(cardNo, product_agent_id) or href state = by_agent(request, product_agent_id, href) groupId = MyUser._product_group_id(product_agent_id) else: # 扫描登录 devNo = request.GET.get('devNo', None) logicalCode = request.GET.get('l', None) dev, product_agent, state = by_dev(request, devNo, logicalCode, request.GET.get('chargeIndex', None)) groupId = dev.groupId if detect_wechat_client(request): # 微信平台登录 auth_bridge = get_wechat_auth_bridge( source = product_agent, app_type = APP_TYPE.WECHAT_AUTH) # type: WechatAuthBridge pay_type = u'微信' auth_callback = None # 具体处理流程中写死 elif detect_alipay_client(request): # 支付宝平台登录 auth_bridge = get_ali_auth_bridge(source=product_agent, app_type=APP_TYPE.ALIPAY_AUTH) # type: AlipayAuthBridge pay_type = u'支付宝' auth_callback = USER_AUTH_REDIRECT_URL.ALIPAY else: raise UserServerException(u'不支持该平台下扫码') if not auth_bridge.enable: raise UserServerException(u'{}平台暂时未开通,请使用其他方式登录'.format(pay_type)) if not product_agent.customizedUserGzhAllowable: return ErrorResponseRedirect(error=cn(u'系统配置错误,请联系平台客服(10009)')) return auth_bridge, auth_callback, product_agent, state, pay_type, dev, groupId def clone_from_login_user(login_user, auth_bridge, groupId, new_product_agent_id, new_agent_id): if login_user.groupId == groupId: my_user = login_user need_save = False if my_user.agentId != new_agent_id: my_user.agentId = new_agent_id need_save = True if my_user.productAgentId != new_product_agent_id: my_user.productAgentId = new_product_agent_id need_save = True if need_save: my_user.save() else: if login_user.productAgentId == new_product_agent_id: payload = login_user.cloneable_user_info else: payload = {} payload.update({ 'authAppId': auth_bridge.appid, 'agentId': new_agent_id, 'productAgentId': new_product_agent_id }) my_user = MyUser.get_or_create(app_platform_type = auth_bridge.gateway_type, open_id = login_user.openId, group_id = groupId, **payload) return my_user try: ip = get_client_ip(request) logger.debug("user login. ".format(ip)) auth_bridge, auth_callback, product_agent, state, pay_type, dev, groupId = login_context(request) login_user = request.user # type: MyUser if auth_bridge.gateway_type == AppPlatformType.WECHAT: need_auth = (not login_user.is_authenticated()) or (login_user.authAppId != auth_bridge.appid) if state.by == UserAuthState.BY.AGENT: if need_auth: manager_auth_bridge = get_wechat_auth_bridge(product_agent, APP_TYPE.WECHAT_USER_MANAGER) if manager_auth_bridge.appid == auth_bridge.appid: logger.debug('auth bridge is same with manager auth bridge.') return ExternalResponseRedirect( auth_bridge.generate_auth_url_user_scope( redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_AUTH_USER, payload = state.encode())) else: return ExternalResponseRedirect( auth_bridge.generate_auth_url_base_scope( redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_AUTH_BASE, payload = state.encode())) else: my_user = clone_from_login_user( login_user, auth_bridge, groupId, str(product_agent.id), str(product_agent.id)) manager_auth_bridge = get_wechat_auth_bridge(product_agent, APP_TYPE.WECHAT_USER_MANAGER) manager_openid = my_user.get_bound_pay_openid(manager_auth_bridge.bound_openid_key) if manager_openid and (manager_openid != my_user.managerialOpenId): my_user.managerialAppId = manager_auth_bridge.appid my_user.managerialOpenId = manager_openid my_user.save() if (not manager_openid) or (not my_user.nickname): state.uid = str(my_user.id) return ExternalResponseRedirect( manager_auth_bridge.generate_auth_url_user_scope( redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_MANAGER_AUTH_USER, payload = state.encode())) else: if need_auth: return ExternalResponseRedirect( auth_bridge.generate_auth_url_base_scope( redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_AUTH_BASE, payload = state.encode())) else: my_user = clone_from_login_user( login_user, auth_bridge, groupId, str(product_agent.id), dev.owner.agentId if dev else str(product_agent.id)) state.uid = str(my_user.id) response = auth_wechat_manager_app(my_user, product_agent, state, dev) if response: return response response = auth_wechat_pay_app( my_user, dev.owner, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE) if response: return response else: if not login_user.is_authenticated(): return ExternalResponseRedirect( auth_bridge.generate_auth_url_user_scope( redirect_uri=auth_callback, payload=state.encode())) else: my_user = clone_from_login_user( login_user, auth_bridge, groupId, str(product_agent.id), dev.owner.agentId if dev else str(product_agent.id)) if my_user.nickname is None: return ExternalResponseRedirect( auth_bridge.generate_auth_url_user_scope( redirect_uri = auth_callback, payload = state.encode())) if state.by == UserAuthState.BY.AGENT: response = FrontEndResponseRedirect(str(state.href)) else: response = get_homepage_response(auth_bridge.gateway_type, my_user, dev, state.chargeIndex if state.chargeIndex else '', product_agent) return response_with_login(request, my_user, response) except UserServerException as e: return ErrorResponseRedirect(error=cn(e.message)) except Exception as e: logger.exception(e) return ErrorResponseRedirect(error=cn(u'系统错误')) @trace_call(logger = logger) @error_tolerate(nil = defaultErrorResponseRedirect, logger = logger) def wxpayBaseAccess(request): # type: (WSGIRequest)->HttpResponse """ 获取微信用户支付的openId :param request: :return: """ def authorize(app, request): # type: (Optional[WechatPayApp], WSGIRequest)->None if isinstance(app, WechatPayApp): code = request.GET.get('code', None) if not code: raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL)) auth_bridge = WechatAuthBridge(app) openId = auth_bridge.authorize(code) user.set_bound_pay_openid(auth_bridge.bound_openid_key, openId = openId) user.save() try: if 'code' not in request.GET and 'openId' not in request.GET: raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL)) state = parse_auth_payload(request) if not state.is_valid(): raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.USER_STATE_IS_NOT_VALID)) user = MyUser.objects.get(id = state.uid) # type: MyUser dev = Device.get_dev(state.devNo) # type: DeviceDict product_agent = Agent.objects(id = str(state.productAgentId)).get() app = get_app(source = product_agent, app_type = APP_TYPE.WECHAT_ENV_PAY, role = ROLE.myuser) # type: PayAppBase authorize(app, request) response = get_homepage_response(AppPlatformType.WECHAT, user, dev, state.chargeIndex if state.chargeIndex else '', product_agent) return response_with_login(request, user, response) except Exception as e: logger.exception(e) return ErrorResponseRedirect(error = u'系统错误, 请重新扫码') @trace_call(logger = logger) @error_tolerate(nil = defaultErrorResponseRedirect) def wechatAuthBase(request): # type: (WSGIRequest)->HttpResponse """ 老终端用户扫码进入 只获取openId 用户通过扫码转到的中继器 :param request: :return: """ try: auth_code = request.GET.get('code', None) if auth_code is None: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.AUTH_CODE_IS_NULL) state = parse_auth_payload(request) # type: UserAuthState logger.info('return to wechatAuthBase. code = %s; state = %s' % (auth_code, state)) product_agent = Agent.objects(id = str(state.productAgentId)).get() # type: Agent dev = Device.get_dev(state.devNo) # type: DeviceDict groupId = dev.groupId auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_AUTH) logger.debug( 'wechat auth for login. appid = {}, code = {}, state = {}, agent = {}, group_id = {}'.format( auth_bridge.appid, auth_code, str(state.encode()), str(product_agent.id), groupId)) openId = auth_bridge.authorize(auth_code) if not openId: logger.error( 'auth error, app = %s; payload = %s' % (repr(auth_bridge.app), str(state.encode()))) return ErrorResponseRedirect(error = u'系统错误,请重新扫码') payload = { 'authAppId': auth_bridge.app.appid, 'agentId': str(state.agentId), 'productAgentId': str(state.productAgentId), 'payOpenIdMap': { auth_bridge.bound_openid_key: BoundOpenInfo(openId = openId) } } manager_auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER) if manager_auth_bridge.appid == auth_bridge.appid: payload.update({ 'managerialAppId': auth_bridge.appid, 'managerialOpenId': openId }) my_user = MyUser.get_or_create( app_platform_type = AppPlatformType.WECHAT, open_id = openId, group_id = groupId, **payload) if not my_user: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.LOGIN_USER_IS_NULL) dealer = dev.owner # type: Dealer state.uid = str(my_user.id) response = auth_wechat_manager_app(my_user, product_agent, state, dev) if response: return response response = auth_wechat_pay_app(my_user, dealer, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE) if response: return response response = get_homepage_response(AppPlatformType.WECHAT, my_user, dev, state.chargeIndex if state.chargeIndex else '', product_agent) return response_with_login(request, my_user, response) except UserServerException as e: logger.error(e.message) return ErrorResponseRedirect(error = cn(e.message)) except Exception as e: logger.exception(e) return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔')) @trace_call(logger = logger) @error_tolerate(nil = ErrorResponseRedirect, logger = logger) def wechatManagerAuthBase(request): # type: (WSGIRequest)->HttpResponse """ manager做基础鉴权, 获取OpenId. 只有从用户信息获取不到managerOpenId的情况下才会走这个分支 :param request: :return: """ try: auth_code = request.GET.get(WechatAuthBridge.auth_code_key, None) if not auth_code: raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL)) state = parse_auth_payload(request) my_user = MyUser.objects.get(id = state.uid) product_agent = Agent.objects(id = str(state.productAgentId)).get() manager_auth_bridge = get_wechat_auth_bridge( source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER) # type: WechatAuthBridge openId = manager_auth_bridge.authorize(auth_code) if openId is None: logger.error( 'manager auth error, app = %s; state = %s' % (repr(manager_auth_bridge.app), str(state.encode()))) return ErrorResponseRedirect(error = u'系统错误, 请重新扫码') my_user.managerialAppId = manager_auth_bridge.appid my_user.managerialOpenId = openId my_user.set_bound_pay_openid(manager_auth_bridge.bound_openid_key, openId = openId) my_user.save() dev = Device.get_dev(state.devNo) # type: DeviceDict response = auth_wechat_manager_app(my_user, product_agent, state, dev) if response: return response response = auth_wechat_pay_app(my_user, dev.owner, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE) if response: return response response = get_homepage_response(AppPlatformType.WECHAT, my_user, dev, state.chargeIndex if state.chargeIndex else '', product_agent) return response_with_login(request, my_user, response) except UserServerException as e: logger.error(e.message) return ErrorResponseRedirect(error = cn(e.message)) except WechatOAuthDummyException as e: logger.error(e.message) return WechatAuthDummyRedirect() except Exception as e: logger.exception(e) return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔')) @trace_call(logger = logger) @error_tolerate(nil = ErrorResponseRedirect, logger = logger) def wechatManagerAuthUser(request): # type: (WSGIRequest)->HttpResponse """ 用户首次授权,需要创建用户 :param request: :return: """ try: auth_code = request.GET.get(WechatAuthBridge.auth_code_key, None) if not auth_code: raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL)) state = parse_auth_payload(request) user = MyUser.objects.get(id = state.uid) product_agent = Agent.objects(id = str(state.productAgentId)).get() manager_auth_bridge = get_wechat_auth_bridge( source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER) # type: WechatAuthBridge userInfo = manager_auth_bridge.get_user_info(auth_code = auth_code) openId = userInfo['openId'] if openId is None: logger.error( 'manager auth error, app = %s; payload = %s' % (repr(manager_auth_bridge.app), str(state.encode()))) return ErrorResponseRedirect(error = u'系统错误, 请重新扫码') user.sex = userInfo.get('sex', 0) user.city = userInfo.get('city', '') user.province = userInfo.get('province', '') user.country = userInfo.get('country', '') user.nickname = userInfo.get('nickname', '') user.avatar = userInfo.get('avatar', '') user.unionId = userInfo.get('unionid', '') user.set_bound_pay_openid(manager_auth_bridge.bound_openid_key, openId = openId) user.managerialAppId = manager_auth_bridge.appid user.managerialOpenId = openId user.save() dev = Device.get_dev(state.devNo) # type: DeviceDict response = auth_wechat_pay_app(user, dev.owner, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE) if response: return response response = get_homepage_response(AppPlatformType.WECHAT, user, dev, state.chargeIndex if state.chargeIndex else '', product_agent) return response_with_login(request, user, response) except UserServerException as e: logger.error(e.message) return ErrorResponseRedirect(error = cn(e.message)) except WechatOAuthDummyException as e: logger.error(e.message) return WechatAuthDummyRedirect() except Exception as e: logger.exception(e) return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔')) @trace_call(logger = logger) @error_tolerate(nil=defaultErrorResponseRedirect) def wechatBaseAuthForUserCenter(request): # type: (WSGIRequest)->HttpResponse """ 个人中心 :param request: :return: """ try: auth_code = request.GET.get('code', None) if auth_code is None: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.AUTH_CODE_IS_NULL) state = parse_auth_payload(request) # type: UserAuthState assert state.by == UserAuthState.BY.AGENT, 'must be enter user center.' logger.info('return to wechatBaseAuthForUserCenter. code = %s; state = %s' % (auth_code, state)) product_agent = Agent.objects(id = str(state.productAgentId)).get() # type: Agent groupId = MyUser.groupId.default auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_AUTH) logger.debug( 'wechat base auth for user center login. appid = {}, code = {}, state = {}, agent = {}, group_id = {}'.format( auth_bridge.appid, auth_code, str(state.encode()), str(product_agent.id), groupId)) openId = auth_bridge.authorize(auth_code) if not openId: logger.error( 'auth error, app = %s; payload = %s' % (repr(auth_bridge.app), str(state.encode()))) return ErrorResponseRedirect(error = u'系统错误,请重新扫码') payload = { 'authAppId': auth_bridge.app.appid, 'agentId': str(state.agentId), 'productAgentId': str(state.productAgentId), 'payOpenIdMap': { auth_bridge.bound_openid_key: BoundOpenInfo(openId = openId) } } user = MyUser.get_or_create( app_platform_type = AppPlatformType.WECHAT, open_id = openId, group_id = groupId, **payload) manager_auth_bridge = get_wechat_auth_bridge( source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER) manager_openid = user.get_bound_pay_openid(manager_auth_bridge.bound_openid_key) if manager_openid and (manager_openid != user.managerialOpenId): user.managerialOpenId = manager_openid user.managerialAppId = manager_auth_bridge.appid user.save() if (not manager_openid) or (not user.nickname): state.uid = str(user.id) return ExternalResponseRedirect( manager_auth_bridge.generate_auth_url_user_scope( redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_MANAGER_AUTH_USER, payload = state.encode())) else: logger.debug('redirect url is: {}'.format(state.href)) response = FrontEndResponseRedirect(str(state.href)) return response_with_login(request, user, response) except UserServerException as e: logger.error(e.message) return ErrorResponseRedirect(error = cn(e.message)) except Exception as e: logger.exception(e) return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔')) @trace_call(logger = logger) @error_tolerate(nil = defaultErrorResponseRedirect) def wechatUserAuthForUserCenter(request): # type: (WSGIRequest)->HttpResponse """ 个人中心 :param request: :return: """ try: auth_code = request.GET.get('code', None) if auth_code is None: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.AUTH_CODE_IS_NULL) state = parse_auth_payload(request) # type: UserAuthState assert state.by == UserAuthState.BY.AGENT, 'must be enter user center.' logger.info('return to wechatUserAuthForUserCenter. code = %s; state = %s' % (auth_code, state)) product_agent = Agent.objects(id = str(state.productAgentId)).get() # type: Agent groupId = MyUser.groupId.default auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_AUTH) logger.debug( 'wechat user auth for user center login. appid = {}, code = {}, state = {}, agent = {}, group_id = {}'.format( auth_bridge.appid, auth_code, str(state.encode()), str(product_agent.id), groupId)) userInfo = auth_bridge.get_user_info(auth_code = auth_code) openId = userInfo['openId'] if openId is None: logger.error( 'manager auth error, app = %s; payload = %s' % (repr(auth_bridge.app), str(state.encode()))) return ErrorResponseRedirect(error = u'系统错误, 请重新扫码') payload = { 'sex': userInfo.get('sex', 0), 'city': userInfo.get('city', ''), 'province': userInfo.get('province', ''), 'country': userInfo.get('country', ''), 'nickname': userInfo.get('nickname', ''), 'avatar': userInfo.get('avatar', ''), 'unionId': userInfo.get('unionid', ''), 'authAppId': auth_bridge.appid, 'payOpenIdMap': { auth_bridge.bound_openid_key: BoundOpenInfo(openId = openId) }, 'agentId': str(state.agentId), 'productAgentId': str(state.productAgentId), 'managerialAppId': auth_bridge.appid, 'managerialOpenId': openId } user = MyUser.get_or_create(app_platform_type = AppPlatformType.WECHAT, open_id = openId, group_id = groupId, **payload) logger.debug('redirect url is: {}'.format(state.href)) response = FrontEndResponseRedirect(str(state.href)) return response_with_login(request, user, response) except UserServerException as e: logger.error(e.message) return ErrorResponseRedirect(error = cn(e.message)) except WechatOAuthDummyException as e: logger.error(e.message) return WechatAuthDummyRedirect() except Exception as e: logger.exception(e) return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔')) @trace_call(logger = logger) @error_tolerate(nil=ErrorResponseRedirect, logger=logger) def wechatManagerAuthForUserCenter(request): # type: (WSGIRequest)->HttpResponse """ :param request: :return: """ try: auth_code = request.GET.get(WechatAuthBridge.auth_code_key, None) if not auth_code: raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL)) state = parse_auth_payload(request) assert state.by == UserAuthState.BY.AGENT, 'must enter in user center.' user = MyUser.objects.get(id=state.uid) product_agent = Agent.objects(id=str(state.productAgentId)).get() manager_auth_bridge = get_wechat_auth_bridge( source=product_agent, app_type=APP_TYPE.WECHAT_USER_MANAGER) # type: WechatAuthBridge userInfo = manager_auth_bridge.get_user_info(auth_code=auth_code) openId = userInfo['openId'] if openId is None: logger.error( 'manager auth error, app = %s; payload = %s' % (repr(manager_auth_bridge.app), str(state.encode()))) raise UserServerException(u'系统错误, 请重新扫码') user.sex = userInfo.get('sex', 0) user.city = userInfo.get('city', '') user.province = userInfo.get('province', '') user.country = userInfo.get('country', '') user.nickname = userInfo.get('nickname', '') user.avatar = userInfo.get('avatar', '') user.unionId = userInfo.get('unionid', '') user.set_bound_pay_openid(manager_auth_bridge.bound_openid_key, openId=openId) user.managerialAppId = manager_auth_bridge.appid user.managerialOpenId = openId user.save() logger.debug('redirect url is: {}'.format(state.href)) response = FrontEndResponseRedirect(str(state.href)) return response_with_login(request, user, response) except UserServerException as e: logger.error(e.message) return ErrorResponseRedirect(error=cn(e.message)) except WechatOAuthDummyException as e: logger.error(e.message) return WechatAuthDummyRedirect() except Exception as e: logger.exception(e) return ErrorResponseRedirect(error=cn(u'网络开小差了,重新扫码试试喔')) @permission_required(ROLE.myuser) def baseMoniAccess(request): """ moni app 的鉴权 """ code = request.GET.get("code", None) if code is None: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.MONI_AUTH_IS_NULL) state = parse_auth_payload(request) # type: UserAuthState inhouseMoniApp = MoniApp.objects.filter(appid=state.appid).first() # type: MoniApp if not inhouseMoniApp: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.MONI_APP_IS_NULL) user = MyUser.objects.filter(id=state.uid).first() if not user: raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.LOGIN_USER_IS_NULL) # 存在app 的情况下 使用app进行解码 写入数据 moniAuthBridge = WechatAuthBridge(WechatAuthApp(appid=inhouseMoniApp.appid, secret=inhouseMoniApp.secret)) openId = moniAuthBridge.authorize(code) user.set_bound_pay_openid(moniAuthBridge.bound_openid_key, openId=openId) user.save() productAgent = Agent.objects.get(id=state.productAgentId) dev = Device.get_dev(state.devNo) response = get_homepage_response(AppPlatformType.WECHAT, user, dev, state.chargeIndex, productAgent) return response_with_login(request, user, response) @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"系统繁忙,请稍后重试")) @permission_required(ROLE.myuser) @request_limit_by_user(operation='equipmentPara', logger=logger) def equipmentPara(request): # type: (WSGIRequest)->HttpResponse """ 扫码后获取设备侧以及用户的相关信息 """ currentUser = request.user # type: MyUser logicalCode = request.GET.get("logicalCode") force = True if request.GET.get('refresh', 'false') == 'true' else False dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict if not dev: logger.info('(%s) cannot find device, devNo = %s' % (request.user, logicalCode)) return JsonErrorResponse(description=u"该设备尚未注册(1002)") if not dev.group: logger.info('can not find group. dev = %s' % dev) return JsonErrorResponse(description=u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1010)') if not dev.dealer: logger.info('can not find dealer. dev = %s; group = %s' % (str(dev), str(dev.group))) return JsonErrorResponse(description=u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1011)') if check_black_user(dealerId=dev.get("ownerId"), openId = request.user.openId): return JsonErrorResponse(u"该设备暂不对您开放,请联系经销商") agent = Agent.objects(id=str(dev.dealer['agentId'])).first() # type: Agent agentFeatures = set(agent.features) if agent is not None else set([]) dealer_features = map(lambda x: x['key'], filter(lambda x: x['value'] is True, dev.dealer['featureList'])) if 'mini_recharge' in dealer_features: agentFeatures.add('mini_recharge') if 'mini_card_recharge' in dealer_features: agentFeatures.add('mini_card_recharge') devType = deepcopy(dev.devType) try: portDict = dev.deviceAdapter.get_port_status(force) if not force: dev.deviceAdapter.async_update_portinfo_from_dev() if portDict: chargeIndex = {} for index, info in portDict.items(): if info['status'] == Const.DEV_WORK_STATUS_IDLE: chargeIndex[index] = 'idle' elif info['status'] == Const.DEV_WORK_STATUS_WORKING: chargeIndex[index] = 'busy' elif info['status'] == Const.DEV_WORK_STATUS_FAULT: chargeIndex[index] = 'fault' elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN: chargeIndex[index] = 'ban' elif info['status'] == Const.DEV_WORK_STATUS_CONNECTED: chargeIndex[index] = 'connected' elif info['status'] == Const.DEV_WORK_STATUS_FINISHED: chargeIndex[index] = 'finished' elif info['status'] == Const.DEV_WORK_STATUS_ESTOP: chargeIndex[index] = 'estop' elif info['status'] == Const.DEV_WORK_STATUS_READY: chargeIndex[index] = 'ready' else: chargeIndex[index] = 'busy' devType.update({"chargeIndex": chargeIndex}) except ServiceException as e: return JsonErrorResponse(description=e.result.get('description')) except Exception as e: logger.exception('cannot get_port_status, error=%s' % (str(e),)) return JsonErrorResponse(description=u'未知错误') data = { "devType": devType, "groupId": dev.groupId, "cityId": dev.group.get('districtId', ''), "inFreeGroup": dev.group.get('isFree', False), "lbs": dev.lbs, "instructions": dev.get('instructions', ''), "logicalCode": dev.logicalCode, "payAfterAd": dev.dealer['adShow'], "dealerId": dev.ownerId, "dealerDes": dev.dealer['description'], 'devNo': dev.devNo, 'channelType': dev.channelType, 'avatarUrl': currentUser.avatar, 'nickname': currentUser.nickname, 'openId': currentUser.openId, 'agentFeatures': list(agentFeatures), 'countDown': False, 'bottomAd': dev.dealer.get('bottomAd', {}), 'noRecharge': dev.dealer.get('noRecharge', False), 'favorite': True if dev.devNo in currentUser.collectedDeviceList else False, "payAfterUse": dev.get("otherConf", dict()).get("payAfterUse", False), 'majorDeviceType': dev.majorDeviceType, 'subTemplateId': agent.get_user_sub_template_id_list(), 'priceDescription': dev.priceDescription, 'popPriceDescriptionButton': dev.group.popPriceDescriptionButton } if "hasTempPackage" in dev.dealer: if dev.devTypeCode in [Const.DEVICE_TYPE_CODE_WEIFULE_POLICY_CLASSIC]: data["hasTempPackage"] = False data["displayTempPackage"] = False elif dev.devTypeCode in support_policy_weifule + support_policy_device: try: data["displayTempPackage"] = dev.dealer.get("displayTempPackage", True) packages = dev.deviceAdapter.user_show_package(isTemp=True) if packages: data["hasTempPackage"] = True else: data["hasTempPackage"] = False except Exception as e: logger.error("[equipmentPara] get hasTempPackage error = {}".format(e)) data["hasTempPackage"] = False else: if dev.dealer.get("hasTempPackage", None) is True: data["hasTempPackage"] = dev.dealer.get("hasTempPackage") data["displayTempPackage"] = dev.dealer.get("displayTempPackage", True) if dev.need_fetch_online: data.update({'online': DeviceOnlineStatus.DEV_STATUS_ONLINE}) else: data.update({'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE}) if "telVerify" in agent.features: needTelVerify = check_user_tel(request.user) data.update({ "needTelVerify": needTelVerify }) data.update({'countDown': dev.deviceAdapter.support_count_down()}) if dev.devTypeCode == Const.DEVICE_TYPE_CODE_TIMESWITCH7: pricePerHour = dev.my_obj.otherConf.get('pricePerHour', 2.0) data.update({'pricePerHour': pricePerHour}) elif dev.devTypeCode in [ Const.DEVICE_TYPE_CODE_CAR_NENGPAI, Const.DEVICE_TYPE_CODE_CHARGE_WEIFULE_CAR, Const.DEVICE_TYPE_CODE_CAR_WEIFULE_CHARGING_DOUB, Const.DEVICE_TYPE_CODE_CAR_WEIFULE_21KW, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, ]: infos = dev.deviceAdapter.get_policy_for_user() data.update({"policyInfos": infos}) resultResponse = JsonResponse({'result': 1, 'description': '', 'payload': data}) resultResponse = Agent.record_cookie(dev.dealer['agentId'], resultResponse) return resultResponse @error_tolerate(nil = defaultErrorResponseRedirect) @permission_required(ROLE.myuser) def deviceInfo(request): """ 通过logicalCode获取 设备的一些基本信息, 功能上需要和equipment区分开 :param request: :return: """ logicalCode = request.GET.get("logicalCode") if not logicalCode: return JsonErrorResponse(description = u"无效的设备编号") dev = Device.get_dev_by_l(logicalCode) if not dev: return JsonErrorResponse(description = u"无效的设备编号") group = Group.get_group(dev.get("groupId", "")) # TODO zjl 目前只添加这些信息,后续有需要再添加 但是此接口定义为获取设备的简易信息 需要和equipment区分 data = { "devNo": dev.get("devNo", ""), "logicalCode": dev.get("logicalCode", ""), "ownerId": dev.get("ownerId", ""), "groupId": dev.get("groupId", ""), "groupName": group.get("groupName", ""), "isFree": group.get("isFree", False) } return JsonOkResponse(payload = data) @permission_required(ROLE.myuser) def userBalance(request): # type: (WSGIRequest)->JsonResponse """ 用户余额 用户余额是以地址为单位建立 但是由于地址可以设置通用 并且个人中心也需要显示总余额 """ logicalCode = request.GET.get("logicalCode") if not logicalCode: overallBalance = sum((u.balance for u in request.user.product_users), RMB(0)) return JsonOkResponse( payload={ 'balance': overallBalance, 'overallBalance': overallBalance, 'currencyCoins': overallBalance }) dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict if not dev: return JsonErrorResponse(description=u'设备没有注册,或者二维码错误,请联系客服处理') if not dev.is_registered: return JsonErrorResponse(description=u'设备没有注册,请联系客服处理') if dev.ownerId != dev.group.ownerId: return JsonErrorResponse(description=u'设备注册信息错误,请联系客服处理') if dev.group.groupId != request.user.groupId: product_agent = get_user_manager_agent(dev.owner) # type: Agent if str(product_agent.id) != request.user.productAgentId: return JsonErrorResponse(description=u'设备投放地址不属于该平台,请重新扫描设备二维码。') # 分别为用户总余额、用户经销商下的余额、用户的通用地址余额 overall, dealer_balance, usable_balance = request.user.get_balance_in_dealer(dev.owner, dev.group) return JsonOkResponse( payload={ 'balance': usable_balance, 'balanceInDealer': dealer_balance, 'overallBalance': overall }) @permission_required(ROLE.myuser) def getBalanceList(request): # type: (WSGIRequest)->Union[HttpResponse,JsonResponse] """ 用户账户详情 :param request: :return: """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) currentGroupId = request.GET.get('groupId', None) if currentGroupId == '-1': currentGroupId = None if currentGroupId: current_group = Group.get_group(currentGroupId) # type: GroupDict else: current_group = None # type: None totalCharge, totalBestow, total, dataList = request.user.filter_my_balance(current_group) cmp_dealer = lambda x, y: 1 if x['dealerId'] > y['dealerId'] else -1 dataList.sort(cmp = cmp_dealer) return JsonResponse( { 'result': 1, 'description': '', 'payload': { 'totalCharge': totalCharge, 'totalBestow': totalBestow, 'total': total, 'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize] } } ) def asynDiscountList(request): # type: (WSGIRequest)->JsonResponse """ 用户充值菜单 :param request: :return: """ devNo = Device.get_dev_no_from_request(request) dev = Device.get_dev(devNo) if dev is None: return JsonResponse({'result': 0, 'description': u'该设备未开通网络支付,请投币或者联系客服(1000)', 'payload': {}}) group = Group.get_group(dev['groupId']) # type:GroupDict if not group: return JsonResponse({'result': 0, 'description': u'该设备未开通网络支付,请投币或者联系客服(1001)', 'payload': {}}) return JsonResponse({ 'result': 1, 'description': 'SUCCESS', 'payload': { 'discountList': group.recharge_rule_list } }) @permission_required(ROLE.myuser) def getPackage(request): # type: (WSGIRequest)->JsonResponse """ 获取设备套餐 :param request: :return: """ devNo = request.GET.get("devNo") device = Device.get_dev(devNo) # type: DeviceDict if device is None: return JsonResponse({'result': 0, 'description': u'无此设备', 'payload': {}}) washConfig = device['washConfig'] otherConf = device.get('otherConf') if "displaySwitchs" in otherConf: displaySwitchs = otherConf.get('displaySwitchs') displaySwitchs = dict(filter(lambda x: "display" in x[0], displaySwitchs.items())) else: displaySwitchs = { 'displayCoinsSwitch': True, 'displayTimeSwitch': True, 'displayPriceSwitch': True } if device.devTypeCode in support_policy_weifule + support_policy_device + [ Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU ]: try: if device.deviceAdapter.support_device_package: packages = device.deviceAdapter.user_show_package() return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages}) except Exception as e: logger.exception(e) return JsonResponse({'result': 0, 'description': '当前套餐参数有误, 请联系经销商重新配置', 'payload': []}) packages = [] for packageId, rule in washConfig.items(): # 没有启用的套餐 直接掠过 if not rule.get("switch", True): continue price = rule['price'] imgList = [] try: for img in rule.get('imgList', []): if img.startswith('/'): imgList.append('{}{}'.format(settings.OSS_RESOURCE_URL, img)) else: imgList.append(img) except Exception as e: logger.exception(e) imgList = rule.get('imgList', []) item = { 'id': packageId, 'name': rule['name'], 'time': rule['time'], 'price': price, 'description': rule.get('description', ''), 'imgList': imgList, 'unit': rule.get('unit', u'分钟'), } if rule.get('basePrice'): item.update({'basePrice': rule.get('basePrice')}) if rule.get('sn', None) is not None: item.update({'sn': rule.get('sn')}) if rule['name'] == u'充满自停' and float(rule['coins']) == 0 and float(price) == 0: item.update({'displayCoinsSwitch': False, 'displayTimeSwitch': False, 'displayPriceSwitch': False}) else: item.update(displaySwitchs) packages.append(item) packages = sorted(packages, key=lambda x: (x.get('sn'), x.get('price'))) return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages}) @permission_required(ROLE.myuser) def getTempPackage(request): # type: (WSGIRequest)->JsonResponse """ 设备套餐 :param request: :return: """ def cmp_by_price(x, y): if x['price'] < y['price']: return -1 elif x['price'] > y['price']: return 1 else: return 0 devNo = Device.get_dev_no_from_request(request) if not devNo: return JsonResponse({'result': 0, 'description': u'获取数据失败,请重新扫码登录'}) device = Device.get_dev(devNo) if device is None: return JsonResponse({'result': 0, 'description': u'无此设备', 'payload': {}}) if device['devType']['code'] in support_policy_weifule + support_policy_device: try: if device.deviceAdapter.support_device_package: packages = device.deviceAdapter.user_show_package(isTemp=True) if not packages: return JsonResponse({'result': 0, 'description': '当前设备未配置临时套餐, 请联系经销商去配置', 'payload': {}}) else: return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages}) else: return JsonResponse({'result': 0, 'description': '当前套餐参数有误, 请联系经销商重新配置', 'payload': []}) except: return JsonResponse({'result': 0, 'description': '当前套餐参数有误, 请联系经销商重新配置', 'payload': []}) elif device['devType']['code'] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,]: tempWashConfig = device['tempWashConfig'] if not tempWashConfig: return JsonResponse({'result': 0, 'description': u'当前设备未配置临时套餐, 请联系经销商去配置', 'payload': {}}) packages = device.deviceAdapter.user_show_package(isTemp=True) return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages}) if device['tempWashConfig'] == {}: Device.get_and_update_device_cache(device["devNo"], tempWashConfig = device['washConfig']) device = Device.get_dev(devNo) tempWashConfig = device['tempWashConfig'] otherConf = device.get('otherConf') if "displayTempSwitchs" in otherConf: displayTempSwitchs = otherConf.get('displayTempSwitchs') displayTempSwitchs = dict(filter(lambda x: "display" in x[0], displayTempSwitchs.items())) else: displayTempSwitchs = {'displayCoinsSwitch': True, 'displayTimeSwitch': True, 'displayPriceSwitch': True, } group = Group.get_group(device['groupId']) # 探测是否地址为免费活动组,默认为否 is_free_service = group.get('isFree', False) appendix = u' 免费使用' if is_free_service else '' packages = [] for packageId, rule in tempWashConfig.items(): item = { 'id': packageId, 'coins': rule['coins'], 'name': rule['name'] + appendix, 'time': rule['time'], 'price': rule['price'], 'description': rule.get('description', ''), 'imgList': rule.get('imgList', []), 'unit': rule.get('unit', u'分钟') } if rule.get('basePrice'): item.update({'basePrice': rule.get('basePrice')}) if rule.get('sn', None) is not None: item.update({'sn': rule.get('sn')}) item.update(displayTempSwitchs) packages.append(item) packages = sorted(packages, key = lambda x: (x.get('sn'), x.get('price'))) return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages}) def authCallback(request, gateway): try: state = UserAuthState.decode(str(request.GET.get('payload'))) # type: UserAuthState if not state.is_valid(): return ErrorResponseRedirect(error = cn(u'网络异常,请重新扫码(10000)')) if state.by == UserAuthState.BY.AGENT: source = Agent.objects(id = str(state.agentId)).get() # type: Agent group_id = MyUser.groupId.default dealer = None else: dev = Device.get_dev(state.devNo) # type: DeviceDict if not dev: return ErrorResponseRedirect(error = u'该设备未开通网络支付,请投币或者联系客服(1006)') source = dealer = dev.owner if not dealer: return ErrorResponseRedirect(error = u'该设备未开通网络支付,请投币或者联系客服(1007)') group_id = dev.groupId # 配置平台的代理商ID必定配置自定义公众号, 否则扫码客户无法知道平台代理商是谁 product_agent = get_user_manager_agent(source) if str(product_agent.id) != state.productAgentId: return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10004)') if gateway == AppPlatformType.ALIPAY: auth_bridge = get_ali_auth_bridge(source = product_agent, app_type = APP_TYPE.ALIPAY_AUTH) # type: AlipayAuthBridge else: return ErrorResponseRedirect(error = cn(u'参数错误,请重新扫码(10001)')) auth_code = request.GET.get(auth_bridge.auth_code_key) if not auth_code: return ErrorResponseRedirect(error = cn(u'参数错误,请重新扫码(10002)')) user_info = auth_bridge.get_user_info(auth_code = auth_code) open_id = user_info.pop('openId') user = MyUser.get_or_create( app_platform_type = auth_bridge.gateway_type, open_id = open_id, group_id = group_id, authAppId = auth_bridge.appid, agentId = state.agentId, productAgentId = state.productAgentId, payOpenIdMap = { auth_bridge.bound_openid_key: BoundOpenInfo(openId = open_id) }, **user_info) if state.by == UserAuthState.BY.AGENT: response = FrontEndResponseRedirect(state.href) else: response = get_homepage_response(gateway, user, dev, state.chargeIndex if state.chargeIndex else '', product_agent) return response_with_login(request, user, response) except AliException as e: logger.error(repr(e)) return ErrorResponseRedirect(error = cn(e.errMsg)) @error_tolerate(nil = u"获取消费详情失败", logger = logger) @permission_required(ROLE.myuser) def getConsumeRecord(request): """ 获取用户的单一的 消费订单记录 :param request: :return: """ recordId = request.GET.get("id", None) cardTicketId = request.GET.get('cardTicketId', None) # 这个接口是同时 查询虚拟卡消费记录 以及用户的直接消费记录 的入口 if not any([recordId, cardTicketId]): return JsonErrorResponse(description = u'参数错误,请刷新后再试') if recordId: ownerId = request.GET.get('ownerId', None) if ownerId: record = ClientConsumeModelProxy.get_one(shard_filter = {'ownerId': ownerId}, id = recordId) # type: ConsumeRecord else: record = ConsumeRecord.objects(id = recordId).first() else: record = VCardConsumeRecord.objects(id = cardTicketId).first() # type: VCardConsumeRecord if not record: return JsonErrorResponse(description = u"未查询到相应订单,请刷新页面重试") payload = record.to_user_detail() try: agentId = request.user.productAgentId agent = Agent.objects.get(id = agentId) except Exception as e: logger.exception(e) agent = None if payload.get("actualNeedTime"): elecKeys = [_key for _key in payload.keys() if _key.startswith("elec") or _key.endswith("elec")] for _elecKey in elecKeys: payload.pop(_elecKey, None) if not agent or 'show_elec_data_for_user' not in agent.features: payload.pop('elec', None) payload.pop('needElec', None) if agent and 'hide_time_data_for_user' in agent.features: payload.pop("leftTime", None) payload.pop("duration", None) payload = UserConsumeFilter(record.owner, payload).filter() return JsonOkResponse(payload = payload) @permission_required(ROLE.myuser) def asynTransactionRecord(request): # type: (WSGIRequest)->JsonResponse """ 用户消费记录 :param request: :return: JsonResponse """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) startTime = request.GET.get('startTime', Const.QUERY_START_DATE) endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d')) dataList = [] if 'cardTicketId' in request.GET and request.GET.get('cardTicketId'): records = VCardConsumeRecord.objects.filter(cardId = request.GET.get('cardTicketId')).order_by('-dateTimeAdded') total = records.count() for rcd in records.paginate(pageIndex, pageSize): dataList.append(rcd.summary) else: dealer_ids = MyUser.get_dealer_ids(openId = request.user.openId, productAgentId = request.user.productAgentId) if len(dealer_ids) > 0: records = ClientConsumeModelProxy.get_data_list( ownerId__in = dealer_ids, startTime = startTime, endTime = endTime, openId = request.user.openId, isNormal = True, hint = [('openId', 1), ('dateTimeAdded', -1)]) # type: CustomQuerySet total = records.count() for rcd in records.paginate(pageIndex, pageSize): dataList.append(rcd.summary) else: total = 0 return JsonResponse( { 'result': 1, 'description': '', 'payload': {'total': total, 'dataList': dataList} }) @permission_required(ROLE.myuser) def getChargeRecordDetail(request): # type: (WSGIRequest)->JsonResponse """ 用户充值详细记录 :param request: :return: JsonResponse """ _id = str(request.GET.get('id')) ownerId = request.GET.get('ownerId') record = ClientRechargeModelProxy.get_one(shard_filter = {'ownerId': ownerId}, id = _id) # type: RechargeRecord if not record: return JsonResponse({'result': 1, 'description': '', 'payload': {}}) payload = { 'createdTime': record.dateTimeAdded, 'orderNo': record.orderNo, 'amount': record.my_amount, 'groupName': record.groupName, 'groupNumber': record.groupNumber, 'address': record.address, 'logicalCode': record.logicalCode, 'devTypeName': record.dev_type_name, 'via': record.via, 'ownerId': record.ownerId } payload.update(record.extra_detail_info) return JsonResponse( { 'result': 1, 'description': '', 'payload': payload } ) @permission_required(ROLE.myuser) def hybridStartAction(request): """ 此处有红包链接, 可以判断出往下走的流程是拉起支付还是直接启动 """ payload = json.loads(request.body) urlId = payload.get('urlId') dev = Device.get_dev(payload['devNo']) if not dev: return JsonErrorResponse(description= '设备参数缺失, 请重试') if not urlId: return JsonErrorResponse(description='传入参数有误, 请重试') url = payload.pop('url', None) payload = { "packageId": payload['packageId'], "groupId": dev.groupId, "devNo": dev['devNo'], "logicalCode": dev['logicalCode'], "openId": payload['openId'], "attachParas": payload['attachParas'] } serviceCache.set('urlId_{}'.format(urlId), payload) return JsonResponse( { 'result': 1, 'description': '', 'payload': {'url': url} } ) @permission_required(ROLE.myuser) def getHybridStartActionInfo(request): """ 返回缓存的参数 直接拉起支付 """ payload = json.loads(request.body) urlId = payload.get('mktId') openId = request.user.openId redpack = Redpack.objects.filter(openId=openId, urlId=urlId).first() if redpack: if redpack.taskStatus != redpack.Result.FINISHED: try: # 去查询 ApiRequest = json.loads(redpack.extra.get('ApiRequest', '')) clicklink = ApiRequest['Seatbid'][0]['Bid'][0]['Ads'][0]['Trackers']['Imps'][0] adid = ApiRequest['Seatbid'][0]['Bid'][0]['Ads'][0]['Id'] from apps.thirdparties.aliyun import AlipayYunMaV3 resp = AlipayYunMaV3().query_task_status( clicklink=clicklink, openId=openId, adid=adid, ) if resp.body.success and resp.body.result.success: redpack = Redpack.take_effect(openId=openId, urlId=urlId, **{'ApiResult': json.dumps(resp.body.result.to_map(), ensure_ascii=False)}) RedpackBuilder._set_alipay_key(openId, redpack.factoryCode, urlId, redpack.money.mongo_amount, showType=redpack.showType) else: pass except: import traceback logger.error(traceback.format_exc()) else: pass if redpack.taskStatus == redpack.Result.FINISHED: cacheInfo = serviceCache.get('urlId_{}'.format(urlId)) serviceCache.delete('urlId_{}'.format(urlId)) if urlId and cacheInfo: logicalCode = cacheInfo['logicalCode'] attachParas = cacheInfo['attachParas'] device = Device.get_dev_by_l(logicalCode) if "isTempPackage" in attachParas and attachParas['isTempPackage'] is True: washConfig = device["tempWashConfig"] else: washConfig = device["washConfig"] package = washConfig.get(cacheInfo['packageId']) if not package: payload = { "startAction": False, "logicalCode": logicalCode } else: showInfo = { 'goodsInfo': { 'name': '{}, {}'.format(device.majorDeviceType, device.logicalCode), 'port': attachParas.get('chargeIndex'), }, 'packageInfo': { 'name': '{}{}'.format(package.get('time', ''), package.get('unit', '')), 'coins': package['coins'], 'price': package['price'] }, 'redPackInfo': { 'price': min(redpack.money.amount, package['price']), # 'coins': Redpack.pre_deducted_coins(str(redpack.id), package), }, # 'checkoutInfo': { # 'price': (RMB(package['price']) - redpack.money).mongo_amount, # 'coins': RMB(package['coins'] - Redpack.pre_deducted_coins(str(redpack.id), package)).mongo_amount, # }, } attachParas['redpackId'] = str(redpack.id) payload = { "packageId": cacheInfo['packageId'], "groupId": cacheInfo['groupId'], "devNo": cacheInfo['devNo'], "logicalCode": logicalCode, "openId": cacheInfo['openId'], "attachParas": attachParas, "startAction": True, 'showInfo': showInfo } else: payload = { "startAction": False, "logicalCode": redpack.logicalCode } return JsonResponse( { 'result': 1, 'description': '', 'payload': payload } ) else: return JsonResponse( { 'result': 1, 'description': '', 'payload': {'startAction': False} } ) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def submitFeedback(request): # type: (WSGIRequest)->JsonResponse """ 用户提交反馈 :param request: :return: """ openId = request.user.openId with memcache_lock(key="{openId}.submitFeedBack".format(openId=openId), value='1', expire=60) as acquired: if acquired: try: payload = feedbackSchema(json.loads(request.body)) except MultipleInvalid as e: logger.exception(e) return JsonErrorResponse(description = u"信息不完整,请补充信息或尝试重新扫码") dev = Device.get_dev_by_logicalCode(payload['detailInfo']['logicalCode']) # type: DeviceDict if not dev: return JsonErrorResponse(description = u"当前设备不存在,请重新扫码") if not dev.is_registered: return JsonErrorResponse(description = u'当前设备已经被运营商解绑定(1001)') group = dev.group # type: GroupDict if group is None: logger.error('[submitFeedback] failed to get group, device\'s logicalCode=%s groupId=%s' % (dev['logicalCode'], dev['groupId'])) return JsonErrorResponse(description = u"当前设备已经被运营商解绑定(1002)") feedbackPayload = { 'openId': openId, 'ownerId': dev.ownerId, 'nickname': request.user.nickname, 'description': payload['description'], 'phone': payload['phone'], 'feedType': payload['feedType'], 'imgList': payload['imgList'], 'isRead': True } detail_info = payload.pop('detailInfo') if payload['feedType'] == 'netpay': detail_info = { 'orderNo': detail_info['orderNo'] } detail_info.update(dev.identity_info) feedbackPayload['detailInfo'] = detail_info feedback = FeedBack(**feedbackPayload).save() if bool(payload.get('orderNo')) and not feedbackPayload['feedType'] == 'fault': order = ConsumeRecord.objects( ownerId = dev.ownerId, orderNo = feedbackPayload['consumeRecordOrderNo'] ).first() # type: ConsumeRecord if not order: return JsonErrorResponse(description = u'您选择的订单不存在,请重新选择。') if order.feedbackId: return JsonErrorResponse(description = u'您选择的订单已有投诉反馈,请等待设备运营商处理。') updated = order.update(feedbackId = ObjectId(feedback.id)) if not updated: logger.info('failed to update ConsumeRecord feedbackId = %s' % (str(feedback.id),)) dealer = Dealer.objects(id = str(dev['ownerId'])).first() if dealer is None: logger.error('[submitFeedback] cannot get dealer by id = %s' % (str(dev['ownerId']),)) return JsonOkResponse() agent = Agent.objects(id = str(dealer.agentId)).first() if agent is None: logger.error('[submitFeedback] cannot get agent by id = %s' % (str(dealer.agentId),)) return JsonOkResponse() if payload['feedType'] == 'fault': msgType = u'设备故障' else: msgType = u'订单投诉' msg = u'尊敬的%s用户%s,您的客户刚才给您报告了一条【%s】的信息,请您登录后台,从【用户反馈】查看详情' \ % (agent.productName, dealer.nickname, msgType) task_caller('report_feedback_to_dealer_via_wechat', dealerId = str(dealer.id), msg = msg, nickname = request.user.nickname, feedbackTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) return JsonOkResponse() else: return JsonErrorResponse(description = u'您已正在提交') @error_tolerate(nil = JsonErrorResponse(description = u'获取反馈失败'), logger = logger) @permission_required(ROLE.myuser) def getFeedbackList(request): # type: (WSGIRequest)->JsonResponse """ 用户提交反馈 :param request: :return: """ openId = request.user.openId pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) dealerIds = MyUser.get_dealer_ids(openId, request.user.productAgentId) feedbacks = FeedBack.objects(openId = openId, ownerId__in = dealerIds) \ .order_by('-createTime') \ .paginate(pageIndex, pageSize) # type: CustomQuerySet total = feedbacks.count() items = [] for item in feedbacks: # type: FeedBack items.append(item.summary) return JsonResponse( { 'result': 1, 'description': "", 'payload': { 'total': total, 'dataList': items } } ) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def getFeedbackDetail(request): id_ = request.GET.get('id') feedback = FeedBack.objects(id = id_).first() # type: FeedBack if not feedback: return JsonErrorResponse(description = u'没有找到反馈单,请刷新试试') else: if not feedback.isRead: feedback.isRead = True feedback.save() return JsonResponse({'result': 1, 'description': '', 'payload': feedback.detail}) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def getFeedbackConfigs(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ logicalCode = request.GET.get('logicalCode') # if not logicalCode: # return JsonErrorResponse(description = u'找不到设备编号') dev = Device.get_dev_by_l(logicalCode) or dict() #: 暂时只是显示充电桩的端口 devTypeName = dev.get("devType", dict()).get("name", "") if re.match(ur"充电桩", devTypeName): payload = {"port": [str(_) for _ in range(1, 21)]} else: payload = {} return JsonResponse({'result': 1, 'description': '', 'payload': payload}) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def getConsumeRecordsForFeedback(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) skip = (pageIndex - 1) * pageSize logicalCode = request.GET.get('logicalCode', None) if logicalCode: device = Device.get_dev_by_logicalCode(logicalCode) if not device: return JsonErrorResponse(description = u'设备不存在,请重新扫码') ownerIds = [device.ownerId] else: ownerIds = MyUser.get_dealer_ids(request.user.openId, request.user.productAgentId) records = ConsumeRecord.objects( ownerId__in = ownerIds, openId = request.user.openId, dateTimeAdded__gte = (datetime.datetime.now() - datetime.timedelta(days = 30)), feedbackId__exists = 0).order_by("-dateTimeAdded") # type: CustomQuerySet dataList = [] for record in records.skip(skip).limit(pageSize): # type: ConsumeRecord dataList.append(record.info_for_feedback) return JsonResponse( { 'result': 1, 'description': '', 'payload': {'total': records.count(), 'dataList': dataList} }) def getNearbyDevicesFromDB(lng, lat, pageIndex, pageSize, maxDistance, agentId, devTypeName, groupId = None): def hav(theta): s = sin(theta / 2) return s * s def get_distance_hav(lat0, lng0, lat1, lng1): if lat1 == 360 or lng1 == 360: return -1 EARTH_RADIUS = 6371000 lat0 = radians(lat0) lat1 = radians(lat1) lng0 = radians(lng0) lng1 = radians(lng1) dlng = fabs(lng0 - lng1) dlat = fabs(lat0 - lat1) h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng) return int(2 * EARTH_RADIUS * asin(sqrt(h))) def formatDeviceInfo(dev, devTypeName): # type: (DeviceDict, basestring)->Optional[Dict] logger.debug('try to format device info.'.format(dev.logicalCode, dev.devNo)) distance = get_distance_hav(lat, lng, float(dev['lat']), float(dev['lng'])) group = Group.get_group(dev['groupId']) if group is None: return None package = [ { 'name': rule.get('name', ''), 'coins': rule['coins'], 'price': rule.get('price', rule['coins']), 'time': rule.get('time', 20), 'unit': rule.get('unit', u'分钟') } for packageId, rule in dev['washConfig'].items()] return { 'devNo': dev.devNo, 'type': devTypeName, 'logicalCode': dev.logicalCode, 'groupName': group['groupName'], 'groupNumber': dev['groupNumber'], 'groupId': dev.groupId, 'address': group['address'], 'online': dev.online, 'status': dev.status, 'signal': dev.signal, 'remarks': dev['remarks'], 'distance': distance, 'lng': float(dev.lng), 'lat': float(dev.lat), 'often': False, 'beingUsed': False, 'package': package, 'devTypeCode': dev.devType['code'] } if not agentId: logger.error('agent is null.') return { 'total': 0, 'items': [] } dealers = Dealer.get_dealers(agentId) if not dealers: return { 'total': 0, 'items': [] } if groupId: devices = Device.get_collection().find({'groupId': groupId}) else: if devTypeName: devices = Device.get_collection().find( { 'ownerId': {'$in': dealers}, '$where': 'this.devType != null && this.devType.name == "%s"' % devTypeName, 'isFault': False, 'location': { '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]}, '$maxDistance': maxDistance}}}) else: devices = Device.get_collection().find( { 'ownerId': {'$in': dealers}, 'isFault': False, 'location': { '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]}, '$maxDistance': maxDistance}}}) items = [] for dev in devices: dev = DeviceDict(dev) # type: DeviceDict if dev is None or not dev.lbs: continue try: devInfo = formatDeviceInfo(dev, dev.devType.get('name', '')) # type: Dict except Exception as e: logger.exception(e) continue if devInfo is None: continue items.append(devInfo) return_items = items[(pageIndex - 1) * pageSize:pageIndex * pageSize] dev_ctrl_map = Device.get_many_dev_control_cache([item['devNo'] for item in return_items]) for item in return_items: # 换电柜的端口显示可用电池数量 if item['devTypeCode'] in [Const.DEVICE_TYPE_CODE_CHARGING_AQKJ, Const.DEVICE_TYPE_CODE_CHARGING_AQKJ_NEW]: dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {}) item["canUseBattery"] = dev_ctrl_info.get("canUseBattery", 0) elif Const.DEVICE_TYPE_CODE_CHARGING_KYXN <= item['devTypeCode'] < Const.DEVICE_TYPE_CODE_WASHER_BASE: dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {}) item['allPorts'] = dev_ctrl_info.get('allPorts', 10) item['usedPorts'] = dev_ctrl_info.get('usedPorts', 0) item['usePorts'] = dev_ctrl_info.get('usePorts', 10) if 'power' in dev_ctrl_info: item['power'] = dev_ctrl_info['power'] payload = { 'total': len(items), 'items': return_items } return payload @permission_required(ROLE.myuser) def getNearbyGroups(request): # type: (WSGIRequest)->JsonResponse try: lng = float(request.GET.get('lng')) lat = float(request.GET.get('lat')) maxDistance = int(request.GET.get('distance', 3000)) logger.debug('now location. lat = %s; lng = %s' % (lat, lng)) if maxDistance > Const.NEAR_BY_MAX_DISTANCE: maxDistance = Const.NEAR_BY_MAX_DISTANCE if lng == 360 or lat == 360 or isnan(lng) or isnan(lat): return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'}) payload = getNearbyDevicesFromDB(lng, lat, 1, 1000, maxDistance, request.user.agentId, request.GET.get('type', None)) groupDict = {} for dev in payload['items']: if groupDict.has_key(dev['groupId']): groupDict[dev['groupId']]['allDevices'] += 1 if dev['status'] == Const.DEV_WORK_STATUS_IDLE: groupDict[dev['groupId']]['idleDevices'] += 1 else: newValue = { 'distance': dev['distance'], 'lng': float(dev['lng']), 'lat': float(dev['lat']), 'address': dev['address'], 'groupName': dev['groupName'], 'groupId': dev['groupId'], 'allDevices': 1, 'idleDevices': 1 if dev['status'] == Const.DEV_WORK_STATUS_IDLE else 0 } groupDict[dev['groupId']] = newValue payload = {'total': len(groupDict.values()), 'items': groupDict.values()} return JsonResponse({'result': 1, 'description': '', 'payload': payload}) except Exception as e: logger.exception(e) return JsonResponse({'result': 0, 'description': u'获取附近设备失败'}) @permission_required(ROLE.myuser) def getNearbyDevices(request): # type: (WSGIRequest)->JsonResponse try: groupId = request.GET.get('groupId', None) lng = float(request.GET.get('lng')) lat = float(request.GET.get('lat')) maxDistance = int(request.GET.get('distance', 3000)) logger.debug('now location. lat = %s; lng = %s' % (lat, lng)) if maxDistance > Const.NEAR_BY_MAX_DISTANCE: maxDistance = Const.NEAR_BY_MAX_DISTANCE if lng == 360 or lat == 360 or isnan(lng) or isnan(lat): return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'}) pageIndex = int(request.GET.get('pageIndex', 0)) pageSize = int(request.GET.get('pageSize', 10)) payload = getNearbyDevicesFromDB(lng, lat, pageIndex, pageSize, maxDistance, getattr(request.user, 'productAgentId', ''), request.GET.get('type', None), groupId) return JsonResponse({'result': 1, 'description': '', 'payload': payload}) except Exception as e: logger.exception(e) return JsonResponse({'result': 0, 'description': u'获取附近设备失败'}) @permission_required(ROLE.manager) def getEndUserDetailList(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ mid = str(request.user.id) pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) searchKey = request.GET.get('searchKey', None) agentIds = [str(agent['_id']) for agent in Agent.get_collection().find({'managerId': mid}, {'_id': True})] dealerIds = [str(dealer['_id']) for dealer in Dealer.get_collection().find({'agentId': {'$in': agentIds}}, {'_id': True})] groupIds = [str(group['_id']) for group in Group.get_collection().find({'ownerId': {'$in': dealerIds}}, {'_id': True})] skip = (pageIndex - 1) * pageSize dataList = [] users = MyUser.search(searchKey).filter(groupId__in = groupIds) for u in users.skip(skip).limit(pageSize): item = { 'id': str(u.id), 'nickname': u.nickname, 'openId': u.openId, 'sex': u.sex, 'country': u.country, 'province': u.province, 'city': u.city, 'balance': u.balance, 'groupName': '', 'gateway': u.gateway } group = Group.get_group(u.groupId) if group: item.update({'groupName': group.get('groupName')}) dataList.append(item) total = users.count() return JsonResponse({ 'result': 1, 'description': '', 'payload': { 'total': total, 'dataList': dataList } }) @error_tolerate(nil = JsonErrorResponse(description = u'获取消费记录失败'), logger = logger) @permission_required(ROLE.manager) def getEndUserConsumeRecords(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) userId = request.GET.get('id', None) if not userId: return JsonErrorResponse(description = u'用户id为空') else: startTime = request.GET.get('startTime', Const.QUERY_START_DATE) endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d')) user = MyUser.objects(id = str(userId)).get() group = Group.get_group(user.groupId) cursor = ClientConsumeModelProxy.get_data_list( startTime = startTime, endTime = endTime, ownerId = group['ownerId'], openId = user.openId, groupId = user.groupId) # type: QuerySetProxy total = cursor.count() records = [ { "orderNo": r.orderNo, "time": r.time, "coins": r.coin, "devNo": r.devNo, "devType": r.dev_type_name, "groupName": r.groupName } for r in cursor.paginate(pageIndex, pageSize) ] return JsonResponse({'result': 1, 'description': '', 'payload': {'total': total, 'dataList': records}}) @error_tolerate(nil = JsonErrorResponse(description = u'获取充值记录失败'), logger = logger) @permission_required(ROLE.manager) def getEndUserRechargeRecords(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) userId = request.GET.get('id', None) if not userId: return JsonErrorResponse(description = u'用户id为空') else: startTime = request.GET.get('startTime', Const.QUERY_START_DATE) endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d')) user = MyUser.objects(id = str(userId)).get() group = Group.get_group(user.groupId) cursor = ClientRechargeModelProxy.get_data_list(startTime = startTime, endTime = endTime, ownerId = group['ownerId'], openId = user.openId, groupId = user.groupId, hint = [('openId', 1)]) # type: QuerySetProxy total = cursor.count() records = [ { "orderNo": r.orderNo, "time": r.to_js_timestamp(r.dateTimeAdded), "money": r.money, "coins": r.coins, "devNo": r.devNo, "devType": r.dev_type_name, "groupName": r.groupName, "gateway": r.gateway } for r in cursor.paginate(pageIndex, pageSize)] return JsonResponse({'result': 1, 'description': '', 'payload': {'total': total, 'dataList': records}}) def wxconfig(request): url = request.GET.get('href') if not url: return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}}) current_user = request.user # type: MyUser wxconfig = get_wx_config(current_user, url) return JsonOkResponse(payload = {'wxconfig': wxconfig}) # 用于前台界面时间计时用 @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def countDown(request): # type: (WSGIRequest)->JsonResponse openId = str(request.user.openId) devNo = str(request.GET.get('devNo', '')) portStr = request.GET.get('chargeIndex', None) if portStr is not None: port = int(portStr) else: port = None dev = Device.get_dev(devNo) logicalCode = dev['logicalCode'] group = Group.get_group(dev['groupId']) devType = dev.get('devType') dealer = Dealer.objects.get(id = dev['ownerId']) agent = Agent.objects.get(id = dealer.agentId) # 判断是否是摩丫丫的设备 判断是否是烘干机设备 if (agent.features != [] and 'moyaya666' in agent.features) or ( dealer.features != [] and 'dryer' in dealer.features): last_time_cache = serviceCache.get(user_last_time_use_ended_cache(openId, logicalCode), '') if last_time_cache == '': serviceCache.set(user_last_time_use_ended_cache(openId, logicalCode), datetime.datetime.now(), 3600) elif last_time_cache != '': if datetime.datetime.now() > last_time_cache + datetime.timedelta(hours = 1): serviceCache.set(user_last_time_use_ended_cache(openId, logicalCode), datetime.datetime.now(), 3600) ctrInfo = Device.get_dev_control_cache(devNo) if ctrInfo: lastOpenId = ctrInfo.get('openId', '') else: lastOpenId = '' box = ActionDeviceBuilder.create_action_device(dev) try: response = box.count_down(request, dev, agent, group, devType, lastOpenId, port) if response is None: return JsonErrorResponse(description = u'系统不支持此操作哦') return response except ServiceException as e: logger.error('get count_down error=%s' % e.result['description'].encode('utf-8')) return JsonErrorResponse(description = e.result['description']) except Exception, e: logger.error('device(%s) get count_down error=%s' % (devNo, e)) return JsonErrorResponse(description = u'系统异常,请重新刷新页面') # 只要有回调过来,说明一定是登录成功了,就直接送金币,然后跳转到控制页面即可。暂时不考虑authCode的鉴定以防止伪造URL。 @error_tolerate(nil = ErrorResponseRedirect(error = cn(u'系统开小差了哦,真是抱歉呀,请您刷新页面试试哦'))) @permission_required(ROLE.myuser) def huaweiAccess(request): # type: (WSGIRequest)->HttpResponseRedirect openId = request.user.openId devNo = request.COOKIES.get('devNo', None) groupId = request.COOKIES.get('groupId', None) if openId is None or devNo is None or groupId is None: return ErrorResponseRedirect(error = cn(u'系统开小差了哦,真是抱歉呀,请您重新扫码试试哦')) dev = Device.get_dev(devNo) ads = AdRecord.objects.filter(openId = openId, adId = 0) if ads.count() > 0: return NetDeviceResponseRedirect(l = dev.logicalCode) newRcd = AdRecord(converted = True, adId = 0, openId = openId, groupId = groupId, devNo = devNo) newRcd.save() user = MyUser.objects.get(openId = openId, groupId = groupId) user.balance += 1 user.save() return NetDeviceResponseRedirect(l = dev.logicalCode) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) def getCardStatus(request): # type: (WSGIRequest)->JsonResponse lc = request.GET.get('logicalCode') devNo = Device.get_devNo_by_logicalCode(lc) cardInfo = Card.get_dev_cur_card(devNo) if cardInfo is None: return JsonResponse( { "result": 0, "description": u'刷卡区没有检测到卡,请您先把卡放到读卡区,这样才能开始充值哦', "para": None } ) return JsonResponse( { "result": 1, "description": None, "para": { "ready": True, "cardId": cardInfo['cardNo'], "money": cardInfo["money"] } } ) @permission_required(ROLE.myuser) def pollBtInfo(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) device = Device.get_dev_by_logicalCode(payload.get('logicalCode')) if not device: return JsonResponse({'result': 0, 'description': u'设备不存在', 'payload': {}}) code = Const.BT_DEVICE_TYPE_CODE_MAP[int(payload.get('code'))] actionBox = ActionBtDeviceBuilder.create(code, device) major = int(payload.get('major')) minor = int(payload.get('minor')) notify_payload = payload.get('payload', None) if not notify_payload: notify_payload = payload.get('advertisData', None) if notify_payload: result, description = actionBox.poll_notify(notify_payload, **{'major': major, 'minor': minor}) return JsonResponse({'result': result, 'description': description, 'payload': {}}) else: return JsonResponse({'result': 1, 'description': 'empty', 'payload': {}}) @error_tolerate(nil=JsonErrorResponse(description=u'显示用户信息错误'), logger=logger) @permission_required(ROLE.myuser) @request_limit_by_user(operation='userInfo', limit=50, logger=logger) def userInfo(request): # type: (WSGIRequest)->JsonResponse logger.info('receive userInfo') user = request.user # type: MyUser agentId = user.agentId payload = { 'nickname': user.nickname, 'balance': user.total_balance, 'agentId': agentId, 'domain': settings.MY_DOMAIN, 'avatarUrl': request.user.avatar if request.user.avatar else settings.DEFAULT_AVATAR_URL, 'noVirtualCard': False, 'noRechargeCard': False, 'noRecharge': False, 'userId': '' } agent = Agent.objects(id = agentId).first() # type: Optional[Agent] if agent: payload['agentFeatures'] = agent.features if 'hideRechargeCardForUser' in agent.features: payload.update({'noRechargeCard': True}) # if 'ledgerAfterFinished' in agent.features: # payload.update({ # 'noVirtualCard': True, # 'noRechargeCard': True, # 'noRecharge': True # }) # 校验是否要绑定用户的手机号码 if 'telVerify' in agent.features: needTelVerify = check_user_tel(user) payload.update({ "needTelVerify": needTelVerify }) # 检查是否支持一卡多用 if 'card_multi_use' in agent.features: payload.update({'card_multi_use': True}) user_id = user.user_id if user_id: payload.update({'userId': user_id}) return JsonResponse({'result': 1, 'description': '', 'payload': payload}) @error_tolerate(nil = JsonErrorResponse(description = u'获取组失败'), logger = logger) @permission_required(ROLE.myuser) def getRecentlyGroup(request): # type: (WSGIRequest)->JsonResponse my_product_agent_id = request.user.productAgentId # 是否是查询卡卷 hasCoupon = request.GET.get('hasCoupon', False) openId = request.user.openId rcds = ConsumeRecord.objects.filter(openId = openId, isNormal = True).order_by('-dateTimeAdded') devNoList = list(set([rcd.devNo for rcd in rcds[0:100]])) dataList = [] groupIdList = [] dealerIdList = [] map_dealer_product = {} for devNo in devNoList: dev = Device.get_dev(devNo) if (dev is None) or (not dev.has_key('groupId')): continue group = Group.get_group(dev['groupId']) if not group: continue dealer_id = str(dev['ownerId']) if not dealer_id: logger.error('dealer is null. id = %s' % dealer_id) continue try: dealer = Dealer.objects(id = dealer_id).first() if not dealer: logger.error('dealer is null. id = %s' % dealer_id) continue except Exception as e: logger.error('dealerId = {}; exception = {}'.format(dealer_id, str(e))) if dealer_id not in map_dealer_product: try: product_agent = get_user_manager_agent(dealer) # type:Agent except Exception as e: logger.exception(e) product_agent = None if not product_agent: logger.error('get product agent failure. devNo = {}; dealer id = {}'.format(dev['devNo'], dealer_id)) continue map_dealer_product[dealer_id] = str(product_agent.id) if map_dealer_product[dealer_id] != my_product_agent_id: logger.debug('{} is not equal agent({})'.format(repr(dev), my_product_agent_id)) continue if dev['groupId'] not in groupIdList: if (not group.has_key('address')) or (not group.has_key('groupName')): continue dataList.append({'address': group['address'], 'groupName': group['groupName'], 'groupId': dev['groupId'], 'devType': dev.get('devType', {}).get('name', ''), 'logicalCode': dev['logicalCode'], 'ownerId': dev['ownerId']} ) groupIdList.append(dev['groupId']) dealerIdList.append(dev['ownerId']) if not hasCoupon: return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList), "dataList": dataList}}) # 查询下地址下的已经发布的虚拟卡 dealerIdList = list(set(dealerIdList)) vCards = VirtualCard.objects.filter(ownerId__in = dealerIdList, status = 1) dataList1 = [] for data in dataList: match = False for card in vCards: if data['ownerId'] == card.ownerId and ('*' in card.groupIds or data['groupId'] in card.groupIds): match = True break if match: dataList1.append(data) return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList1), "dataList": dataList1}}) @error_tolerate(nil = JsonErrorResponse(description = u'获取卡列表失败'), logger = logger) @permission_required(ROLE.myuser) def getCardList(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) searchKey = request.GET.get('searchKey', None) openId = request.user.openId agentId = request.user.agentId # zjl user.agentId -> user.productAgentId agent = Agent.objects.get(id = agentId) manager = Manager.objects(id = agent.managerId).get() # zjl delete agent_id_list = [str(item.id) for item in Agent.objects(managerId = str(manager.id))] # zjl delete hideMenu = True if 'hideCardMenu' in agent.features else False skip = (pageIndex - 1) * pageSize cards = Card.objects.filter(openId = openId, # zjl delete agentId__in = agent_id_list).search(searchKey) # zjl delete # cards = Card.objects.filter(openId=openId, # zjl new # agentId=agentId).search(searchKey) # zjl new dataList = [] for card in cards.skip(skip).limit(pageSize): hide = ['orderRecord', 'rechargeRecord', 'backRecord', 'frozen'] if (card.cardType == 'IC' and hideMenu) else [] if card.devNo: dev = Device.get_dev(card.devNo) or dict() devType = dev.get('devType', {}) if devType.has_key('id'): try: devType = DeviceType.objects.get(id = devType['id']) if not devType.supportIcCardcharge: hide.append('cardCharge') except Exception, e: pass # 分以下三种情况处理 # 1 有groupId, 但是没有dealerId, 这个查数据目前没有。 这个情况下dealerId设置为group对应的, 如果没有dealer, 全部清空 # 2 有dealerId, 没有groupId, 这种情况下, 直接取dealer的第一个groupId, 没有全部取空 # 3 两个都没有的情况下, 直接取设备对应的group和dealerId if not card.groupId: if card.dealerId: group = Group.get_default_group(card.dealerId) # type: GroupDict if group: card.groupId = group.groupId else: card.groupId = '' card.dealerId = '' card.save() else: # 不处理. 这个用户自己去绑定 pass else: if not card.dealerId: group = Group.get_group(card.groupId) # type: GroupDict if not group: card.groupId = '' card.dealerId = '' else: card.dealerId = group.ownerId card.save() group = Group.get_group(card.groupId) # type: GroupDict dataList.append( { 'cardId': str(card.id), 'cardNo': card.cardNo, 'cardType': card.cardType, 'cardName': card.cardName, 'phone': card.phone, 'groupId': card.groupId, 'groupName': group.groupName if group else '', 'dealerId': card.dealerId, 'balance': card.balance, 'isHaveBalance': card.isHaveBalance, 'remarks': card.remarks, 'status': card.status, 'frozen': False if card.frozen is None else card.frozen, 'hide': hide, 'boundVirtualCardId': card.boundVirtualCardId } ) total = cards.count() return JsonResponse( { 'result': 1, 'description': '', 'payload': { 'total': total, "dataList": dataList } } ) @error_tolerate(nil = JsonOkResponse(description = u"获取卡信息失败"), logger = logger) @permission_required(ROLE.myuser) def getCard(request): """ 获取单一的卡信息 :param request: :return: """ cardId = request.GET.get("cardId", "") try: card = Card.objects.get(id = cardId) except DoesNotExist: return JsonErrorResponse(description = u"获取卡信息失败,请刷新页面试试") agentId = request.user.agentId agent = Agent.objects.get(id = agentId) hideMenu = True if 'hideCardMenu' in agent.features else False hide = ['orderRecord', 'rechargeRecord', 'backRecord', 'frozen'] if (card.cardType == 'IC' and hideMenu) else [] if card.devNo: dev = Device.get_dev(card.devNo) or dict() devType = dev.get('devType', {}) if devType.has_key('id'): try: devType = DeviceType.objects.get(id = devType['id']) if not devType.supportIcCardcharge: hide.append('cardCharge') except Exception as e: logger.exception(e) group = Group.get_group(card.groupId) data = { 'cardId': str(card.id), 'cardNo': card.cardNo, 'cardType': card.cardType, 'cardName': card.cardName, 'phone': card.phone, 'groupId': card.groupId, 'groupName': group.groupName if group else '', 'dealerId': card.dealerId, 'balance': card.balance, 'isHaveBalance': card.isHaveBalance, 'remarks': card.remarks, 'status': card.status, 'frozen': False if card.frozen is None else card.frozen, 'hide': hide, } return JsonOkResponse(payload = data) @error_tolerate(nil = JsonErrorResponse(description = u"查询卡信息失败"), logger = logger) @permission_required(ROLE.myuser) def queryCard(request): """ 根据前台提供的cardNo 以及 groupId 返回该卡的所有信息 :param request: :return: """ # 获取参数 参数校验 cardNo = request.GET.get("cardNo") groupId = request.GET.get("groupId") if not all([cardNo, groupId]): return JsonErrorResponse(description = u"参数不全,请输入卡号获取扫描设备获取绑定地址") group = Group.get_group(groupId) # type: GroupDict if not group: return JsonErrorResponse(description = u"开卡地址不存在,请重新扫描设备获取绑定地址或联系发卡经销商(1001)") dealer = Dealer.objects(id = str(group.ownerId)).first() # type: Dealer if not dealer: return JsonErrorResponse(description = u"开卡地址不存在,请重新扫描设备获取绑定地址或联系发卡经销商(1002)") agent = Agent.objects(id = str(dealer.agentId)).first() if not agent: return JsonErrorResponse(description = u"代理商不存在,请刷新页面后重试(1001)") productAgent = get_user_manager_agent(agent) if str(productAgent.id) != request.user.productAgentId: return JsonErrorResponse(description = u"不是该平台下的地址,请换个设备编号扫码试试(1001)") # 鉴别卡相应信息 try: card = Card.objects.get(cardNo=cardNo, agentId=str(agent.id)) except DoesNotExist: # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡 dealerBindCard = True if "dealerBindCard" in agent.features else False if dealerBindCard: return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方") return JsonResponse( { "result": 1, "description": u"", "payload": { "cardNo": cardNo, "groupId": group.groupId, "groupName": group.groupName, } } ) # 卡已经被被别人绑定了 if card.openId and card.openId != request.user.openId and card.openId != Const.DEFAULT_CARD_OPENID: return JsonResponse( { "result": ErrorCode.CARD_BIND_BY_OTHER, "description": u"{} 卡片已经被其他用户使用,请检查卡号是否正确或联系相应的经销商".format(cardNo), "payload": {} } ) if group.groupId != card.groupId: card_bind_group = Group.get_group(card.groupId) else: card_bind_group = group if not card_bind_group: card_bind_dealer = None else: card_bind_dealer = Dealer.objects(id = str(card_bind_group.ownerId)).first() # 卡綁定的組和經銷商只要有一個無效, 就走增加的流程 if not card_bind_group or not card_bind_dealer: return JsonResponse( { "result": 1, "description": u"", "payload": { "cardNo": cardNo, "groupId": group.groupId, "groupName": group.groupName, } } ) # 该卡已经被自己绑定 if card.openId and card.openId != Const.DEFAULT_CARD_OPENID: return JsonResponse( { "result": ErrorCode.CARD_BIND_BY_SELF, "description": u"{} 卡片已经存在于您的卡包中,是否进入编辑界面编辑该卡的相应信息".format(cardNo), "payload": { "cardId": str(card.id), "cardNo": cardNo, "cardName": card.cardName, "groupId": card_bind_group.groupId, "groupName": card_bind_group.groupName, "phone": card.phone } } ) # 该卡没有被绑定, 但是经销商信息已经绑定, 直接走绑定流程 if not card.openId or card.openId == Const.DEFAULT_CARD_OPENID: return JsonResponse( { "result": ErrorCode.CARD_FORBID_CHARGE_GROUP, "description": u"该卡已经被经销商录入,是否进入卡绑定界面绑定卡{}".format(cardNo), "payload": { "cardId": str(card.id), "cardNo": cardNo, "cardName": card.cardName, "groupId": card_bind_group.groupId, "groupName": card_bind_group.groupName, "phone": card.phone } } ) @error_tolerate(nil = JsonErrorResponse(description = u"添加卡失败"), logger = logger) @permission_required(ROLE.myuser) def addCard(request): """ 添加卡 之前已经做过校验了 :param request: :return: """ payload = json.loads(request.body) cardNo = payload.get("cardNo") cardName = payload.get("cardName") phone = payload.get("phone") logicalCode = payload.get("logicalCode") cardId = payload.get("cardId") cardType = payload.get('cardType', '') # 参数校验 if cardNo.isdigit(): cardNo = str(int(cardNo)) if not Card.check_card_no(cardNo): return JsonErrorResponse(description = u"激活失败,无效的卡号,卡号长度不能超过32位") if cardName and not check_entity_name(cardName): return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)") if phone and not check_phone_number(phone): return JsonErrorResponse(description = u"手机号码输入错误") # 绑定设备和经销商的关系校验 device = Device.get_dev_by_l(logicalCode) if not device: return JsonErrorResponse(description = u"错误的设备二维码,请重新扫描设备二维码") group = Group.get_group(device.get("groupId")) if not group: return JsonErrorResponse(description = u"未找到设备组,请刷新页面重试") dealer = Dealer.objects.filter(id = group.get("ownerId")).first() if not dealer: return JsonErrorResponse(description = u"未找到经销商,请刷新页面重试") agent = Agent.objects.filter(id = str(dealer.agentId)).first() if not agent: return JsonErrorResponse(description = u"未找到代理商,请刷新页面重试") productAgent = get_user_manager_agent(agent) if str(productAgent.id) != request.user.productAgentId: return JsonErrorResponse(description = u"不是该平台下的用户,不能绑定该平台的实体卡") if not cardId: # 是否允许办理多张实体卡 onlyOneCard = True if "onlyOneCard" in agent.features and not request.user.many_cards else False if onlyOneCard and request.user.cards_num > 0: return JsonErrorResponse(description = u"您只能绑定一张实体卡,请联系经销商了解相应的规则") # 卡存在校验 try: card = Card.objects.get(Q(agentId=str(agent.id)) | Q(agentId=str(agent.id)), cardNo=cardNo) except DoesNotExist: # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡 dealerBindCard = True if "dealerBindCard" in agent.features else False if dealerBindCard: return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方") card = Card( cardNo = cardNo, openId = request.user.openId, cardName = cardName, groupId = device.get("groupId"), phone = phone, nickName = request.user.nickname, agentId = str(agent.id), dealerId = str(dealer.id), productAgentId = request.user.productAgentId, managerialAppId = request.user.managerialAppId, managerialOpenId = request.user.managerialOpenId, cardType = cardType ) card.save() return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)}) # 优先判断dealerId是否允许,在判断绑定关系 if card.dealerId and card.dealerId != device.get("ownerId"): return JsonErrorResponse(description = u"该卡已被其他经销商录入,请确认卡号无误后联系您的发卡经销商") if card.openId and card.openId != request.user.openId and card.openId != Const.DEFAULT_CARD_OPENID: return JsonErrorResponse(description = u"该卡已被其他用户绑定,请确认卡号无误后联系您的发卡经销商") card.openId = request.user.openId card.cardName = cardName card.phone = phone card.nickName = request.user.nickname card.groupId = device.get("groupId") card.dealerId = str(dealer.id) card.agentId = str(agent.id) card.productAgentId = request.user.productAgentId card.managerialAppId = request.user.managerialAppId card.managerialOpenId = request.user.managerialOpenId card.save() return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)}) # 1003 ErrorCode 过来的 else: try: card = Card.objects.get(id = cardId) except DoesNotExist: return JsonErrorResponse(description = u"未找到实体卡,请刷新页面后重试") card.openId = request.user.openId card.groupId = group.groupId card.dealerId = group.ownerId card.agentId = str(agent.id) if cardName != card.cardName: card.cardName = cardName if phone != card.phone: card.phone = phone card.nickName = request.user.nickname card.productAgentId = request.user.productAgentId card.managerialAppId = request.user.managerialAppId card.managerialOpenId = request.user.managerialOpenId card.save() return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)}) @error_tolerate(nil = JsonErrorResponse(description = u"编辑卡失败"), logger = logger) @permission_required(ROLE.myuser) def editCard(request): """ 卡编辑 :param request: :return: """ payload = json.loads(request.body) cardName = payload.get("cardName") if cardName and not check_entity_name(cardName): return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)") phone = payload.get("phone") if phone and not check_phone_number(phone): return JsonErrorResponse(description = u"手机号码输入错误") card = Card.objects(id = str(payload.get("cardId"))).first() if not card: return JsonErrorResponse(description = u"未找到可编辑的卡片,请刷新页面重试") card.cardName = cardName card.phone = phone card.save() return JsonOkResponse(description = u"修改成功") @error_tolerate(nil = JsonErrorResponse(description = u"补卡失败"), logger = logger) @permission_required(ROLE.myuser) def swapCardNo(request): """ 用户补卡 其实就是换个卡号 :param request: :return: """ payload = json.loads(request.body) cardNo = payload.get("cardNo", "") cardId = payload.get("cardId") # 卡号前置去0 if cardNo.isdigit(): cardNo = str(int(cardNo)) openId = str(request.user.openId) if not Card.check_card_no(cardNo): return JsonErrorResponse(description = u"无效的卡号,卡号长度不能超过32位") try: oldCard = Card.objects.get(id = cardId) except DoesNotExist: return JsonErrorResponse(description = u"查询旧卡失败") # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡 agent = Agent.objects.get(id=oldCard.productAgentId) dealerBindCard = True if "dealerBindCard" in agent.features else False if dealerBindCard: return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方") if oldCard.cardNo == cardNo: return JsonErrorResponse(description = u"卡号一致无需修改") if oldCard.openId != openId: return JsonErrorResponse(description = u"不是您的卡号,无权修改") checkStatus, checkMsg = Card.check_swap_card_no(cardNo, oldCard.dealerId, oldCard.agentId) if not checkStatus: return JsonErrorResponse(description = checkMsg) # 直接将卡号更新掉,然后新建一条换卡记录 oldCard.update(cardNo = cardNo) SwapCardRecord.add_record(oldCard.cardNo, cardNo, oldCard.agentId, str(request.user.id)) return JsonOkResponse(description = u"卡号修改成功") @error_tolerate(nil = JsonErrorResponse(description = u"绑定失败"), logger = logger) def bindCard(request): """ 用户通过经销商分享的链接进来绑定实体卡 :param request: :return: """ openId = request.user.openId payload = json.loads(request.body) cardName = payload.get("cardName") if not check_entity_name(cardName): return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)") phone = payload.get("phone") if not check_phone_number(phone): return JsonErrorResponse(description = u"手机号码输入错误") cardId = payload.get('cardId') card = Card.objects(id = cardId).first() # type: Card if not card: return JsonErrorResponse(u"该实体卡不存在,请联系经销商获取正确的绑定二维码") group = Group.get_group(card.groupId) # type: GroupDict if not group: return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1001)') dealer = Dealer.objects(id = str(group.ownerId)).first() # type: Dealer if not dealer: return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1002)') if str(dealer.id) != card.dealerId: return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1003)') agent = Agent.objects(id = str(dealer.agentId)).first() if not agent: return JsonErrorResponse(description = u'代理商不存在,请刷新页面后重试(1002)') productAgent = get_user_manager_agent(agent) if str(productAgent.id) != request.user.productAgentId: return JsonErrorResponse(description = u"不是该平台下的用户,不能绑定该平台的实体卡") # 和卡相关的特性的获取 onlyOneCard = True if "onlyOneCard" in agent.features and not request.user.many_cards else False if onlyOneCard and request.user.cards_num > 0: return JsonErrorResponse(description = u"您只能绑定一张实体卡,请联系经销商了解相应的规则") card.openId = openId card.cardName = cardName card.phone = phone card.nickName = request.user.nickname card.productAgentId = request.user.productAgentId card.managerialAppId = request.user.managerialAppId card.managerialOpenId = request.user.managerialOpenId card.save() return JsonOkResponse(description = u"添加成功", payload = {"cardId": str(card.id)}) @error_tolerate(nil = JsonErrorResponse(description = u'解绑卡失败'), logger = logger) @record_operation_behavior() @permission_required(ROLE.myuser) def unbindCard(request): # type: (WSGIRequest)->JsonResponse openId = request.user.openId payload = json.loads(request.body) cardId = payload.get('id', None) card = Card.objects(id = cardId, openId = openId).first() if not card: return JsonErrorResponse(description = u'找不到该卡') updated = card.clear_card() if not updated: return JsonErrorResponse(description = u'变更状态失败') return JsonResponse({"result": 1, "description": "", "payload": {}}) @error_tolerate(nil = JsonErrorResponse(description = u'获取正在使用失败'), logger = logger) @permission_required(ROLE.myuser) def getCurrentUse(request): # type: (WSGIRequest)->JsonResponse openId = request.user.openId filters = { "open_id": openId, "isFinished": False, "port": {"$ne": -1} } # 后付费流程中,扫码的时候会将 跳转到用户的正在服务 这个地方不要受其他设备类型的干扰 orderId = request.GET.get("orderId") if orderId: consumeOrder = ClientConsumeModelProxy.get_one(id=orderId) device = Device.get_dev(consumeOrder.devNo) if not device.owner: # 经销商此时解绑了 return JsonResponse({"result": 1, "description": "", "payload": {"total": 0, "dataList": []}}) # 下面的可以恢复正常流程 if device.devTypeCode in support_policy_device: filters = { "open_id": openId, "device_imei": device.devNo, "consumeOrder.consumeRecordId": orderId, } pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) dataList = [] for item in ServiceProgress.get_collection().find(filters): if int(time.time()) > item['finished_time']: continue else: try: devNo = item['device_imei'] device = Device.get_dev(devNo) # type: DeviceDict smartBox = ActionDeviceBuilder.create_action_device(device) group = Group.get_group(device['groupId']) nowTime = int(time.time()) data = { 'startTime': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(item['start_time'])), 'order': item['consumeOrder'], 'address': group.get('address', ''), 'groupName': group.get('groupName', ''), 'devType': device['devType'].get('name'), 'devTypeCode': device['devType'].get('code'), 'logicalCode': device['logicalCode'], 'status': Const.DEV_WORK_STATUS_WORKING, 'devNo': devNo, 'majorDeviceType': device.majorDeviceType } if 'show_PG_to_user' in device.owner.features and device.support_power_graph and item.get("port"): data.update({'showPG': True, 'port': item.get("port")}) if device['devType']['code'] in support_policy_weifule: orderInfoList = smartBox.get_current_use(base_data=data, spDict=item) dataList.extend(orderInfoList) continue needTime = item.get('consumeOrder', {}).get('needTime', None) unit = item.get('consumeOrder', {}).get('unit', None) if needTime and unit in [u'分钟', u'小时', u'天', u'秒']: # 数据库里面记录的都是归为分钟(建议后续全部统一为秒).这里计算的时间是以设备为准,不是以端口为准的,实际如果有端口,应该以端口为准 if needTime == 999: # 特殊表示充满自停 data.update({'needTime': u'充满自停'}) else: data.update({'needTime': u'%s分钟' % needTime, 'leftTime': round(int(item['finished_time'] - nowTime) / 60.0, 1)}) if item.get('port', -2) in [0, -1]: dataList.append(data) continue else: data.update({"port": item["port"]}) ctrInfo = Device.get_dev_control_cache(devNo) _coin = data.get("order", dict()).get("coin") if _coin: data["order"].update({"coin": "{}{}".format(_coin, smartBox.show_pay_unit)}) try: curInfo = device.deviceAdapter.get_port_using_detail(item['port'], ctrInfo) if curInfo.has_key('startTime'): # 微付乐自己的单板会上报startTime上来,和这里的startTime有冲突,所以,需要以订单的startTime为准 curInfo.pop('startTime') if device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_HAINIAO: curInfo['port'] = str(int(curInfo['port']) + 1) if 'orderNo' in curInfo: if data['order']['orderNo'] == curInfo['orderNo']: # 说明此单正处于运行中,数据可以直接用 data.update(curInfo) else: data.update({ 'orderNo': data['order']['orderNo'], 'desc': u'此订单已经下发到设备上,上一单运行完毕就会自动运行此订单', }) data.pop('leftTime', None) data.pop('leftElec', None) else: data.update(curInfo) # 正在服务显示按钮 data.update(DeviceType.get_services_button(device['devType']['id'])) try: data.update({'actualNeedTime': data['usedTime'] + data['leftTime']}) except Exception as e: pass dealer = Dealer.get_dealer(device.ownerId) if dealer: agent = Agent.objects(id = dealer['agentId']).first() # type: Agent if agent: agentFeatures = agent.features if 'show_elec_data_for_user' not in agentFeatures: data.pop('elec', None) data.pop('needElec', None) data.pop('power', None) data.pop("leftElec", None) data.pop("usedElec",None) if not device.is_auto_refund and "hide_refund_data_for_user" in agentFeatures: data.pop("consumeMoney", None) data.pop("leftMoney", None) data.pop("usedTime", None) data.pop("leftTime", None) if 'hide_consume_coin_data' in device.devTypeFeatures: data.pop('consumeMoney', None) data.pop('leftMoney', None) if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHARGING_HONGZHUO]: data.pop('actualNeedTime',None) data['power'] = data['powerNow'] if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_BL_TEN, Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE]: data.pop('actualNeedTime',None) # 这里需要反过来做一次校验,因为网络不稳定,可能造成丢包,没有刷新状态。 # 如果出来的状态是空闲的,那就说明服务已经结束 # zjl 充电柜的临时跳过 下个版本会对这个function进行彻底的拆分 if device.devTypeCode not in [ Const.DEVICE_TYPE_CODE_CABINET_NEW, Const.DEVICE_TYPE_CODE_CABINET, Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING, Const.DEVICE_TYPE_CODE_CHANGING_BL_TEN, Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE,] + support_policy_device: isFinished = False if curInfo.has_key('power') and curInfo.has_key('leftTime'): if curInfo['power'] == 0 and curInfo['leftTime'] in [0, u'(线路空载)']: isFinished = True else: if (curInfo.has_key('power') and curInfo['power'] == 0) or ( curInfo.has_key('leftTime') and curInfo['leftTime'] in [0, u'(线路空载)']): isFinished = True if isFinished: try: ServiceProgress.get_collection().update_many( { 'open_id': openId, 'isFinished': False, 'device_imei': devNo, 'port': item['port'] }, { '$set': { 'isFinished': True, 'expireAt': datetime.datetime.now() } }) data['leftTime'] = 0 except Exception as e: logger.error('update service progress e=%s' % e) except Exception as e: logger.exception('get cur info=%s' % e) dataList.append(data) except Exception as e: logger.exception(e) # 返回数据之前 将数据再次过滤一遍 count = len(dataList) dataList = dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize] newDataList = list() for _consumeDict in dataList: if "devNo" in _consumeDict: dev = Device.get_dev(_consumeDict["devNo"]) newDataList.append(UserConsumeFilter(dev.owner, _consumeDict).filter()) else: newDataList.append(_consumeDict) return JsonResponse({ "result": 1, "description": "", "payload": { "total": count, "dataList": newDataList } }) @error_tolerate(nil=JsonErrorResponse(description = u'获取计数失败'), logger = logger) @permission_required(ROLE.myuser) def getUserCenterCount(request): # type: (WSGIRequest)->JsonResponse openId = request.user.openId # 统计正在使用 currentUse = ConsumeRecord.objects.filter( openId=openId, status__in=[ ConsumeRecord.Status.RUNNING, ConsumeRecord.Status.END ] ).count() # 统计反馈消息 dealerIds = MyUser.get_dealer_ids(openId, request.user.productAgentId) newMessage = FeedBack.objects.filter(openId=openId, ownerId__in=dealerIds, isRead=False) return JsonResponse( { "result": 1, "description": "", "payload": { "currentUse": currentUse, "newMessage": newMessage.count() } }) @error_tolerate(nil = JsonErrorResponse(description = u'获取卡记录失败'), logger = logger) @permission_required(ROLE.myuser) def getUserCardRecord(request): # type: (WSGIRequest)->JsonResponse pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) startTime = request.GET.get('startTime', 10) endTime = request.GET.get('endTime', 10) cardId = request.GET.get('cardId', None) type = request.GET.get('type', None) card = Card.objects.get(id = cardId) if type == "chargeCard": dataList = [] for item in CardRechargeRecord.get_collection().find( { 'cardId': cardId, 'dateTimeAdded': { '$gte': to_datetime(startTime + " 00:00:00"), '$lte': to_datetime(endTime + " 23:59:59") }, "remarks": { "$ne": u"退币" } } ).sort("dateTimeAdded", -1): data = { "cardId": str(item['_id']), "cardNo": card.cardNo, "via": "chargeCard", "amount": item['money'], "coins": item.get('coins', item['money']), "address": item['address'], "groupName": item['groupName'], "balance": item['balance'], "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S') } if item.has_key('preBalance'): data.update({'preBalance': item['preBalance']}) dataList.append(data) elif type == "consume": dataList = [] rcds = CardConsumeRecord.get_collection().find({'cardId': cardId, 'dateTimeAdded': { '$gte': to_datetime(startTime + " 00:00:00"), '$lte': to_datetime(endTime + " 23:59:59")}}).sort( "dateTimeAdded", -1) for item in rcds: newData = { "cardId": str(cardId), "cardNo": card.cardNo, "via": "consume", "devType": item['devType'], "amount": item['money'], "logicalCode": item['logicalCode'], "address": item['address'], "groupName": item['groupName'], "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S') } newData.update(item.get('servicedInfo', {})) dataList.append(newData) elif type == 'order': dataList = [ { "via": "order", "amount": item['money'], "coins": item.get('coins', item['money']), "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'), "status": u'等待刷卡充值' if item['status'] == 'finishedPay' else u'充值完成', "desc": item['remarks'] } for item in CardRechargeOrder.get_collection().find({ 'cardId': cardId, 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"), '$lte': to_datetime(endTime + " 23:59:59")}}) .sort("dateTimeAdded", -1)] elif type == "refund": dataList = [] for item in CardRechargeRecord.get_collection().find( { 'cardId': cardId, 'dateTimeAdded': { '$gte': to_datetime(startTime + " 00:00:00"), '$lte': to_datetime(endTime + " 23:59:59") }, "remarks": u"退币" } ).sort("dateTimeAdded", -1): data = { "cardId": str(item['_id']), "cardNo": card.cardNo, "via": "refund", "amount": item['money'], "coins": item.get('coins', item['money']), "address": item['address'], "groupName": item['groupName'], "balance": item['balance'], "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S') } if item.has_key('preBalance'): data.update({'preBalance': item['preBalance']}) dataList.append(data) elif type == "frozen": dataList = [] for item in getattr(card, 'ongoingList', []): order = ConsumeRecord.objects.filter(id = item['transaction_id']).first() data = { "amount": order.coin.mongo_amount, "createdTime": order.startTime.strftime(Const.DATETIME_FMT), "via": "consume", "devType": order.dev_type_name, "chargeIndex": order.used_port, "logicalCode": order.logicalCode, "address": order.address, "groupName": order.groupName, "balance": card.balance.mongo_amount, "spendMoney": order.coin.mongo_amount, } dataList.append(data) else: return JsonResponse({"result": 0, "description": u"查询类型错误", "payload": {}}) return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList), "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]}}) @permission_required(ROLE.myuser) def freezeCard(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) isFrozen = payload.get('frozen') cardId = payload.get('id', '') try: card = Card.objects.get(id = cardId) card.frozen = isFrozen card.status = 'deactive' card.save() except Exception as e: logger.exception(e.message) return JsonResponse({"result": 0, "description": u'系统错误', "payload": {}}) # 如果是淋浴器,如果卡正在使用,直接把设备停掉,发指令过去 return JsonResponse({"result": 1, "description": '', "payload": {}}) @permission_required(ROLE.myuser) def bindVirtualCardToRechargeIDCard(request): # type: (WSGIRequest)->JsonResponse # TODO zjl 这个地方最好加上虚拟卡的绑定记录 payload = json.loads(request.body) virtualCardId = payload.get('virtualCardId') rechargeIDCardId = payload.get('rechargeIDCardId') if virtualCardId is None: return JsonErrorResponse(description = u'未找到虚拟卡ID') if rechargeIDCardId is None: return JsonErrorResponse(description = u'未找到ID实体卡') card = Card.objects(id = rechargeIDCardId).first() if card is None: return JsonErrorResponse(description = u'未找到ID实体卡') if card.cardType != RECHARGE_CARD_TYPE.ID: return JsonErrorResponse(description = u'该卡不是ID卡') virtualCard = UserVirtualCard.objects(id = virtualCardId).first() if virtualCard is None: return JsonErrorResponse(description = u'未找到虚拟卡') updated = card.bind_virtual_card(virtualCard) if updated: return JsonOkResponse() else: return JsonErrorResponse(description = u'绑定失败') def unbindVirtualCardToRechargeIDCard(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) virtualCardId = payload.get('virtualCardId') rechargeIDCardId = payload.get('rechargeIDCardId') if virtualCardId is None: return JsonErrorResponse(description = u'未找到虚拟卡ID') if rechargeIDCardId is None: return JsonErrorResponse(description = u'未找到ID实体卡') card = Card.objects(id = rechargeIDCardId).first() if card is None: return JsonErrorResponse(description = u'未找到ID实体卡') if card.cardType != RECHARGE_CARD_TYPE.ID: return JsonErrorResponse(description = u'该卡不是ID卡') virtualCard = UserVirtualCard.objects(id = virtualCardId).first() if virtualCard is None: return JsonErrorResponse(description = u'未找到虚拟卡') updated = card.unbind_virtual_card(virtualCard) if updated: return JsonOkResponse() else: return JsonErrorResponse(description = u'解绑失败') @permission_required(ROLE.myuser) def cardDiscountList(request): # type: (WSGIRequest)->JsonResponse """ 获取用户实体卡套餐. 获取的方式有两种: 1、实体卡管理里面,直接选择卡,进入套餐界面。传入cardId参数; 2、在扫码的充卡界面,直接输入卡号,进入套餐界面,传入扫码的设备号; :param request: :return: """ def user_center_recharge(card_id): card = Card.objects(id = str(card_id)).first() # type: Card if not card: logger.error('can not find the cardId = %s' % request.GET.get('cardId')) return JsonResponse({'result': 0, 'description': u'没有找到对应的卡,请您刷新页面重试', 'payload': {}}) if not card.dealerId or not card.groupId: return JsonResponse({ 'result': ErrorCode.CARD_NEED_BIND_GROUP, 'description': u'此卡没有绑定开卡地址', 'payload': { 'cardId': str(card.id), 'cardNo': card.cardNo, 'phone': card.phone, 'cardName': card.cardName }}) group = Group.get_group(card.groupId) # type: GroupDict card_rule_list = group.card_rule_list card_rule_list = filter(lambda x: (float(x["coins"]) + float(card.balance)) < 5000, card_rule_list) return JsonResponse({ 'result': 1, 'description': 'SUCCESS', 'payload': {'groupId': card.groupId, 'ruleList': card_rule_list}}) def device_type_card_charge(devCache): """ 从套餐页面的充卡按钮进入的卡充值页面。 不同设备类型进入不同的判断,后续有新的设备类型特有的需求增加新的判断分支。 """ if devCache.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LANGUANG: box = ActionDeviceBuilder.create_action_device(devCache) devStatus = box.get_dev_status() if devStatus.get('xf_status') == '0x0001': allowCardCharge = True else: allowCardCharge = False return allowCardCharge return True if 'cardId' in request.GET: return user_center_recharge(request.GET.get('cardId')) else: if 'devNo' in request.GET and request.GET.get('devNo'): dev = Device.get_dev(request.GET.get('devNo')) # type: Optional[DeviceDict] elif 'logicalCode' in request.GET and request.GET.get('logicalCode'): dev = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: Optional[DeviceDict] else: dev = None # type: Optional[DeviceDict] if not dev: return JsonErrorResponse(description = u'参数错误,请刷新重试(1001)') if device_type_card_charge(dev) is False: return JsonErrorResponse(description = u'暂不支持卡充值,请联系经销商检查设备或重试一下') group = Group.get_group(dev.groupId) # type: GroupDict return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': {'groupId': dev.groupId, 'ruleList': group.card_rule_list}}) @error_tolerate(nil = JsonErrorResponse(description = u'未知错误')) def getAgentQRCode(request): # type: (WSGIRequest)->JsonResponse agentId = request.GET.get('agentId', None) if agentId is None: return JsonErrorResponse(description = u'页面过期,请您重新扫码重试') try: agent = Agent.objects.get(id = agentId) if agent.gzhServiceQrcodeUrl == '': return JsonErrorResponse(description = u'没有提供公众号的二维码,需要先配置好公众号的二维码') else: return JsonOkResponse( payload = {'url': agent.gzhServiceQrcodeUrl, 'linkUrl': agent.gzhServiceLinkUrl, 'title': agent.title, 'desc': agent.desc}) except DoesNotExist: logger.exception('could not find agent by agentId={0}'.format(agentId)) return JsonErrorResponse(description = u'没有找到对应的代理商,请您检查数据是否正确') @permission_required(ROLE.myuser) def reportEndUserLocation(request): # type: (WSGIRequest)->JsonResponse """ 上报终端用户的地理信息 `sample request` { 'logicalCode': '111', 'lng': 12323.23 'lat': 1232123.22, 'type': 'gcj02' } :param request: :return: """ currentUser = request.user # type: cast(MyUser) payload = json.loads(request.body) logger.debug('end user location is: %s' % payload) try: GPS_TYPE.lookupByValue(payload['type']) except ValueError: return JsonErrorResponse(u'无效的GPS类型') pointPair = (float(payload.get('lng', 360)), float(payload.get('lat', 360))) # type: Tuple[float, float] if any(map(lambda _: _ == 360 or isnan(_), pointPair)): return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'}) if pointPair in [_.coordinates for _ in currentUser.locations]: logger.debug('user{0!r} location point{1} duplicates'.format(currentUser, pointPair)) return JsonResponse({'result': 1, 'description': ''}) location = EndUserLocation(logicalCode = payload['logicalCode'], point = pointPair, type = payload['type']) updated = currentUser.update(add_to_set__locations = location) if not updated: logger.info(u'记录终端用户地址失败 user({0!r}) payload={1}'.format(currentUser, payload)) return JsonResponse({'result': 1, 'description': ''}) @permission_required(ROLE.myuser) def getOnsale(request): # type: (WSGIRequest)->JsonResponse """ 用户侧 进入之前获取营销活动的流程 :param request: :return: """ lc = request.GET.get('logicalCode') showSite = int(request.GET.get('showSite')) dev = Device.get_dev_by_logicalCode(lc) nowTime = datetime.datetime.now() onsales = OnSale.objects.filter(status = 'start', showSite = showSite, dealerId = dev['ownerId'], logicalCodeList = lc, startTime__lte = nowTime, endTime__gte = nowTime) if onsales.count() <= 0: return JsonOkResponse() onsaleList = [] # 查询是否已经参加了活动, 如果已经参加 并且活动描述仅仅只能参加一次 不在展示该活动 for onsale in onsales: if OnSaleRecord.objects.filter(onsaleId = str(onsale['id']), userId__in = [str(request.user.id), request.user.openId]).count() and onsale.showType == "onlyOne": continue onsaleList.append(onsale) if not onsaleList: return JsonOkResponse() # TODO 这个活动为什么是随机的 ??? 这个 shuffle 也很有问题 # random.shuffle(onsaleList) # onsale = onsaleList[0] onsale = random.choice(onsaleList) return JsonResponse({ "result": 1, "description": '', "payload": { 'onsaleId': str(onsale.id), 'img': onsale.img, 'desc': onsale.desc, 'onClickUrl': onsale.onClickUrl, 'showType': onsale.showType } }) @permission_required(ROLE.myuser) def getPromotionalCoins(request): # type: (WSGIRequest)->JsonResponse """ 营销活动,用户获币 :param request: :return: """ lc = request.GET.get('logicalCode') onsaleId = request.GET.get('onsaleId') # 先检查这个用户是否有领取过,如果领取过,就不允许领取 if not onsaleId: return JsonErrorResponse(description = u'找不到营销活动ID') if not lc: return JsonErrorResponse(description = u'找不到设备') user = request.user # type: MyUser userId = str(user.id) key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId) with memcache_lock(key = key, value = '1', expire = 60) as acquired: if acquired: count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count() if count > 0: return JsonErrorResponse(description = u'您已经领取过金币了哦,不能再领了哦') onsale = OnSale.objects(id = onsaleId).first() # type: Optional[OnSale] if not onsale: return JsonErrorResponse(description = u'推广活动不存在') if onsale.status == 'stop': return JsonErrorResponse(description = u'推广活动已经下架,无法领取了哦') coins = int(onsale.detailDict.get('coins', 0)) updated = user.incr_balance(VirtualCoin(coins)) if not updated: return JsonErrorResponse(description = u'获币失败') # 添加一条充值记录 orderNo = str(uuid.uuid1()) dev = Device.get_dev_by_logicalCode(lc) group = Group.get_group(dev['groupId']) try: newRcd = RechargeRecord(orderNo = orderNo, coins = coins, money = 0.00, openId = request.user.openId, groupId = dev['groupId'], devNo = dev['devNo'], logicalCode = lc, ownerId = dev['ownerId'], groupName = group['groupName'], groupNumber = dev['groupNumber'], address = group['address'], wxOrderNo = u'活动赠币', devTypeName = dev.devTypeName, nickname = '', result = 'success', via = 'onsaleSendCoins') newRcd.save() except Exception as e: logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo)) # 增加一条活动 try: newRcd = OnSaleRecord( onsaleId = onsaleId, userId = userId, nickName = request.user.nickname, addedTime = datetime.datetime.now(), onsaleDetail = {'coins': coins} ) newRcd.save() except Exception as e: logger.exception('update record for onsale record error=%s,orderNo=%s' % e) return JsonOkResponse(description = u'赠送成功!您可以直接使用金币!') else: return JsonErrorResponse(description = u'您已正在领取') @permission_required(ROLE.myuser) def getPromotionalDuration(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ lc = request.GET.get('logicalCode') onsaleId = request.GET.get('onsaleId') # 先检查这个用户是否有领取过,如果领取过,就不允许领取 if not onsaleId: return JsonErrorResponse(description = u'找不到营销活动ID') if not lc: return JsonErrorResponse(description = u'找不到设备') userId = str(request.user.id) key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId) with memcache_lock(key = key, value = '1', expire = 60) as acquired: if acquired: # 先检查这个用户是否有领取过,如果领取过,就不允许领取 count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count() if count > 0: return JsonErrorResponse(description = u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦') onsale = OnSale.objects(id = onsaleId).first() # type: Optional[OnSale] if not onsale: return JsonErrorResponse(description = u'该活动不存在') if onsale.status == 'stop': return JsonErrorResponse(description = u'推广活动已经下架,无法体验了哦') duration = int(onsale.detailDict.get('duration')) * 60 dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict box = ActionDeviceBuilder.create_action_device(dev) try: box.send_dev_runtime(request.user.openId, duration) except ServiceException, e: return JsonErrorResponse(description = e.result.get('description')) except Exception, e: return JsonErrorResponse(description = u'系统异常,请您重试') # 增加一条活动 try: OnSaleRecord( onsaleId = onsaleId, userId = str(request.user.id), nickName = request.user.nickname, addedTime = datetime.datetime.now(), onsaleDetail = {'duration': int(onsale.detailDict.get('duration'))} ).save() except Exception as e: logger.exception('update record for onsale record error=%s' % (e,)) return JsonOkResponse(description = u'服务开始啦!您可以体验啦') else: return JsonErrorResponse(description = u'您已领取福利') @permission_required(ROLE.myuser) def getBannerList(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ lc = request.GET.get('logicalCode') dev = Device.get_dev_by_logicalCode(lc) dealer = Dealer.objects.get(id = dev['ownerId']) agent = Agent.objects.get(id = dealer.agentId) aBannerList = agent.bannerList if not aBannerList or dealer.isShowBanner is False: return JsonResponse({"result": 1, "description": '', "payload": {}}) return JsonResponse({"result": 1, "description": '', "payload": aBannerList}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.myuser) def submitComment(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ payload = json.loads(request.body) lc = payload.get('logicalCode') desc = payload.get('description') dev = Device.get_dev_by_logicalCode(lc) group = Group.get_group(dev['groupId']) Comment( devNo = dev['devNo'], logicalCode = lc, groupId = dev['groupId'], groupNumber = dev['groupNumber'], groupName = group['groupName'], address = group['address'], ownerId = dev['ownerId'], openId = request.user.openId, nickname = request.user.nickname, ratingList = payload['rating'], description = desc ).save() return JsonResponse({"result": 1, "description": '', "payload": {}}) @permission_required(ROLE.myuser) def onsaleRecharge(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ user = request.user # type: MyUser lc = request.GET.get('logicalCode') if not lc: return JsonResponse({"result": 0, "description": u'设备不存在,请刷新后重试(1001)', "payload": {}}) device = Device.get_dev_by_logicalCode(lc) # type: DeviceDict if not device: return JsonResponse({"result": 0, "description": u'设备不存在,请刷新后重试(1002)', "payload": {}}) onsaleId = request.GET.get('onsaleId') if not onsaleId: return JsonResponse({"result": 0, "description": u'活动ID错误,请刷新后重试', "payload": {}}) if user.groupId != device.groupId: return JsonResponse({"result": 0, "description": u'请在扫码后点击活动页面去充值。点击其他方式的活动链接无效。', "payload": {}}) jumpUrl = concat_user_recharge_url(l = lc) # 增加一条活动 try: OnSaleRecord( onsaleId = onsaleId, userId = str(request.user.id), nickName = request.user.nickname, addedTime = datetime.datetime.now(), onsaleDetail = {} ).save() except Exception as e: logger.exception(e) return JsonResponse({"result": 0, "description": u'系统异常,请重试', "payload": {}}) return JsonResponse({"result": 1, "description": '', "payload": {'url': jumpUrl}}) @permission_required(ROLE.myuser) def onsaleTicketList(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ user = request.user # type: MyUser lc = request.GET.get('logicalCode') onsaleId = request.GET.get('onsaleId') agentId = user.productAgentId if agentId is None: return JsonResponse({"result": 0, "description": '获取代理商错误', "payload": {}}) encodeUrl = concat_user_cardTicketList_entry_url(agentId = agentId, l = lc) # 增加一条活动 try: OnSaleRecord( onsaleId = onsaleId, userId = str(request.user.id), nickName = request.user.nickname, addedTime = datetime.datetime.now(), onsaleDetail = {} ).save() except Exception as e: logger.exception(e) return JsonResponse({"result": 0, "description": u'系统异常,请重试', "payload": {}}) return JsonResponse({"result": 1, "description": '', "payload": {'url': encodeUrl}}) @permission_required(ROLE.myuser) def sendCodeForVerify(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ payload = json.loads(request.body) lc = payload.get('logicalCode') onsaleId = payload.get('onsaleId') userId = str(request.user.id) key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId) with memcache_lock(key = key, value = '1', expire = 60) as acquired: if acquired: count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count() if count > 0: return JsonErrorResponse(description = u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦') dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict phoneNumber = payload.get('phoneNumber') dealer = Dealer.get_dealer(dev['ownerId']) agent = Agent.objects.get(id = dealer['agentId']) status, msg = userMobileVerifySMSProvider.get(phoneNumber = phoneNumber, productName = agent.productName, vendor = SysParas.get_sms_vendor(request.user.smsVendor)) if not status: return JsonErrorResponse(description = msg) else: return JsonOkResponse() else: return JsonErrorResponse(description = u'您已正在领取') @permission_required(ROLE.myuser) def mobileVerify(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ payload = json.loads(request.body) lc = payload.get('logicalCode') onsaleId = payload.get('onsaleId') phoneNumber = payload.get('phoneNumber') code = payload.get('code') userId = str(request.user.id) key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId) with memcache_lock(key = key, value = '1', expire = 60) as acquired: if acquired: status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code) if not status: return JsonErrorResponse(description = msg) count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = str(request.user.id)).count() if count > 0: return JsonResponse({"result": 0, "description": u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦', "payload": {}}) try: onsale = OnSale.objects.get(id = onsaleId) except Exception as e: logger.exception(e) return JsonResponse({"result": 0, "description": u'推广活动已经下架,无法体验了哦', "payload": {}}) if onsale.status == 'stop': return JsonResponse({"result": 0, "description": u'推广活动已经下架,无法体验了哦', "payload": {}}) duration = int(onsale.detailDict.get('duration')) * 60 dev = Device.get_dev_by_logicalCode(lc) duration = int(onsale.detailDict.get('duration')) * 60 dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict box = ActionDeviceBuilder.create_action_device(dev) try: box.send_dev_runtime(request.user.openId, duration) except ServiceException, e: return JsonErrorResponse(description = e.result.get('description')) except Exception, e: return JsonErrorResponse(description = u'系统异常,请您重试') # 增加一条活动 try: OnSaleRecord( onsaleId = onsaleId, userId = str(request.user.id), nickName = request.user.nickname, addedTime = datetime.datetime.now(), onsaleDetail = {'duration': int(onsale.detailDict.get('duration')), 'phoneNumber': phoneNumber} ).save() except Exception as e: logger.exception('update record for onsale record error=%s' % (e,)) return JsonOkResponse(description = u'服务开始啦!您可以体验啦') else: return JsonErrorResponse(description = u'您已领取福利') @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) def test(request): return JsonOkResponse() @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) def getCurrentOrder(request): # type: (WSGIRequest)->JsonResponse """ 获取目前用户目前订单的情况,给予用户下面操作的指示 :param request: :return: """ devNo = request.GET.get('devNo') startKey = request.GET.get('startKey') if not startKey: return JsonErrorResponse(description = u'未找到启动key') def get_response(orderProcessing, succeeded, desc = '', record = None): record = {} if record is None else record return JsonOkResponse( payload = { 'orderProcessing': orderProcessing, 'succeeded': succeeded, 'desc': desc, 'record': record } ) #: 前台还需要发送请求轮询获取数据 not_yet = get_response(orderProcessing = True, succeeded = None) #: 有错误或状态未知,前台可以停止轮询 stop_polling_unknown = get_response(orderProcessing = False, succeeded = False, desc = u'系统异常') #: 确切知道启动成功 polling_finished_succeeded = lambda desc, record: get_response(orderProcessing = False, succeeded = True, desc = desc, record = record) #: 确切知道启动失败 polling_finished_failed = lambda desc, record: get_response(orderProcessing = False, succeeded = False, desc = desc, record = record) record = None start_key_status = get_start_key_status(startKey) # type: dict if start_key_status: logger.debug('getCurrentOrder startKey = %s; status = %s; ts = %s' % (startKey, start_key_status, timestamp_to_dt(start_key_status['ts']).strftime( '%Y-%m-%d %H:%M:%S') if 'ts' in start_key_status else '')) state = start_key_status['state'] if state == START_DEVICE_STATUS.FAILURE or state == START_DEVICE_STATUS.TIMEOUT: return polling_finished_failed(desc=start_key_status['reason'], record = None) if state == START_DEVICE_STATUS.FINISHED: if 'orderId' in start_key_status: record = ConsumeRecord.objects(id = str(start_key_status['orderId'])).first() # type: ConsumeRecord if not record: logger.error('start key cache is not valid. value = {}'.format(str(start_key_status))) return stop_polling_unknown else: logger.debug('start key status is {}'.format(state)) # 如果查过2分钟还没有结果,直接检查订单 exp = long(request.GET.get('exp', 0)) if exp < 2 * 60 * 1000: return not_yet else: logger.debug('too long to get result. try to query record.') if not record: record = ConsumeRecord.objects(startKey = startKey).first() # type: Optional[ConsumeRecord] if not record: logger.error('cache and record are null, startKey = {}'.format(startKey)) return not_yet if record.status in [ConsumeRecord.Status.WAITING, ConsumeRecord.Status.CREATED]: return not_yet dev = Device.get_dev(devNo) # type: DeviceDict if not dev: logger.error('cannot find device by devNo(%s))' % (devNo,)) return stop_polling_unknown if record.isNormal: #: 表明应用服务器并未发现异常,但是还是有可能实际场景失败,比如吃币,所以需要给用户良好的指导和要求其上传证据。并返回币数以便上分 return polling_finished_succeeded( desc = u'您已成功启动设备。如果有疑问,请点击右下角"设备无反应"按钮', record = {'coins': record.coin, 'detailLink': record.deail_link(dev), "isIns": record.insId} ) else: #: 设备服务器与设备连接失败(超时 etc,.)需要记录失败场景,同时保证用户不扣币,前台则给予提示其重试 return polling_finished_failed( desc = record.errorDesc, record = {'coins': record.coin, 'detailLink': record.deail_link(dev)} ) @permission_required(ROLE.myuser) def getOrderStatus(request): # type: (WSGIRequest)->JsonResponse """ 蓝牙获取订单状态 :param request: :return: """ payload = json.loads(request.body) try: order_id = str(payload.get('orderId')) if OrderCacheMgr(order_id, cls_name = RechargeRecord.__name__).has_done(): record = RechargeRecord.objects(id = str(payload.get('orderId'))).first() # type: RechargeRecord if record.is_success: return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'success'}}) else: return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'fail'}}) else: return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'nop'}}) except Exception as e: logger.exception(e) return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'nop'}}) @permission_required(ROLE.myuser) def pressButton(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) button_name = payload.get('button') value = payload.get('value') lc = payload.get('logicalCode') dev = Device.get_dev_by_logicalCode(lc) smartBox = ActionDeviceBuilder.create_action_device(dev) try: devInfo = smartBox.press_button(button_name, value) except ServiceException as e: return JsonErrorResponse(description = e.result.get('description')) except Exception as e: logger.exception('cannot get_port_status, error=%s' % (str(e),)) return JsonErrorResponse(description = u'未知错误') return JsonResponse({"result": 1, "description": '', "payload": devInfo}) @permission_required(ROLE.myuser) def changeVolume(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) logical_volume = payload.get('logicalCode') volume = payload.get('value') dev = Device.get_dev_by_logicalCode(logical_volume) smart_box = ActionDeviceBuilder.create_action_device(dev) try: result = smart_box.changeVolume(volume) return JsonResponse({"result": 1, "description": '', "payload": result}) except ServiceException as e: return JsonErrorResponse(description = e.result.get('description')) except AttributeError as e: return JsonErrorResponse(description = u'暂时不支持该功能') except Exception as e: logger.exception('cannot changeVolume, error=%s' % (str(e),)) return JsonErrorResponse(description = u'未知错误') @record_operation_behavior() @permission_required(ROLE.myuser) def stopCountDown(request): # type: (WSGIRequest)->JsonResponse openId = str(request.user.openId) payload = json.loads(request.body) port = payload.get('chargeIndex', None) devNo = Device.get_devNo_by_logicalCode(logicalCode = payload['logicalCode']) devCtrInfo = Device.get_dev_control_cache(devNo = devNo) orderNo = payload.get("orderNo") # 如果设备本身停止后,有停止时间上报,系统会在停止事件中处理退费、通知事宜。这里要做的就是直接停止而已. dev = Device.get_dev(devNo = devNo) # type: DeviceDict groupId = str(dev.get("groupId")) group = Group.get_group(groupId) box = ActionDeviceBuilder.create_action_device(dev) if box.isHaveStopEvent: try: if dev.devType["code"] in [Const.DEVICE_TYPE_CODE_CHARGE_WEIFULE_CAR, Const.DEVICE_TYPE_CODE_CAR_WEIFULE_CHARGING_DOUB, Const.DEVICE_TYPE_CODE_CAR_WEIFULE_21KW, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, Const.DEVICE_TYPE_CODE_CHANGING_SOCKET, Const.DEVICE_TYPE_CODE_WEIFULE_TOUCH_PAD, Const.DEVICE_TYPE_CODE_WEIFULE_ANJIAN, ] or dev.support_reliable: box.stop_by_order(port, orderNo) else: box.stop(port) except ServiceException, e: return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}}) return JsonResponse({'result': 1, 'description': '', 'payload': {}}) # 没有停止事件的,需要在这里处理退费事宜 if port is None: for ii in range(10): try: portInfo = devCtrInfo.get(str(ii + 1), None) if portInfo is None: continue if portInfo.has_key('openId') and portInfo['openId'] == openId and portInfo['status'] in [ Const.DEV_WORK_STATUS_WORKING, Const.DEV_WORK_STATUS_PAUSE]: port = str(ii + 1) break except Exception, e: continue with memcache_lock(key = start_device_lock_key(openId = openId), value = '1', expire = 360) as acquired: if acquired: if port is not None: devCtrInfo = devCtrInfo.get(str(port), {}) totalFee = devCtrInfo.get('coins', None) if totalFee is None: logger.error('feedback coins error devNo=%s, totalFee=%s' % (devNo, totalFee)) return JsonResponse({"result": 0, "description": u'获取订购金额失败', "payload": {}}) totalTime = devCtrInfo.get('needTime', None) if totalTime is None: for _ in dev['washConfig'].values(): if totalFee == _['price']: totalTime = int(_['time']) try: devInfo = box.stop(port) except ServiceException, e: return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}}) if 'remainder_time' not in devInfo: # 有些情况,是不需要根据时间退费的,比如云快充的充电桩,会根据事件,直接结算 return JsonResponse({"result": 1, "description": '', "payload": ''}) remainderTime = devInfo['remainder_time'] # 更新内存缓存状态 if port is None: Device.invalid_device_control_cache(devNo) else: ctrInfo = Device.get_dev_control_cache(devNo) ctrInfo.update({str(port): {}}) Device.update_dev_control_cache(devNo, ctrInfo) refundFee = box.calc_stop_back_coins(totalFee, remainderTime, totalTime) backCoins = VirtualCoin(refundFee) desc = u'共付款:%s元,预定时间为:%s分钟,剩余时间:%s' % ( totalFee, totalTime, remainderTime) # 通知完成 user = MyUser.objects(openId = openId, groupId = groupId).first() task_caller('report_to_user_via_wechat', openId = user.managerialOpenId, dealerId = dev['ownerId'], templateName = 'service_complete', **{ 'title': u'订购总时间为:%s分钟,剩余时间:%s分钟' % ( totalTime, remainderTime), 'service': u'服务(设备编号:%s,地址:%s)' % ( payload['logicalCode'], group['address']), 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'remark': u'谢谢您的支持' }) # 如果需要退款,计算退款数据. if not dev.is_auto_refund: ServiceProgress.update_progress_and_consume_rcd( dev['ownerId'], {'open_id': openId, 'device_imei': devNo, 'isFinished': False}, {'leftTime': remainderTime, 'needTime': u'扫码订购%s分钟' % totalTime, 'duration': totalTime - remainderTime} ) else: # 扫码退钱, 退到个人账号 user.incr_balance(backCoins) # 添加一条充值记录 orderNo = str(uuid.uuid4()) try: newRcd = RechargeRecord(orderNo = orderNo, coins = backCoins, openId = openId, groupId = str(request.user.groupId), devNo = devNo, logicalCode = payload['logicalCode'], ownerId = dev['ownerId'], groupName = group['groupName'], groupNumber = dev['groupNumber'], address = group['address'], wxOrderNo = u'设备退币', devTypeName = dev.devTypeName, nickname = '', result = 'success', via = 'refund') newRcd.save() except Exception as e: logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo)) ServiceProgress.update_progress_and_consume_rcd( dev['ownerId'], {'open_id': openId, 'device_imei': devNo, 'isFinished': False}, {'leftTime': remainderTime, 'needTime': u'扫码订购%s分钟' % totalTime, 'duration': totalTime - remainderTime} ) task_caller('report_to_user_via_wechat', openId = user.managerialOpenId, dealerId = dev['ownerId'], templateName = 'refund_coins', **{ 'title': desc, 'backCount': u'金币:%s' % backCoins, 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) return JsonResponse({"result": 1, "description": '', "payload": ''}) @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡列表失败")) @permission_required(ROLE.myuser) def getCardTicketList(request): # type: (WSGIRequest)->JsonResponse """ 获取虚拟卡的列表 """ pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) invalid = int(request.GET.get("invalid", 0)) openId = request.user.openId now_time = datetime.datetime.now() filters = {"openIds": openId} if invalid: filters.update({"expiredTime__lt": now_time}) else: filters.update({"expiredTime__gte": now_time}) vCards = UserVirtualCard.objects.filter(**filters) total = vCards.count() dataList = list() for _vcard in vCards.skip((pageIndex - 1) * pageSize).limit(pageSize): data = _vcard.to_dict() # 检查是否需要续费 isNeedRenew, days = is_need_renew(_vcard) if isNeedRenew: data.update({'needRenew': True}) # 添加是否是卡主 data.update({"isOwner": _vcard.isOwner(request.user.openId)}) dataList.append(data) return JsonOkResponse(payload={ 'total': total, 'pageSize': pageSize, 'dataList': dataList }) @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡详情失败")) @permission_required(ROLE.myuser) def getCardTicket(request): cardId = request.GET.get("cardId") try: card = UserVirtualCard.objects.get(id=cardId) except DoesNotExist: return JsonErrorResponse(description=u"获取虚拟卡详情失败") payload = card.to_detail() isNeedRenew, days = is_need_renew(card) if isNeedRenew: payload.update({'needRenew': True}) payload.update({ "isOwner": card.isOwner(request.user.openId), "agentId": request.user.productAgentId }) return JsonOkResponse(payload=payload) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.myuser) def getUserVirtualCardByGroup(request): """ 通过groupId查询该地址下有没有购买过虚拟卡 :param request: :return: """ groupId = request.GET.get("groupId") if not groupId: return JsonErrorResponse(u"查询错误") # 如果没有通过地址数量的检查 则直接提示不能开卡 if not Group.check_virtual_card_number(groupId): return JsonErrorResponse(description = u"该地址虚拟卡数量已经达到上限,请联系发卡经销商") vCards = UserVirtualCard.objects.filter( openIds__in = [request.user.openId], groupIds__in = ['*', groupId], expiredTime__gt = datetime.datetime.now() ) vCardList = [str(vCard.cardNo) for vCard in vCards] return JsonOkResponse(payload = {"vCardList": vCardList}) @permission_required(ROLE.myuser) def getCardTicketTypeList(request): # type: (WSGIRequest)->JsonResponse groupId = request.GET.get('groupId', None) if groupId is None: return JsonErrorResponse(u'没有找到您的充值地址哦') if not Group.check_virtual_card_number(groupId): return JsonErrorResponse(description=u"该地址虚拟卡数量已经达到上限,请联系发卡经销商") group = Group.get_group(groupId) onlineCards = VirtualCard.objects.filter( ownerId=group['ownerId'], status=1, groupIds__in=['*', groupId], expiredTime__gt=datetime.datetime.now() ) dataList = [] for obj in onlineCards: data = obj.to_dict() if '*' in obj.groupIds: groups = [{'groupName': grp['groupName'], 'address': grp['address']} for grp in Group.get_groups_by_group_ids(Group.get_group_ids_of_dealer(obj.ownerId)).values()] else: groups = [{'groupName': grp['groupName'], 'address': grp['address']} for grp in Group.get_groups_by_group_ids(obj.groupIds).values()] data["groups"] = groups dataList.append(data) return JsonOkResponse(payload={'dataList': dataList}) # 分享卡卷的链接 @permission_required(ROLE.myuser) def getShareCardTicket(request): # type: (WSGIRequest)->JsonResponse vCardId = request.GET.get('cardId', None) if vCardId is None: return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被卡主注销,无法共享', "payload": None}) try: vCard = UserVirtualCard.objects.get(id = vCardId) except DoesNotExist as e: return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被卡主注销,无法共享', "payload": None}) if len(vCard.openIds) > vCard.userLimit - 1: return JsonResponse({"result": 0, "description": u'共享的人数已经达到卡的限制,您无法共享哦', "payload": None}) agentId = Dealer.get_dealer(vCard.dealerId).get('agentId', None) if agentId is None: return JsonResponse({"result": 0, "description": u'非法卡,您无法共享哦', "payload": None}) if request.user.agentId != agentId: return JsonResponse({"result": 0, "description": u'非法卡,您无法共享哦', "payload": None}) if request.user.openId in vCard.openIds: return JsonResponse({"result": 0, "description": u'您已经共享了此卡', "payload": None}) vCard.openIds.append(request.user.openId) try: vCard.save() except Exception as e: logger.info('save sharing card error=%s' % e) return JsonResponse({"result": 0, "description": u'保存卡的信息异常,请您重试', "payload": None}) data = vCard.to_detail() data.update({ "isOwner": vCard.isOwner(request.user.openId), "agentId": request.user.productAgentId }) return JsonResponse({"result": 1, "description": '', "payload": data}) @permission_required(ROLE.myuser) def removeCardSharedMembers(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) vCardId = payload.get('cardId') openId = payload.get('userId') if vCardId is None: return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被注销,请您刷新页面后再重试', "payload": None}) try: vCard = UserVirtualCard.objects.get(id = vCardId) except DoesNotExist: return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被注销,请您刷新页面后再重试', "payload": None}) vCard.openIds.remove(openId) try: vCard.save() except Exception as e: logger.info('save sharing card error=%s' % e) return JsonResponse({"result": 0, "description": u'保存卡的信息异常,请您重试', "payload": None}) return JsonResponse({"result": 1, "description": '', "payload": None}) @permission_required(ROLE.myuser) def stopService(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) logicalCode = payload.get('logicalCode') port = payload.get('port', None) dev = Device.get_dev_by_l(logicalCode) box = ActionDeviceBuilder.create_action_device(dev) try: box.stop(port) except ServiceException, e: return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}}) return JsonResponse({'result': 1, 'description': '', 'payload': {}}) @permission_required(ROLE.myuser) def toggleDeviceStatus(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) logicalCode = payload.get('logicalCode') port = payload.get('chargeIndex', None) isContinue = False if payload.get('targetStatus', None) == 'pause' else True dev = Device.get_dev_by_l(logicalCode) box = ActionDeviceBuilder.create_action_device(dev) try: result = box.pause(request.user.openId, isContinue, port) return JsonResponse({'result': 1, 'description': '', 'payload': result}) except ServiceException, e: return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}}) @permission_required(ROLE.myuser) def getDeviceSellItems(request): payload = json.loads(request.body) logicalCode = payload.get('logicalCode') objs = Cell.objects.filter(logicalCode = logicalCode, itemStatus = 'full') dataList = [{ 'cellNo': obj.cellNo, 'boardNo': obj.boardNo, 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle, 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl, 'itemPrice': obj.itemPrice } for obj in objs] return JsonResponse({'result': 1, 'description': '', 'payload': {'dataList': dataList}}) @permission_required(ROLE.myuser) def getDeviceCells(request): logicalCode = request.GET.get('logicalCode') objs = Cell.objects.filter(logicalCode = logicalCode) dev = Device.get_dev_by_logicalCode(logicalCode) box = ActionDeviceBuilder.create_action_device(dev) lockStatusDict = box.get_all_lock_status() dataList = [{'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo, 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle, 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl, 'itemPrice': round(obj.itemPrice / 100.0, 2), 'lockStatus': lockStatusDict.get(obj.cellNo, 'close')} for obj in objs if (lockStatusDict.get(obj.cellNo, 'close') == 'close' and obj.itemStatus != 'empty')] return JsonResponse({'result': 1, 'description': '', 'payload': {'dataList': dataList}}) @permission_required(ROLE.myuser) def updateUserActiveInfo(request): """ 安骑换电用户 的身份信息上传接口 需要信息 手机验证码 手机号码 身份验证信息 推荐人信息(非必须) 推荐人 # 新添加了字段 phoneNumber """ user = request.user # type: MyUser if user.is_product_user(): return JsonErrorResponse(u"请先扫描设备") active_info = MyUser.get_active_info(user.openId, agentId = user.agentId) if active_info and active_info.get("isMember"): return JsonErrorResponse(u"您已经完成实名认证,请勿重复") payload = json.loads(request.body) code = payload.get("code", "") phoneNumber = payload.get("phoneNumber", "") imgList = payload.get("imgList", []) recommender = payload.get("recommender", "") if phoneNumber: if MyUser.objects.filter( Q(phoneNumber = phoneNumber), Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId) ): return JsonErrorResponse(description = u"手机号码已经被注册!") # 推荐人如果填写必须有效 并且非本人 并且激活 if recommender: if not MyUser.objects.filter( Q(phoneNumber = recommender), Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId) ) or recommender == phoneNumber: return JsonErrorResponse(u"无效的推荐人") status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code) if not status: return JsonErrorResponse(msg) MyUser.set_active_info( {"phoneNumber": phoneNumber, "imgList": imgList, "recommender": recommender, "status": 1, "createdTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S") }, openId = user.openId, agentId = user.agentId, groupId = user.groupId ) return JsonOkResponse() @permission_required(ROLE.myuser) def getUserActiveInfo(request): user = request.user active_info = MyUser.get_active_info(user.openId, agentId = user.agentId) status = active_info.get("status", "") payload = { "id": user.id, "identifyUrl": active_info.get("identifyUrl", ""), "recommender": active_info.get("recommender", ""), "phoneNumber": active_info.get("phoneNumber", ""), "status": status if status else 0, "remarks": active_info.get("remarks", "") } return JsonResponse({"result": 1, "description": '', "payload": payload}) @permission_required(ROLE.myuser) def getTelVerifyInfo(request): user = request.user status = 1 if user.phone else 0 return JsonResponse({"result": 1, "description": "", "payload": {"status": status}}) @permission_required(ROLE.myuser) def updateTelVerifyInfo(request): """ 绑定手机号码. 手机号码只是做为属性, 谁能获取验证码, 手机号码就是谁的 """ user = request.user jsonData = json.loads(request.body) phoneNumber = jsonData.get("phoneNumber", "") code = jsonData.get("code", "") # 首先校验 短信验证码 status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code) if not status: return JsonErrorResponse(msg) try: user.phone = phoneNumber except Exception as e: logger.exception(e) return JsonErrorResponse(description=u"手机号码绑定失败,请刷新重试") return JsonOkResponse(description=u"绑定成功") @permission_required(ROLE.myuser) def sendActiveSmsCode(request): """ 安骑换电用户 获取手机验证码 手机号码 """ user = request.user payload = json.loads(request.body) phoneNumber = payload.get("phoneNumber", "") # phoneNumber 唯一 checkUser = MyUser.objects.filter( Q(phoneNumber = phoneNumber), Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId) ).first() if checkUser and checkUser.gateway == user.gateway: return JsonErrorResponse(u"该号码已经被注册") agent = Agent.objects.get(id = user.agentId) status, msg = userMobileVerifySMSProvider.get(phoneNumber = phoneNumber, productName = agent.productName, vendor = SysParas.get_sms_vendor(request.user.smsVendor), openId = user.openId) if not status: return JsonErrorResponse(description = msg) else: return JsonOkResponse() @error_tolerate(logger = logger, nil = JsonErrorResponse(u'上传身份文件图片存储失败,请重新试试')) @permission_required(ROLE.myuser) def UploadIdentify(request): """ 用户上传身份验证 """ files = request.FILES.getlist('file') if not len(files): return JsonResponse({'result': 0, 'description': u'未知的身份文件信息,请重新试试', 'payload': {}}) uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'identify') logger.info('[uploadItemPic] %s is being used' % (repr(uploader),)) try: outputUrl = uploader.upload() return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl}) except InvalidFileSize, e: logger.info( '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),)) return JsonResponse({'result': 0, 'description': e.message, 'payload': {}}) except InvalidFileName, e: logger.info( '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),)) return JsonResponse({'result': 0, 'description': e.message, 'payload': {}}) @permission_required(ROLE.myuser) def UserActiveIntercepter(request): """ 安骑用户 拦截器 身份认证未通过的用户 """ user = request.user active_info = MyUser.get_active_info(openId = user.openId, agentId = user.agentId) isMember = active_info.get("isMember", False) return JsonOkResponse(payload = {"isMember": int(isMember)}) @permission_required(ROLE.myuser) def DeviceTrack(request): """ 电池电压、位置信息 存在位置信息 """ # TODO 数据库分库整改 # 获取用户的最后一次serverProcess 从中获取用户电池的IMEI # API查询电池信息 # 返回信息 user = request.user active_info = MyUser.get_active_info(openId = user.openId, agentId = user.agentId) status = active_info.get("status", 0) if status != 2: # 完成身份认证的用户状态是2 return JsonErrorResponse(u"请先完成身份认证信息") # 找出换电柜的使用记录 并且拿到的电池的编号不为-1 record = ConsumeRecord.objects.filter( openId = user.openId, servicedInfo__newBatteryImei__exists = True, servicedInfo__newBatteryImei__ne = "-1" ).order_by("-dateTimeAdded").first() if not record: return JsonErrorResponse(u"未获取到有效电池信息") battery = record.servicedInfo.get("newBatteryImei") try: result = batteryInfo(battery) except Exception as e: logger.info("get battery info error ,reason is : %s" % e) return JsonErrorResponse(u"网络故障,获取电池信息失败") batInfo = result.get(battery) if not batInfo: return JsonErrorResponse(u"电池编号错误") lng = batInfo.get("lng") lat = batInfo.get("lat") lng, lat = coordinateHandler(lng, lat) payload = { "total": 1, "items": [ { "lng": lng, "lat": lat, "remarks": u"当前电池电压信息是%s" % batInfo.get("voltage"), } ] } return JsonOkResponse(payload = payload) @error_tolerate(logger=logger) @permission_required(ROLE.myuser) # @ServerSwitch.payment_switch('系统维护升级中,请稍后重试') def payGateway(request): # type: (WSGIRequest)->HttpResponse """ 用户请求充值 两层机制保证订单不被重复处理。 1、用户订单创建后,在cache塞一个值为0的key;在收到回调或者查询到状态后,对这个key加1。如果返回新值为2则代表已经有处理过。 2、如果cache失效,那么返回值为None。这个时候需要判断RechargeRecord的update结果,如果有修改,则代表没处理;否则已经处理过 :param request: :return: """ from apps.web.common.transaction.pay import PayPullUpFactoryIntf class PayPullUpFactory(PayPullUpFactoryIntf): @classmethod def create_by_alipay(cls, payment_gateway, payParam, record): current_user = payParam.curUser open_id = current_user.get_bound_pay_openid(payment_gateway.bound_openid_key) pull_up_cls = PayManager().get_pull_up(payment_gateway.pay_app_type) return pull_up_cls(open_id, payment_gateway, record, **{ 'showAd': payParam.showAd, 'notifyUrl': PAY_NOTIFY_URL.ALI_PAY_BACK }) @classmethod def create_by_wechat(cls, payment_gateway, payParam, record): current_user = payParam.curUser open_id = current_user.get_bound_pay_openid(payment_gateway.bound_openid_key) pull_up_cls = PayManager().get_pull_up(payment_gateway.pay_app_type) return pull_up_cls(open_id, payment_gateway, record, **{ 'showAd': payParam.showAd, 'notifyUrl': PAY_NOTIFY_URL.WECHAT_PAY_BACK }) @classmethod def create(cls, payment_gateway, record, **payload): payParam = payload.get('payParam') if payment_gateway.pay_app_type == PayAppType.ALIPAY: return cls.create_by_alipay(payment_gateway, payParam, record) elif payment_gateway.pay_app_type == PayAppType.WECHAT: return cls.create_by_wechat(payment_gateway, payParam, record) else: raise UserServerException(u'不支持的支付方式') try: logger.info('----{user} unified order----'.format(user=repr(request.user))) payParam = PayParam(request) # type: PayParam payParam.call_check() payment_gateway = payParam.payGateway if not payment_gateway: raise UserServerException(u'第三方支付配置错误,请联系平台客服(1001)') record = BUILDER_MAP.get(payParam.recordBuilderKey)(payParam) # type: RechargeRecord from apps.web.common.transaction.pay import PayPullUp pull_up = PayPullUp.create(PayPullUpFactory, payment_gateway, record, **{'payParam': payParam}) response = pull_up.do() if 'startKey' in payParam.attachParas: set_start_key_status(payParam.attachParas['startKey'], START_DEVICE_STATUS.PAYING) return response except InterceptException as e: logger.debug(e.redirect) return JsonResponse({ 'result': ErrorCode.LOGIN_VERIFY, 'payload': { 'redirect': e.redirect } }) except ServiceException as e: logger.error(str(e)) return JsonResponse(e.result) except UserServerException as e: logger.error(e.message) return JsonErrorResponse(e.message) except AliException as e: logger.error(str(e)) return JsonErrorResponse(description=e.message) except Exception as e: logger.exception(e) return JsonErrorResponse(description=u'系统错误,请重试') finally: logger.info('----{user} unified order over----'.format(user=repr(request.user))) @error_tolerate(logger = logger) @permission_required(ROLE.myuser) def setMyUserDetail(request): user = request.user # type: MyUser payload = json.loads(request.body) ownerId = payload.pop('ownerId') MyUserDetail.objects(openId = str(user.openId), dealerId = str(ownerId)).upsert_one( openId = str(user.openId), dealerId = str(ownerId), userName = payload.get('userName'), userPhone = payload.get('userPhone'), userUnit = payload.get('userUnit'), userFloor = payload.get('userFloor'), userRoom = payload.get('userRoom')) return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': {}}) @error_tolerate(logger = logger) def payNotify(request, pay_app_type): # type: (WSGIRequest, str)->JsonResponse if pay_app_type == PayAppType.ALIPAY: payload = request.POST.dict() if 'refund_fee' in payload and 'gmt_refund' in payload: notifier_cls = RefundManager().get_notifier(pay_app_type) return notifier_cls(request, lambda filter: RefundMoneyRecord.get_record(**filter)).do(refund_post_pay) recharge_cls_factory = lambda order_no: RechargeRecord notifier_cls = PayManager().get_notifier(pay_app_type = pay_app_type) return notifier_cls(request, recharge_cls_factory).do(post_pay) @permission_required(ROLE.myuser) def getFavoriteDevice(request): pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) devNoList = request.user.collectedDeviceList devs = Device.get_dev_by_nos(devNoList, verbose = True) dataList = [] for dev in devs.values(): dev.update({'type': dev['devType'].get('name', '')}) dataList.append(dev) return JsonOkResponse( payload = {'total': len(dataList), 'items': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}) @permission_required(ROLE.myuser) def deleteFavoriteDevice(request): payload = json.loads(request.body) lcCodes = payload['logicalCodeList'] removeList = set() for lcCode in lcCodes: devNo = Device.get_devNo_by_logicalCode(lcCode) removeList.add(devNo) devNolist = set(request.user.collectedDeviceList) request.user.collectedDeviceList = list(devNolist - removeList) return JsonOkResponse() @permission_required(ROLE.myuser) def addFavoriteDevice(request): payload = json.loads(request.body) isFavorite = payload['favorite'] lcCode = payload['logicalCode'] devNo = Device.get_devNo_by_logicalCode(lcCode) collectedDeviceList = request.user.collectedDeviceList if isFavorite: if devNo not in collectedDeviceList: collectedDeviceList.append(devNo) request.user.collectedDeviceList = collectedDeviceList else: return JsonOkResponse(description = u'该设备已经收藏啦') else: if devNo in collectedDeviceList: collectedDeviceList.remove(devNo) request.user.collectedDeviceList = collectedDeviceList else: return JsonOkResponse(description = u'该设备已经取消收藏啦') return JsonOkResponse() # 检查是否需要弹出加粉界面。1、需要获取监督号的openId。2、检查是否需要弹出加粉界面 # 监督号的入口也需要调用此函数,目的是找到客户应该登录的agentId。 @permission_required(ROLE.myuser) def moniUserAccess(request): logger.info('receive moniUserAccess') # 目前只支持微信加粉 try: href = request.GET.get('redirect') moniAppId = request.GET.get('moniAppId', None) if moniAppId is None: agent = Agent.objects.get(id = request.user.agentId) moniApp = agent.get_online_moni_app() if not moniApp: return ErrorResponseRedirect(error = cn(u'请您刷新下页面,重新点击试试')) else: try: moniApp = MoniApp.get_collection().find({'appId': moniAppId})[0] except Exception, e: return ErrorResponseRedirect(error = cn(u'建议您从扫码页面关注公众号,这样才可以使用此公众号的服务哦')) # 返回跳转页面 state = MoniUserAuthState(appId = moniApp['appId'], openId = request.user.openId, href = href) wechatApp = WechatAuthApp(appid = moniApp['appId'], secret = moniApp['secret']) bridge = WechatAuthBridge(wechatApp) return ExternalResponseRedirect( bridge.generate_auth_url_base_scope(redirect_uri = USER_AUTH_REDIRECT_URL.MONI_BASE, payload = state.encode())) except Exception, e: logger.exception(e) return ErrorResponseRedirect(error = cn(u'系统开小差了~~~,请您刷新下页面,重新点击试试')) @permission_required(ROLE.myuser) def checkPoint(request): logger.info('checkPoint,receive,user openId=%s' % request.user.openId) # 目前只支持微信加粉 if (not detect_wechat_client(request)): logger.info('checkPoint,it is not wechat client') return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) try: point = request.GET.get('point') logicalCode = request.GET.get('logicalCode') dev = Device.get_dev_by_logicalCode(logicalCode) dealer = Dealer.objects(id = dev['ownerId']).get() logger.info('checkPoint,user openId=%s,logicalCode=%s' % (request.user.openId, logicalCode)) # 检查经销商和代理商的开关 if dealer.moniAppCheckPointDict.has_key(point) and (not dealer.moniAppCheckPointDict[point]): logger.info('checkPoint,moniappcheck point dealer is off,point') return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) agent = Agent.objects(id = dealer.agentId).get() if agent.moniAppCheckPointDict.has_key(point) and (not agent.moniAppCheckPointDict[point]): logger.info('checkPoint,moniappcheck point agent is off') return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) moniApp = agent.get_online_moni_app() if not moniApp: return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) rcds = MoniUser.objects.filter(openId = request.user.openId, moniAppId = moniApp['appId']) if rcds.count() == 0: # 一条记录都没有是,说明没有拿到对应数据 logger.info('checkPoint,can not find moniuser') return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) else: moniUser = rcds.first() if moniUser.isSubscribe: return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) else: # 如果没关注,可能存在用户通过其他手段提前关注了,要多重检查下 app = WechatAuthApp(appid = moniApp['appId'], secret = moniApp['secret']) proxy = WechatClientProxy(app) isSubGzh = proxy.is_subscribe_gzh(moniUser['moniOpenId']) if isSubGzh: moniUser.isSubscribe = True moniUser.subPoint = point moniUser.subLogicalCode = logicalCode moniUser.subDealerId = str(dealer.id) moniUser.subAgentId = str(agent.id) moniUser.save() return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) else: moniUser.subPoint = point moniUser.subLogicalCode = logicalCode moniUser.subDealerId = str(dealer.id) moniUser.subAgentId = str(agent.id) moniUser.save() return JsonOkResponse( payload = {'addFans': True, 'qrCode': moniApp['qrCode'], 'title': moniApp['title'], 'desc': moniApp['desc']}) except Exception, e: return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''}) @permission_required(ROLE.myuser) def isNeedAccessMoniApp(request): logger.info('receive isNeedAccessMoniApp') if (not detect_wechat_client(request)): return JsonOkResponse(payload = {'isNeed': False}) try: agent = Agent.objects(id = request.user.agentId).get() # 如果代理商支持强制关注公众号,而且用户一天内才创建进来,为了体验好一点,这次就不要弹窗了 if agent.forceFollowGzh and (datetime.datetime.now() - request.user.dateTimeAdded).total_seconds() < 24 * 60 * 60: return JsonOkResponse(payload = {'isNeed': False}) # 如果这个用户已经订阅了某个监督号,就直接返回 moniApp = agent.get_online_moni_app() if not moniApp: return JsonOkResponse(payload = {'isNeed': False}) moniUserCount = MoniUser.objects.filter(openId = request.user.openId, moniAppId = moniApp['appId']).count() if moniUserCount == 0: return JsonOkResponse(payload = {'isNeed': True}) return JsonOkResponse(payload = {'isNeed': False}) except Exception, e: return JsonOkResponse(payload = {'isNeed': False}) @permission_required(ROLE.myuser) def getComplaintList(request): pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) objs = Complaint.objects.filter(openId = request.user.openId) dataList = [] total = objs.count() for obj in objs.paginate(pageIndex = pageIndex, pageSize = pageSize): dataList.append({ 'id': str(obj.id), 'logicalCode': obj.logicalCode, 'createdTime': obj.dateTimeAdded.strftime(Const.DATETIME_FMT), 'handledTime': obj.handledTime.strftime(Const.DATETIME_FMT), 'handledStatus': obj.handledStatus, 'groupName': obj.groupName, 'reason': obj.reason }) return JsonOkResponse(payload = {'total': total, 'dataList': dataList}) def submitComplaint(request): payload = json.loads(request.body) # 首先产生一条投诉记录 logicalCode = payload.get('logicalCode') orderNo = payload.get('orderNo') reason = payload.get('reason') order = ConsumeRecord.objects.get(orderNo = orderNo) if order.logicalCode != logicalCode: return JsonErrorResponse(description = u'设备的编码填写错误,请您检查下哦') if Complaint.objects.filter(orderNo = orderNo).count() > 0: return JsonErrorResponse(description = u'该订单已经投诉成功,不需要您重复投诉了哦') newObj = Complaint( openId = request.user.openId, logicalCode = logicalCode, groupName = order.groupName, orderNo = orderNo, reason = reason ) newObj.save() # 然后通知经销商 newMsg = DealerMessage( ownerId = order.ownerId, fromUser = u'系统平台', messageType = 'complaint', title = u'客户投诉', desc = u'平台收到客户的投诉,请您尽快处理,如果收到投诉过多,系统会提醒设备用户,甚至禁用此设备。地址:%s,设备:%s,投诉原因:%s' % ( order.groupName, logicalCode, reason), relatedInfo = {'complaintId': str(newObj.id)} ) newMsg.save() return JsonOkResponse() @permission_required(ROLE.myuser) @request_limit_by_user(operation='queryServicePhone', limit=10, period=2 * 60 * 60, logger=None) def queryServicePhone(request): """ 根据订单查询客服电话 :param request: :return: """ logicalCode = request.GET.get('logicalCode') dealerIds = MyUser.get_dealer_ids(openId = request.user.openId, productAgentId = request.user.productAgentId) device = Device.get_dev_by_logicalCode(logicalCode) # type: DeviceDict if not device or device.ownerId not in dealerIds: return JsonOkResponse(payload={}) if not device.owner: logger.error('dealer not exists.'.format(device.ownerId)) return JsonOkResponse(payload={}) return JsonOkResponse(payload=({'phone': device.owner.service_phone})) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def getAllFeature(request): agent = Agent.objects.get(id = request.user.agentId) if agent is None: return JsonErrorResponse(description = u'代理商不存在') else: return JsonOkResponse(payload = {_: True for _ in agent.features}) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def queryCardNo(request): logicalCode = request.GET.get('logicalCode') devNo = Device.get_devNo_by_logicalCode(logicalCode) if devNo is None: return JsonErrorResponse(description = u'未识别的设备编号') cardNo = Card.get_dev_card_no(devNo) if cardNo is None: return JsonOkResponse(payload = {'cardNo': ''}) return JsonOkResponse(payload = {'cardNo': cardNo}) @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger) @permission_required(ROLE.myuser) def prepareScanCard(request): logicalCode = request.GET.get('logicalCode') devNo = Device.get_devNo_by_logicalCode(logicalCode) if devNo is None: return JsonErrorResponse(description = u'未识别的设备编号') Card.clear_dev_card_no(devNo) return JsonOkResponse() @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger) @permission_required(ROLE.myuser) def checkUserConsumeOrder(request): logicalCode = request.GET.get("logicalCode") dev = Device.get_dev_by_logicalCode(logicalCode) if not dev: return JsonErrorResponse(u"未找到设备,请扫码重试") box = ActionDeviceBuilder.create_action_device(dev) if not hasattr(box, "check_user_consume_order"): return JsonOkResponse() status = box.check_user_consume_order() return JsonResponse({"result": status}) @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger) @permission_required(ROLE.myuser) def preJudgment(request): """ 这个接口 无论如何不能抛出异常 前台规定 :param request: :return: """ logicalCode = request.GET.get("logicalCode") dev = Device.get_dev_by_logicalCode(logicalCode) if not dev: return JsonErrorResponse(u"该设备不存在") order = get_user_not_complete_order(request.user, dev.owner) # 正常结果下的返回 if not order: return JsonOkResponse() if order.status == order.Status.RUNNING: return JsonResponse({"result": ErrorCode.ORDER_RUNNING, "description": u"您有一笔正在进行的订单", "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}}) elif not order.isPaid: return JsonResponse({"result": ErrorCode.ORDER_NEED_PAY, "description": u"你有一笔尚未支付的订单,请先完成支付,然后在使用设备", "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}}) # elif order.is_waitPay(): # return JsonResponse({"result": ErrorCode.ORDER_PAYING, "description": u"正在检查支付结果,请稍后", # "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}}) else: return JsonResponse({"result": "2", "description": u"系统错误,请您稍后重试"}) @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger) @permission_required(ROLE.myuser) def getCardBindUserStatus(request): user = request.user status = 1 if user.extra.get('campus_user_num', '') else 0 return JsonResponse({"result": 1, "description": "", "payload": {"status": status}}) @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger) @permission_required(ROLE.myuser) def updateCardBindUserInfo(request): user = request.user jsonData = json.loads(request.body) phoneNumber = str(jsonData.get("phoneNumber", "").strip()) code = jsonData.get("code", "") campus_user_num = str(jsonData.get('userNo').strip()) userName = str(jsonData.get('userName').strip()) from apps.web.eventer.caiyi import config_dic # 测试白名单 test_card = serviceCache.get('yc-num-{}'.format(campus_user_num)) if test_card: userName = 'test' campus_user_num = 'test001' logger.debug('yc_test_card,to reg card!!!') res = {'factoryFixId': '757996699'} else: # TODO 去服务器验证人员编号和手机号是否吻合 yc = YuChuanApi(**config_dic) try: res = yc.sql_get_user_info(campus_user_num) user_phone = base64.encodestring(phoneNumber + '.00').strip() if res['mobilePhone'] != user_phone or res['userName'] != userName: return JsonErrorResponse(description = u'一卡通信息填写错误~,请您检查下哦') except Exception as e: return JsonErrorResponse(description = u'一卡通信息填写错误!!!,请您检查下哦') card_no = str(res.get('factoryFixId')).replace('L', '') if not card_no: raise UserServerException(u'一卡通信息填写错误!!') status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code) if not status: return JsonErrorResponse(msg) dic = { "card_dealer": "宇川智能平台一卡通", "campus_user_num": campus_user_num, } card = Card.objects.filter(cardNo = card_no, cardType = 'YuChuanCard').first() or Card.objects.create( cardNo = card_no, agentId = user.agentId, phone = phoneNumber, remarks = '宇川一卡通', productAgentId = user.productAgentId, cardName = userName, attachParas = dic, cardType = 'YuChuanCard', nickName = user.nickname, openId = user.openId) if card.openId == card_no or card.openId != user.openId: # 判断是否为刷卡注册入库,或则换微信绑定 card.openId = user.openId card.nickName = user.nickname card.phone = phoneNumber card.save() dic['card_no'] = card_no user.phoneNumber = phoneNumber user.extra = dic user.save() return JsonResponse({"result": 1, "description": "", "payload": {"status": 1}}) @error_tolerate(logger = logger, nil = JsonErrorResponse(description = u"获取卡金额失败")) @permission_required(ROLE.myuser) def getRemoteCardBalance(request): """ 获取远程充值卡的金额 :param request: :return: """ logicalCode = request.GET.get("logicalCode") dev = Device.get_dev_by_l(logicalCode) if not dev: return JsonErrorResponse(description = u"请先扫描设备") box = ActionDeviceBuilder.create_action_device(dev) if not hasattr(box, "get_remote_card_balance"): return JsonErrorResponse(description = u"当前设备暂不支持充值卡") try: result = box.get_remote_card_balance() except ServiceException as e: return JsonErrorResponse(description = e.message.get("description")) res = result.get("res") if res == "02": return JsonErrorResponse(description = u"请先将卡片置于设备上") # 这个地方将用户的信息塞入进去 user = request.user result.update({ "avatarUrl": user.avatar, "openId": user.openId }) # 然后再次塞入设备信息 result.update({ "devNo": dev.devNo, "groupId": dev.groupId }) packages = dev.get("washConfig", dict()) newPackages = list() for _id, item in packages.items(): switch = item.get("switch", True) if not switch: continue newPackages.append({ "id": _id, "payAmount": item.get("price"), "coins": item.get("coins") }) result.update({"packages": newPackages}) return JsonOkResponse(payload = result) @error_tolerate(logger = logger, nil = JsonOkResponse()) @permission_required(ROLE.myuser) def getUserDisclaimer(request): """ 获取用户的免责声明 用户 用户进入系统第一次的时候需要阅读此协议并且 明确表示阅读 否则展示界面给用户 :param request: :return: """ productAgentId = request.user.productAgentId disclaimer = Agent.get_disclaimer(productAgentId) # 当用户阅读的声明版本与当前免责代理商的版本不一致 并且代理商的免责声明内容不为空的时候 前台需要展示免责声明 payload = { "version": disclaimer.version, "content": disclaimer.content } if not disclaimer.content: payload = {} return JsonOkResponse(payload = payload) @error_tolerate(logger = logger, nil = JsonOkResponse()) @permission_required(ROLE.myuser) def pauseUsingDevice(request): payload = json.loads(request.body) logicalCode = payload.get('logicalCode', '') if logicalCode == '': return JsonErrorResponse(description = u'参数错误(没有逻辑码)') port = payload.get('chargeIndex', '') if port == '': return JsonErrorResponse(description = u'参数错误(没有端口号)') dev = Device.get_dev_by_l(logicalCode) portCache = Device.get_dev_control_cache(dev['devNo'])[str(port)] if dev['devType']['code'] in ['1002121', '1002122']: if portCache.get('pausePort', False) is True: oper = '01' else: oper = '02' else: oper = '00' smartBox = ActionDeviceBuilder.create_action_device(dev) try: smartBox.pauseToUseDevice(port, oper) except Exception as e: return JsonErrorResponse(description = u'操作失败') return JsonOkResponse() @error_tolerate(logger = logger, nil = ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试')) @permission_required(ROLE.myuser) def gatewayEntry(request): """ 再发起支付之前 获取一次用户的 payOpenId 然后重定向到用户的支付详情页面 并直接访问payGateway :param request: :return: """ def get_pay_gateway_redirect(pp, adLink): redirect = pp._request.GET.get("redirect") info = { 'params': pp._request.GET.get("params"), 'goodsInfo': json.dumps(pp.goodsInfo) } if adLink: info.update({'adLink': adLink}) url = before_frag_add_query(redirect, info) logger.debug('redirect to client url is: {}'.format(url)) return FrontEndResponseRedirect(url) def get_auth_redirect(pp, bridge, adLink): authCode = pp._request.GET.get(bridge.auth_code_key) if not authCode: redirect_uri = concat_server_end_url( uri = add_query('/user/pay/gatewayEntry', { 'params': pp._request.GET.get("params"), 'redirect': pp._request.GET.get("redirect") }) ) logger.debug('base scope auth url is:{}'.format(redirect_uri)) return ExternalResponseRedirect( bridge.generate_auth_url_base_scope( redirect_uri = redirect_uri, payload = {} ) ) else: userPayOpenId = bridge.authorize(authCode) if not userPayOpenId: return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试') else: pp.curUser.set_bound_pay_openid(bridge.bound_openid_key, openId = userPayOpenId) pp.curUser.save() return get_pay_gateway_redirect(pp, adLink) def RCU_process(payParam): code = request.GET.get('code') if not code: redirect = payParam._request.GET.get("redirect") redirect_uri = concat_server_end_url( uri = add_query('/user/pay/gatewayEntry', { 'params': payParam._request.GET.get("params"), 'redirect': redirect }) ) url = add_query(pay_gateway.app.authCodeUrl, {'authCallBackUrl': redirect_uri}) logger.debug('base scope auth url is:{}'.format(redirect_uri)) return FrontEndResponseRedirect(url) else: redirect = payParam._request.GET.get("redirect") info = { 'params': payParam._request.GET.get("params"), 'code': code, 'goodsInfo': json.dumps(payParam.goodsInfo), } if adLink: info.update({'adLink': adLink}) url = before_frag_add_query(redirect, info) logger.debug('redirect to client url is: {}'.format(url)) return FrontEndResponseRedirect(url) payParam = PayParam(request) curUser = payParam.curUser pay_gateway = payParam.payGateway adLink = request.GET.get('adLink', None) # 首先判断登录的平台 只有微信扫码的需要获取其支付的openId if detect_wechat_client(request): if pay_gateway.pay_app_type == PayAppType.WECHAT: authBridge = WechatAuthBridge(pay_gateway.app) payOpenId = curUser.get_bound_pay_openid(authBridge.bound_openid_key) if payOpenId: return get_pay_gateway_redirect(payParam, adLink) else: return get_auth_redirect(payParam, authBridge, adLink) else: return JsonErrorResponse(description = u"平台配置错误,请稍后再试") # 支付宝平台登录 elif detect_alipay_client(request): return get_pay_gateway_redirect(payParam, adLink) # 其他平台暂时不支持 else: return NotSupportedPlatformResponseRedirect() @error_tolerate(logger = logger, nil = JsonErrorResponse(u"套餐获取失败")) @permission_required(ROLE.myuser) def getMonthlyPackage(request): """ 获取包月的套餐 :param request: :return: """ devNo = Device.get_dev_no_from_request(request) cardNo = request.GET.get("cardNo") device = Device.get_dev(devNo) card = Card.objects.filter(cardNo = cardNo, openId = request.user.openId, productAgentId = request.user.productAgentId).first() if device: group = Group.get_dealer_group(dealerId = device.ownerId, id = device.groupId) elif card: group = Group.get_dealer_group(dealerId = card.dealerId, id = card.groupId) else: return JsonErrorResponse(description = u"获取套餐失败(1000),请刷新重试") if not group: return JsonErrorResponse(description = u"套餐获取失败(1001),请刷新重试") monthPackage = group.monthlyRule if not monthPackage: return JsonOkResponse() return JsonOkResponse(payload = {"dataList": [monthPackage.to_dict()]}) @error_tolerate(nil = JsonErrorResponse(u"续费失败,请重新尝试"), logger = logger) @permission_required(ROLE.myuser) def checkVirtualCardRenew(request): """ 检查当前的虚拟卡是否可以续费 :param request: :return: """ cardId = request.GET.get("cardId") if not cardId: return JsonErrorResponse(description = u"未找到相应虚拟卡,请重试") vCard = UserVirtualCard.objects.get(id = cardId) if not Group.check_virtual_card_number(groupId = vCard.groupId): return JsonErrorResponse(description = u"该地址虚拟卡数量已经达到上限,请联系发卡经销商") return JsonOkResponse() @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger) @permission_required(ROLE.myuser) def getUserMonthlyPackage(request): """ 获取用户的 包月套餐 :param request: :return: """ openId = request.user.openId monthlyPackages = MonthlyPackage.get_user_all(openId) dataList = [_package.to_dict() for _package in monthlyPackages] return JsonOkResponse(payload = {"dataList": dataList}) @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger) @permission_required(ROLE.myuser) def getMonthlyPackageUseDetail(request): """ 获取 用户的使用详情 :param request: :return: """ monthlyPackageId = request.GET.get("monthlyPackageId") pageIndex = int(request.GET.get("pageIndex", 1)) pageSize = int(request.GET.get("pageSize", 10)) monthlyPackage = MonthlyPackage.objects.get(id = monthlyPackageId) useDetail = monthlyPackage.get_used_detail() # 获取使用的总的数量 添加上订单的ID 方便前台跳转 total = len(useDetail) result = useDetail[pageSize * (pageIndex - 1): pageSize * pageIndex] orderNos = [_item.get("orderNo") for _item in result] consumeRecords = ConsumeRecord.objects.filter(openId = request.user.openId, orderNo__in = orderNos).only("openId", "orderNo", "id", "dateTimeAdded") dataList = [ {"id": consume.id, "orderNo": consume.orderNo, "orderTime": consume.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")} for consume in consumeRecords ] return JsonOkResponse(payload = {"total": total, "dataList": dataList}) @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger) @permission_required(ROLE.myuser) def supportPayment(request): def get_dealer(request): logicalCode = request.GET.get('logicalCode', None) if logicalCode: device = Device.get_dev_by_logicalCode(logicalCode) if not device: logger.info('can not find device. logicalCode={}'.format(logicalCode)) return None else: return device.owner else: groupId = request.GET.get('groupId', None) if not groupId: logger.info('can not find group. groupId={}'.format(groupId)) return None else: group = Group.get_group(groupId) # type: GroupDict if not group: logger.info('can not find group. groupId={}'.format(groupId)) return None else: return group.owner dealer = get_dealer(request) if dealer is None: return JsonErrorResponse(description = u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1013)') return JsonOkResponse(description = u'无商户配置') @permission_required(ROLE.myuser) def getAlipayAd(request): """ 领取红包福利任务 :param request: :return: """ try: user = request.user # type: MyUser logicalCode = request.GET.get('logicalCode', '') pageIndex = int(request.GET.get('pageIndex', 0)) pageSize = int(request.GET.get('pageSize', 10)) chargeIndex = request.GET.get('chargeIndex', '') dev = Device.get_dev_by_l(logicalCode) # Type:DeviceDict from apps.web.core.models import SystemSettings if user.gateway != AppPlatformType.ALIPAY: return JsonOkResponse(payload = {}) if not dev: return JsonOkResponse(payload = {}) if not Redpack.can_use(dealer = dev.owner, devTypeCode = dev.devTypeCode): return JsonOkResponse(payload = {}) if not DevRegToAli.objects.filter(logicalCode = logicalCode).first(): reg_result = DevRegToAli.reg_to_aliyun_v3(dev) if not reg_result: return JsonOkResponse() if 'disable_alipay_ruhui' in dev.owner.features: ruhui = {} elif SystemSettings.disable_alipay_ruhui(): ruhui = {} else: # 判断是否为蓝牙. 蓝牙为老流程 串口充电桩为新流程 if dev.channelType == DeviceChannelType.Channel_BT: showType = 'pop' else: # 1 确认显示方式 showType = 'footerTopRedpack' group = dev.group if group.get('beforeCharge'): showType = 'pop' if 'show_pop_ruhui' in dev.owner.features: showType = 'pop' elif 'show_top_ruhui' in dev.owner.features: showType = 'top' elif 'show_buttun_ruhui' in dev.owner.features: showType = 'buttun' # 2 请求 请求权益 创建红报 ruhui = RedpackBuilder.get_alipay_cpa_by_ruhui_v3(openId = user.openId, logicalCode = logicalCode, chargeIndex = chargeIndex, showType = showType) if ruhui: # 地址组启动强制充值, 后面的页面需要弹窗 比较复杂直接改为弹窗流程 group = dev.group if group.get('beforeCharge'): ruhui = {'url': ruhui['url'], 'money': ruhui['money'], 'showType': ruhui['showType'], 'urlId': ruhui['urlId']} else: pass if 'disable_alipay_laxin' in dev.owner.features: laxin = {} elif SystemSettings.disable_alipay_laxin(): laxin = {} else: # 拉新 dataList = RedpackBuilder.get_alipay_cpa_by_laxin(openId = user.openId) total = len(dataList) if dataList: dataList = dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize] laxin = {'dataList': dataList, 'total': total} return JsonOkResponse(payload = {'laxin': laxin, 'ruhui': ruhui}) except Exception as e: logger.exception(e) return JsonOkResponse() @error_tolerate(u"获取权益失败", logger=logger) @permission_required(ROLE.myuser) def getAlipayAdResult(request): """ 领取红包福利任务 :param request: :return: """ alipayOpenId = request.GET.get('alipayOpenId') taskId = request.GET.get('taskId') taskType = request.GET.get('taskType') openId = request.GET.get('alipayOpenId') logicalCode = request.GET.get('logicalCode') dev = Device.get_dev_by_logicalCode(logicalCode) # 拉新结果处理 if taskId and alipayOpenId: if RedpackBuilder.query_cpa_laxin_task_status(taskId, alipayOpenId): redpack = RedpackBuilder.create_cpa_laxin_redpack(dev, taskId, openId, taskType) if redpack: return JsonOkResponse(payload={'showAmount': redpack.money.mongo_amount}) # 入会结果处理 redpackInfo = RedpackBuilder._pop_alipay_key(request.user.openId) if redpackInfo: showType = redpackInfo.get('showType') if showType == 'pop': return JsonOkResponse(payload={'showAmount': redpackInfo.get('money')}) return JsonResponse({'payload': {}}) @error_tolerate(u"获取权益失败", logger=logger) @permission_required(ROLE.myuser) def getMyRedpackList(request): user = request.user # type: MyUser pageIndex = int(request.GET.get('pageIndex', 0)) pageSize = int(request.GET.get('pageSize', 10)) dataList = Redpack.show_redpack(openId=user.openId) total = len(dataList) dataList = dataList[(pageIndex-1) * pageSize: pageIndex * pageSize] return JsonOkResponse(payload={'dataList':dataList, 'total':total}) @error_tolerate(nil = JsonErrorResponse(description = u'显示用户信息错误'), logger = logger) @permission_required(ROLE.myuser) def getCurrentFeePara(request): devNo = request.GET.get('devNo', None) devObj = Device.objects.get(devNo = devNo) feeMode = devObj.otherConf.get('feeMode',{}) timeRateList = [] shiduan = feeMode.get('shiduan','000000000000000000000000000000000000000000000000') nowTime = datetime.datetime.now().strftime('%H:%M') curFeeIndex = 0 for ii in range(48): startHour = 0 + ii/2 startMin = '00' if ii%2==0 else '30' endHour = startHour if ii%2==0 else startHour + 1 endMin = '30' if ii%2==0 else '00' startTime = '%02d:%s' % (startHour,startMin) endTime = '%02d:%s' % (endHour,endMin) timeRateList.append({'startTime':startTime,'endTime':endTime,'rate':shiduan[ii]}) if nowTime >= startTime and nowTime <= endTime: curFeeIndex = shiduan[ii] result = {'top_price_rate':feeMode.get('jianFee',0), 'top_price_service_rate':feeMode.get('jianServe',0), 'peak_price_rate':feeMode.get('fengFee',0), 'peak_price_service_rate':feeMode.get('fengServe',0), 'normal_price_rate':feeMode.get('pingFee',0), 'normal_price_service_rate':feeMode.get('pingServe',0), 'valley_price_rate':feeMode.get('guFee',0), 'valley_price_service_rate':feeMode.get('guServe',0), 'jishunScale':feeMode.get('jishunScale',0), 'timeRateList':timeRateList, 'curFeeIndex':curFeeIndex} return JsonOkResponse( payload = result ) @permission_required(ROLE.myuser) def getNearbyCarStation(request): # type: (WSGIRequest)->JsonResponse try: lng = float(request.GET.get('lng')) lat = float(request.GET.get('lat')) pageIndex = int(request.GET.get('pageIndex',1)) pageSize = int(request.GET.get('pageSize',10)) maxDistance = int(request.GET.get('distance', 5000)) logger.debug('now location. lat = %s; lng = %s' % (lat, lng)) if maxDistance > Const.NEAR_BY_MAX_DISTANCE: maxDistance = Const.NEAR_BY_MAX_DISTANCE if lng == 360 or lat == 360 or isnan(lng) or isnan(lat): return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'}) payload = getNearbyGroupsFromDB(lng, lat, pageIndex, pageSize, maxDistance, request.user.agentId, request.GET.get('chargeType', 0)) return JsonResponse({'result': 1, 'description': '', 'payload': payload}) except Exception as e: logger.exception(e) return JsonResponse({'result': 0, 'description': u'获取附近设备失败'}) def getNearbyGroupsFromDB(lng, lat, pageIndex, pageSize, maxDistance, agentId, chargeType): def hav(theta): s = sin(theta / 2) return s * s def get_distance_hav(lat0, lng0, lat1, lng1): if lat1 == 360 or lng1 == 360: return -1 EARTH_RADIUS = 6371000 lat0 = radians(lat0) lat1 = radians(lat1) lng0 = radians(lng0) lng1 = radians(lng1) dlng = fabs(lng0 - lng1) dlat = fabs(lat0 - lat1) h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng) return int(2 * EARTH_RADIUS * asin(sqrt(h))) if not agentId: logger.error('agent is null.') return { 'total': 0, 'items': [] } dealers = Dealer.get_dealers(agentId) if not dealers: return { 'total': 0, 'items': [] } queryDict = { 'ownerId': {'$in': dealers}, 'StationStatus':50,# 站点状态必须是正常使用中的 'location': { '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]}, '$maxDistance': maxDistance}}} if chargeType != '0': queryDict.update({'chargeType':int(chargeType)}) groups = SwapGroup.get_collection().find(queryDict) items = [] for swapInfo in groups[(pageIndex - 1) * pageSize:pageIndex * pageSize]: groupId = swapInfo['groupId'] group = Group.get_group(groupId) if group is None: continue swaplng = float(swapInfo['location']['coordinates'][0]) swaplat = float(swapInfo['location']['coordinates'][1]) distance = get_distance_hav(lat, lng, swaplat, swaplng) curFee = SwapGroup.get_cur_fee(swapInfo['PriceChargingInfo']) if curFee is None: continue # 统计交流、直流端口的情况 statsDict = SwapGroup.get_stats(groupId) info = { 'lng': swaplng, 'lat': swaplat, 'Pictures':[{'IsCover':pic['IsCover'],'PicID':pic['PicID'],'Url':pic['Url'],'Title':pic['Title']} for pic in swapInfo.get('Pictures',[])], 'PriceChargingInfo':[{'FeeTime':info['FeeTime'],'ElectricityFee':info['ElectricityFee'],'ServiceFee':info['ServiceFee']} for info in swapInfo['PriceChargingInfo']], 'StationName':group['groupName'] if u'充电站' in group['groupName'] else u'%s充电站' % group['groupName'], 'Address':group['address'], 'Distance':distance, 'BusineHours':swapInfo['BusineHours'], 'acPortsSum':{'allPorts':statsDict['acAllPorts'],'usedPorts':statsDict['acUsedPorts'],'usePorts':statsDict['acUsePorts']}, 'dcPortsSum':{'allPorts':statsDict['dcAllPorts'],'usedPorts':statsDict['dcUsedPorts'],'usePorts':statsDict['dcUsePorts']}, 'exceptSum':{'offline':statsDict['offline'],'fault':statsDict['fault']}, 'curFee':{"curElecFee": curFee['curElecFee'], "curServiceFee": curFee['curServiceFee']}, 'ParkFee':swapInfo['ParkFee'], 'tagDescList':SwapGroup.get_tag_desc_list_for_dict(swapInfo) } items.append(info) payload = { 'total': groups.count(), 'items': items } return payload @error_tolerate(logger = logger) def refundOrderNotifier(request, pay_app_type): """ 退款回调接口. 微信和京东聚合单独指定回调 支付宝支付和退款回调是一个 :param request: :param pay_app_type: :return: """ assert pay_app_type in PayAppType.choices(), 'not support this pay app type({})'.format(pay_app_type) notifier_cls = RefundManager().get_notifier(pay_app_type) response = notifier_cls(request, lambda filter: RefundMoneyRecord.get_record(**filter)).do(refund_post_pay) return response @error_tolerate(logger=logger) @permission_required(ROLE.myuser) def cancelWaitPay(request): """ 后支付用户拉起支付后, 没有输入密码 点击恢复到end状态 用于再次支付 """ payload = json.loads(request.body) ownerId = payload.get('ownerId') consumeRecordId = payload.get('consumeRecordId') if not ownerId or not consumeRecordId: return JsonErrorResponse(description='参数缺失, 请刷新后重试..') order = ConsumeRecord.objects.filter( id=consumeRecordId, ownerId=ownerId ).first() # type: ConsumeRecord if not order: return JsonErrorResponse(description='没有找到该订单') try: if order.status == order.Status.WAIT_PAY and not order.isPaid: order.status = order.Status.END order.save() except Exception as e: logger.exception("[cancelWaitPay] error = {}".format(e)) return JsonErrorResponse(description='参数错误') return JsonOkResponse(payload={}) @permission_required(ROLE.myuser) def cancelRechargeRecord(request): """ 用户取消订单 """ try: payload = json.loads(request.body) orderNo = payload.get('orderNo') record = RechargeRecord.objects(orderNo = orderNo).first() # type: RechargeRecord if not record: logger.warning('has no recharge record'.format(orderNo)) else: record.cancel() except Exception as e: logger.exception(e) finally: return JsonOkResponse()