# -*- coding: utf-8 -*- # !/usr/bin/env python """ web.agent.views ~~~~~~~~~ """ import base64 import logging import datetime import simplejson as json from bson.objectid import ObjectId from django.conf import settings from django.contrib import auth from django.core.handlers.wsgi import WSGIRequest from mongoengine.errors import DoesNotExist, NotUniqueError from operator import itemgetter from typing import Optional, cast from voluptuous import MultipleInvalid from apilib.monetary import RMB, Percent, Ratio from apilib.utils_datetime import to_datetime from apilib.utils_json import JsonResponse from apilib.utils_mongo import BulkHandler, BulkHandlerEx from apilib.utils_url import add_query from apps.thirdparties.aliyun import AliyunSlider from apps.web.agent.define import AGENT_INCOME_SOURCE, AGENT_INCOME_TYPE from apps.web.agent.models import Agent, AgentIncomeReport from apps.web.agent.withdraw import AgentWithdrawService, check_record_when_revoke_or_approve from apps.web.common.models import WithdrawRecord from apps.web.common.transaction import WithdrawStatus, WITHDRAW_PAY_TYPE, translate_withdraw_state from apps.web.common.validation import NAME_RE, check_phone_number from apps.web.constant import Const, DeviceCmdCode, APP_TYPE, ErrorCode from apps.web.core import ROLE from apps.web.core.auth.wechat import WechatAuthBridge from apps.web.core.db import prepare_query from apps.web.core.exceptions import ServiceException, InvalidFileSize, InvalidFileName from apps.web.core.file import AliOssFileUploader from apps.web.core.helpers import ActionDeviceBuilder from apps.web.core.messages.sms import agentRegisterSMSProvider, agentWithdrawSMSProvider from apps.web.core.networking import MessageSender from apps.web.core.payment import WithdrawGateway from apps.web.core.sysparas import SysParas from apps.web.core.utils import DefaultJsonErrorResponse, JsonErrorResponse, JsonOkResponse from apps.web.dealer.models import Dealer from apps.web.device.models import Device, Group, DeviceType, CheckDevice from apps.web.helpers import get_wx_config, current_platform, get_wechat_auth_bridge from apps.web.user.models import Card, UserVirtualCard from apps.web.utils import ( agent_login, error_tolerate, permission_required, features_required, concat_server_end_url, ErrorResponseRedirect, FrontEndResponseRedirect, ExternalResponseRedirect) logger = logging.getLogger(__name__) def login(request): # type: (WSGIRequest)->JsonResponse username = request.POST.get('username', None) password = request.POST.get('password', None) if not all([username, password]): response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}}) else: response = agent_login(request, logger, username, password) response.delete_cookie(key = 'JSESSIONID') return response @permission_required(ROLE.agent) def accountInfo(request): # type: (WSGIRequest)->JsonResponse currentAgent = request.user # type: Agent try: return JsonResponse({ 'result': 1, 'description': None, 'payload': { 'description': None, 'nickname': currentAgent.nickname, 'username': currentAgent.username, 'balance': currentAgent.total_balance, 'agentId': str(currentAgent.id), 'forceFollowGzh': currentAgent.forceFollowGzh, 'cardWechatInfo': { 'bound': True if 'openId' in currentAgent.cardWechatInfo else False, 'avatar': currentAgent.cardWechatInfo.get('avatar', ''), 'sex': currentAgent.cardWechatInfo.get('sex', ''), 'nickname': currentAgent.cardWechatInfo.get('nickname', '') }, 'boundCardName': currentAgent.boundCardName, 'boundCardPhone': currentAgent.boundCardPhone, 'avatar': currentAgent.my_avatar } }) except Exception, e: logger.exception('unable to get agent account info, error=%s' % e) return JsonResponse({'result': 0, 'description': u'无法获取代理商信息', 'payload': {}}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def resetPassword(request): # type: (WSGIRequest)->JsonResponse oldPassword = request.POST.get('oldPassword') password = request.POST.get('password') agent = request.user # type: Agent if agent.check_password(oldPassword): agent.set_password(password) else: return JsonResponse({'result': 0, 'description': u'原密码错误'}) return JsonResponse({'result': 1, 'description': None, 'payload': {}}) @permission_required(ROLE.agent) def homePageData(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent response = JsonResponse( { 'result': 1, 'description': None, 'payload': { 'permission': {'adShow': current_agent.adShow, 'deviceIncome': current_agent.deviceIncomeShow}, 'totalIncome': current_agent.today_income(), 'adIncome': current_agent.today_income(AGENT_INCOME_SOURCE.AD), 'cardFeeIncome': current_agent.today_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE), 'withdrawIncome': current_agent.today_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE), 'deviceIncome': current_agent.today_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE), 'bankwithdraw': current_agent.dealerBankWithdrawFee } }) response = Agent.record_cookie(str(request.user.id), response) return response @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def getIncome(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'adShow': current_agent.adShow, 'totalIncome': current_agent.aggregate_income(), 'totalAdIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.AD), 'totalCardFeeIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE), 'totalWithdrawIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE), 'totalDeviceIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE), 'totalInsuranceIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.INSURANCE), 'yesterdayTotalIncome': current_agent.yesterday_income(), 'yesterdayAdIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.AD), 'yesterdayCardFeeIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE), 'yesterdayWithdrawIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE), 'yesterdayDeviceIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE), 'yesterdayInsuranceIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.INSURANCE), } } ) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def getIncomeStatistics(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent source = request.GET.get('source') if source not in AGENT_INCOME_SOURCE.choices() and source: return JsonResponse({'result': 0, 'description': u'收入请求来源不明', 'payload': {}}) else: return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'totalIncome': current_agent.aggregate_income(source), 'yesterdayIncome': current_agent.yesterday_income(source), 'currentMonthIncome': current_agent.current_month_income(source) } } ) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def getIncomeList(request): # type: (WSGIRequest)->JsonResponse source = request.GET.get('source') if source not in AGENT_INCOME_SOURCE.choices() and source: return JsonResponse({'result': 0, 'description': u'收入请求来源不明', 'payload': {}}) query = prepare_query(request.GET, ('random',)) current_agent = request.user # type: Agent reports = AgentIncomeReport.objects(agentId = str(current_agent.id), **query.attrs).order_by('-dateTimeAdded') total = reports.count() monthlyIncome = current_agent.monthly_income(specific_source = source) dataList = [ { 'title': r.title, 'createdTime': r.date, 'monthlyIncome': monthlyIncome[(r.dateTimeAdded.year, r.dateTimeAdded.month)], 'amount': RMB(r.amount) } for r in reports.paginate(pageIndex = query.pageIndex, pageSize = query.pageSize) ] return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'total': total, 'dataList': dataList } }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def withdrawIncome(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE), 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE), 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE) } } ) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def withdrawIncomeList(request): # type: (WSGIRequest)->JsonResponse pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) endDate = request.GET.get('endDate') current_agent = request.user # type: Agent reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id), source = AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE, endDate = endDate) total = reports.count() monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE) dataList = [ { 'title': r.detail.get('name', '') + r.detail.get('withdrawAmount', ''), 'withdraw': r.detail.get('withdrawAmount'), 'time': r.date, 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)], 'amount': r.amount } for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize) ] return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'total': total, 'dataList': dataList } }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def cardFeeIncome(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE), 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE), 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE) } } ) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def cardFeeIncomeList(request): # type: (WSGIRequest)->JsonResponse pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) endDate = request.GET.get('endDate') current_agent = request.user # type: Agent reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id), source = AGENT_INCOME_SOURCE.DEALER_CARD_FEE, endDate = endDate) total = reports.count() monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.DEALER_CARD_FEE) dataList = [ { 'title': r.detail.get('name', ''), 'time': r.date, 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)], 'amount': r.amount } for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize) ] return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'total': total, 'dataList': dataList } }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def adIncome(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.AD), 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.AD), 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.AD) } } ) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def adIncomeList(request): # type: (WSGIRequest)->JsonResponse pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) endDate = request.GET.get('endDate') current_agent = request.user # type: Agent reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id), source = AGENT_INCOME_SOURCE.AD, endDate = endDate) total = reports.count() monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.AD) dataList = [ { 'title': u'经销商:%s,设备编号:%s,访问ID:%s, 广告ID: %s' % (r.detail.get('dealer'), r.detail.get('logicalCode'), r.detail.get('openId'), r.detail.get('adId', '')), 'time': r.date, 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)], 'amount': r.amount } for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize) ] return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'total': total, 'dataList': dataList } }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def deviceIncome(request): # type: (WSGIRequest)->JsonResponse current_agent = request.user # type: Agent return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE), 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE), 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE) } } ) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def deviceIncomeList(request): # type: (WSGIRequest)->JsonResponse pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) endDate = request.GET.get('endDate') current_agent = request.user # type: Agent reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id), source = AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE, endDate = endDate) total = reports.count() monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE) dataList = [ { 'title': r.detail.get('name', ''), 'time': r.date, 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)], 'amount': r.amount } for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize) ] return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'total': total, 'dataList': dataList } }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def groupListByDealer(request): # type: (WSGIRequest)->JsonResponse ownerId = str(request.user.id) pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) groupIds = Group.get_group_ids_of_dealer(ownerId) groupList = Group.get_groups_by_group_ids(groupIds).values() for grp in groupList: devNos = Device.get_devNos_by_group([grp['groupId']]) grp['equipmentCount'] = len(devNos) groupList.sort() return JsonResponse({ 'result': 1, 'description': None, 'payload': { 'total': len(groupList), 'dataList': groupList[(pageIndex - 1) * pageSize: pageIndex * pageSize] } }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def getDealerList(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') def count_devices(ownerId): devNoList = [device['devNo'] for device in Device.get_collection().find({'ownerId': ownerId, 'groupId': {'$ne': ''}}, {'devNo': 1, '_id': 0})] allCount = len(devNoList) devDict = Device.get_dev_by_nos(devNoList) if not devDict: return 0, 0, 0, 0, 0 onlineCount = 0 expire_count = 0 to_expire_count = 0 for devNo, dev in devDict.items(): if dev.online: onlineCount += 1 if dev.is_expired: expire_count += 1 if dev.is_to_expired: to_expire_count += 1 offlineCount = allCount - onlineCount return onlineCount, offlineCount, allCount, expire_count, to_expire_count dealers = Dealer.objects(agentId = str(request.user.id)).search(searchKey) dataList = [] dealers_per_page = dealers.paginate(pageIndex, pageSize) for dealer in dealers_per_page: onlineCount, offlineCount, allCount, expireCount, toExpireCount = count_devices(str(dealer.id)) dataList.append({ 'name': dealer.nickname, 'id': str(dealer.id), 'tel': dealer.username, 'onCount': onlineCount, 'offlineCount': offlineCount, 'deviceCount': allCount, 'expireCount': expireCount, 'toExpireCount': toExpireCount, 'adShow': dealer.adShow, 'annualTrafficCost': dealer.annualTrafficCost, }) #: 暂时保持偏序,全序列需要优化实现 dataList.sort(key = itemgetter('deviceCount'), reverse = True) return JsonResponse({ 'result': 1, 'payload': { 'dataList': dataList, 'total': dealers.count() }, 'description': None }) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def getReferralDealerList(request): # type: (WSGIRequest)->JsonResponse """ 代理商获取旗下经销商列表 :param request: :return: """ dealers = Dealer.objects(agentId = str(request.user.id)) dealerNameIdMaps = [{'text': d.nickname, 'value': str(d.id)} for d in dealers] return JsonResponse({'result': 1, 'description': None, 'payload': {'dataList': dealerNameIdMaps}}) @permission_required(ROLE.agent) def verifyRegisterCode(request): # type: (WSGIRequest)->JsonResponse """ 代理商创建旗下经销商 :param request: :return: """ try: nickname = request.POST.get('userName') password = request.POST.get('password') phone = request.POST.get('phoneNumber') remark = request.POST.get('remark') agent = Agent.objects(id = str(request.user.id)).first() if agent is None: return JsonErrorResponse() Dealer.create_user( username = phone, password = password, nickname = nickname, remark = remark, agentId = str(agent.id), adShow = True, noAdPolicy = 'banner', annualTrafficCost = agent.annualTrafficCost if \ agent.annualTrafficCost > agent.trafficCardCost else agent.trafficCardCost, trafficCardCost = agent.trafficCardCost, withdrawFeeRatio = agent.withdrawFeeRatio if \ agent.withdrawFeeRatio > agent.withdrawFeeRatioCost else agent.withdrawFeeRatioCost ) logger.info('a new Dealer(nickname=%s) was created by Agent(id=%s)' % (nickname, str(request.user.id))) return JsonResponse({'result': 1, 'description': 'ok', 'payload': {}}) except NotUniqueError: return JsonResponse({'result': 0, 'description': u'已有相同手机号注册为经销商!', 'payload': {}}) except Exception, e: logger.exception(u'agent(name=%s) failed to create dealers, error=%s' % (request.user.nickname, str(e))) return JsonResponse({'result': 0, 'description': u'系统错误,请重试', 'payload': {}}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'LOGO文件存储失败,请重新试试')) @permission_required(ROLE.agent) def uploadLogo(request): # type: (WSGIRequest)->JsonResponse files = request.FILES.getlist('file') if not len(files): return JsonResponse({'result': 0, 'description': u'未知的logo文件文件信息,请重新试试', 'payload': {}}) uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'logo') logger.info('[uploadLogo] %s is being used' % (repr(uploader),)) try: outputUrl = uploader.upload() return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl}) except InvalidFileSize as 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 as 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': {}}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'二维码文件存储失败,请重新试试')) @permission_required(ROLE.agent) def uploadServiceQrcodeUrl(request): # type: (WSGIRequest)->JsonResponse 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 = 'qrcode') logger.info('[uploadServiceQrcodeUrl] %s is being used' % (repr(uploader),)) try: outputUrl = uploader.upload() return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl}) except InvalidFileSize as 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 as 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': {}}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'二维码文件存储失败,请重新试试')) @permission_required(ROLE.agent) def uploadServiceGzhQrcodeUrl(request): # type: (WSGIRequest)->JsonResponse 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 = 'qrcode') logger.info('[uploadServiceGzhQrcodeUrl] %s is being used' % (repr(uploader),)) try: outputUrl = uploader.upload() return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl}) except InvalidFileSize as 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 as 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.agent) def getAgentInfo(request): # type: (WSGIRequest)->JsonResponse currentAgent = request.user # type: Agent para = { 'productName': currentAgent.productName, 'productLogo': currentAgent.productLogo, 'serviceName': currentAgent.serviceName, 'servicePhone': currentAgent.servicePhone, 'serviceQrcodeUrl': currentAgent.serviceQrcodeUrl, 'gzhServiceQrcodeUrl': currentAgent.gzhServiceQrcodeUrl, 'title': currentAgent.title, 'desc': currentAgent.desc } return JsonResponse({'result': 1, 'description': u'', 'payload': para}) @permission_required(ROLE.agent) def saveAgentInfo(request): # type: (WSGIRequest)->JsonResponse agentId = str(request.user.id) try: brandData = json.loads(request.body) if NAME_RE.match(brandData['productName']) is None: logger.error('productName formatting error, name=%s' % brandData['productName']) return JsonResponse({"result": 0, "description": u"请输入正确格式的品牌名称"}) if brandData['serviceName']: if NAME_RE.match(brandData['serviceName']) is None: logger.error('serviceName formatting error, name=%s' % brandData['serviceName']) return JsonResponse({"result": 0, "description": u"请输入正确格式的客服名称"}) if brandData['servicePhone']: import re if re.match(r'^\d{5,}$', brandData['servicePhone']) is None: logger.error('servicePhone number format error, phone=%s' % brandData['servicePhone']) return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"}) servicePhone = brandData['servicePhone'] status, desc = agentRegisterSMSProvider.verify(servicePhone, brandData['code']) if not status: return JsonErrorResponse(desc) Agent.update_agent(agentId, brandData) except Exception, e: logger.exception('update Agent product information error=%s,agentId=%s' % (e, agentId)) return JsonResponse({'result': 0, 'description': u'更新代理商产品信息错误', 'payload': {}}) response = JsonResponse({'result': 1, 'description': '', 'payload': {}}) response = Agent.record_cookie(agentId, response) return response @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def getDealerInfo(request): # type: (WSGIRequest)->JsonResponse """ 获取旗下经销商的配置信息(提现费率,流量费用...) :param request: :return: """ dealerId = request.GET.get('id') try: dealer = Dealer.objects(id = dealerId).get() # type: Dealer return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'withdrawFeeRatio': dealer.withdrawFeeRatio, 'withdrawFeeRatioCost': request.user.withdrawFeeRatio, 'annualTrafficCost': dealer.annualTrafficCost, 'adShow': dealer.adShow, 'agentProfitShare': dealer.agentProfitShare, 'agentMerProfitShare': dealer.agentMerProfitShare, 'limitDevNum': dealer.limitDevNum, 'isShowBanner': dealer.isShowBanner, 'hasTempPackage': dealer.hasTempPackage, 'agentProxyServicePhone': dealer.linkageSwitch.agentProxyServicePhone } } ) except DoesNotExist: return JsonResponse({'result': 0, 'description': u'经销商不存在,请刷新后再试', 'payload': {}}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def setDealerWithdrawFeeRatio(request): # type: (WSGIRequest)->JsonResponse """ 设置旗下经销商提现手续费用 :param request: :return: """ payload = json.loads(request.body) dealer = Dealer.objects(id = str(payload['id'])).get() if 'withdrawFeeRatio' not in payload: return JsonErrorResponse(description = u'提现手续费没有输入') withdrawFeeRatio = Ratio(payload.get('withdrawFeeRatio')) if withdrawFeeRatio < Const.MIN_DEALER_WITHDRAW_FEE_RATIO or withdrawFeeRatio > Const.MAX_DEALER_WITHDRAW_FEE_RATIO: return JsonErrorResponse(description = u'提现手续费输入错误') # 有资金池客户可以自行设置提现费率, 平台不做限制 if request.user.customizedWechatCashflowAllowable is not True: agent = Agent.objects(id = dealer.agentId).first() if not agent: return JsonErrorResponse(description = u'不存在的代理商') if withdrawFeeRatio < agent.withdrawFeeRatio: return JsonErrorResponse(description = u'提现手续费不能低于厂商提现手续费下限(千分之{})'.format(agent.withdrawFeeRatio)) if withdrawFeeRatio < agent.withdrawFeeRatioCost: return JsonErrorResponse(description = u'提现手续费不能低于平台手续费最低值(千分之{})'.format(agent.withdrawFeeRatioCost)) updated = dealer.update(withdrawFeeRatio = withdrawFeeRatio.mongo_amount) if updated: return JsonResponse({'result': 1, 'description': None, 'payload': {}}) else: return JsonErrorResponse(description = u'设置失败,请重试') @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def setDealerAnnualTrafficCost(request): # type: (WSGIRequest)->JsonResponse """ 设置旗下经销商每年流量费用 :param request: :return: """ currentAgent = request.user # type: Agent payload = json.loads(request.body) dealerId = payload['id'] annualTrafficCost = RMB(payload['annualTrafficCost']) if annualTrafficCost < currentAgent.annualTrafficCost: return JsonResponse( {'result': 0, 'description': u'流量卡年费不能少于%.02f元' % currentAgent.annualTrafficCost, 'payload': {}}) try: dealer = Dealer.objects.get(id = dealerId) # type: Dealer dealer.annualTrafficCost = annualTrafficCost dealer.save() return JsonResponse({'result': 1, 'description': None, 'payload': {}}) except DoesNotExist: return JsonResponse({'result': 0, 'description': u'经销商不存在,请刷新后再试', 'payload': {}}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def setBatchDealerAnnualTrafficCost(request): # type: (WSGIRequest)->JsonResponse currentAgent = request.user # type: Agent payload = json.loads(request.body) dealerIds = [ObjectId(id_) for id_ in payload['ids']] annualTrafficCost = RMB(payload['annualTrafficCost']) if annualTrafficCost < currentAgent.annualTrafficCost: return JsonErrorResponse(description = u'流量卡年费不能少于%s元' % currentAgent.annualTrafficCost) Dealer.set_traffic_costs_multiply(dealer_ids = dealerIds, cost = annualTrafficCost) return JsonResponse({'result': 1, 'description': None, 'payload': {}}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def setDealerAgentProfitShare(request): # type: (WSGIRequest)->JsonResponse """ 代理商设置经销商设备经营提成比例 :param request: :return: """ payload = json.loads(request.body) dealer = Dealer.objects.get(id = payload['id']) # type: Dealer agentProfitShare = Percent(payload['agentProfitShare']) try: maxProfitShare = Percent("100.0") minProfitShare = Percent('0.0') if agentProfitShare < minProfitShare or agentProfitShare > maxProfitShare: return JsonErrorResponse( description = u'分成比例错误,当前最大分成比例 {},最小分成比例 {}'.format(maxProfitShare, minProfitShare)) updated = dealer.set_agent_profit_share(agentProfitShare) if not updated: return JsonErrorResponse(description = u'更新错误,请重试') return JsonResponse({'result': 1, 'description': None, 'payload': {}}) except DoesNotExist: return JsonErrorResponse(description = u'经销商不存在,请刷新后再试') @error_tolerate(nil = JsonErrorResponse(u'设备类型不支持'), logger = logger) @permission_required(ROLE.agent) def getPackageList(request): # type: (WSGIRequest)->JsonResponse devTypeId = request.GET.get('typeId', None) if not devTypeId: return JsonErrorResponse(description = u'设备类型为空') dealerId = request.GET.get('dealerId', None) from apps.web.dealer.models import Dealer try: dealer = Dealer.objects.get(id = dealerId) # type: Dealer except DoesNotExist: return JsonErrorResponse(description = u'经销商不存在') if devTypeId in dealer.defaultWashConfig: dataList = dealer.defaultWashConfig[devTypeId] else: dataList = DeviceType.objects(id = str(devTypeId)).get().package return JsonResponse({'result': 1, 'description': None, 'payload': dataList}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def onPoints(request): # type: (WSGIRequest)->JsonResponse """ 远程上分, 代理商通过上分测试机器系统流程正确。 :param request: :return: """ logicalCode = request.POST.get('logicalCode', None) devNo = Device.get_devNo_by_logicalCode(logicalCode) dev = Device.get_dev(devNo) if not dev: return JsonErrorResponse(description = u'设备不存在') ruleId = request.POST.get('ruleId', 1) # 到设备上获取驱动编码信息 devInfo = MessageSender.send(device = dev, cmd = DeviceCmdCode.GET_DEVINFO, payload = {'IMEI': dev['devNo']}) if devInfo.has_key('rst') and devInfo['rst'] != 0: if devInfo['rst'] == -1: return JsonResponse({'result': 0, 'description': u'设备正在玩命找网络,设备是否上线有问题?'}) elif devInfo['rst'] == 1: return JsonResponse({'result': 0, 'description': u'模块之间的串口通讯有问题, 设备的串口接线是否有问题?'}) if devInfo.has_key('driverCode'): type_code = devInfo['driverCode'] else: type_code = Const.DEVICE_TYPE_CODE_PULSE try: device_adapter = ActionDeviceBuilder.create_action_device(dev, typeCode = type_code) result = device_adapter.test(coins = ruleId) if 'rst' in result and result['rst'] != 0: if result['rst'] == -1: return JsonResponse({'result': 0, 'description': u'设备正在玩命找网络,设备是否上线有问题?'}) elif result['rst'] == 1: return JsonResponse({'result': 0, 'description': u'模块之间的串口通讯有问题, 设备的串口接线是否有问题?'}) else: return JsonResponse({'result': 0, 'description': u'错误{}'.format(result['rst'])}) except ServiceException as e: return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}}) return JsonResponse({'result': 1, 'description': u'success'}) @permission_required(ROLE.agent) def labelBadDevice(request): # type: (WSGIRequest)->JsonResponse """ 标记坏的设备,便于我们记录错误信息 :param request: :return: """ logicalCode = request.POST.get('value', None) devNo = Device.get_devNo_by_logicalCode(logicalCode) desc = request.POST.get('desc', '') if not devNo: return JsonResponse({'result': 0, 'description': u'设备不存在'}) try: CheckDevice.get_collection().update_one({'imei': devNo}, {'$set': {'testResultDesc': desc}}, upsert = False) except Exception as e: logger.info('update check device error = %s' % e) return JsonResponse({'result': 0, 'description': 'update check device error=%s' % e}) return JsonResponse({'result': 1, 'description': u'success'}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.manager, ROLE.advertisement, ROLE.advertiser) def getAgentsDetailList(request): # type: (WSGIRequest)->JsonResponse """ 渲染代理商列表 :param request: :return: """ manager_id = str(request.user.id) page_index = int(request.GET.get('pageIndex', 1)) page_size = int(request.GET.get('pageSize', 100000)) search_key = request.GET.get('searchKey', None) total, items = Agent.filter(manager_id = manager_id, search_key = search_key, page_index = page_index, page_size = page_size) return JsonOkResponse(payload = {'total': total, 'dataList': items}) @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger) @permission_required(ROLE.agent) def equipmentList(request): """ 查看旗下经销商设备 :param request: :return: """ agentId = str(request.user.id) dealerId = request.GET.get("dealerId") online = request.GET.get("online") expireStatus = request.GET.get("expireStatus", "all") groupId = request.GET.get("equipmentGroupId") searchKey = request.GET.get("searchKey") dealer = Dealer.objects.get(id = dealerId) if dealer.agentId != agentId: return JsonErrorResponse(description = u"无权限") groupIds, devList = Device.filter( dealerId = dealerId, searchKey = searchKey, online = online, expireStatus = expireStatus, equipmentGroupId = groupId ) return JsonResponse({ 'result': 1, 'description': None, 'payload': { 'total': len(groupIds), 'groupCount': len(devList), 'dataList': devList } }) @permission_required(ROLE.agent) def logout(request): # type: (WSGIRequest)->JsonResponse agentId = str(request.user.id) auth.logout(request) response = JsonResponse({'result': 1}) # type: JsonResponse response.set_cookie(key = 'agentId', value = agentId, max_age = 30 * 24 * 3600, domain = settings.COOKIE_DOMAIN) return response @permission_required(ROLE.agent) def wxconfig(request): # type: (WSGIRequest)->JsonResponse url = request.GET.get('href') if not url: return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}}) currentAgent = request.user # type: cast(Agent) value = get_wx_config(currentAgent, url) return JsonResponse({'result': 1, 'description': None, 'payload': {'wxconfig': value}}) @permission_required(ROLE.agent) def toggleSwitches(request): # type: (WSGIRequest)->JsonResponse agentId = str(request.user.id) try: Agent.update_agent(agentId, json.loads(request.body)) except Exception, e: logger.exception('update Agent product information error=%s,agentId=%s' % (e, agentId)) return JsonResponse({'result': 0, 'description': u'更新代理商产品信息错误', 'payload': {}}) response = JsonResponse({'result': 1, 'description': '', 'payload': {}}) return response # 代理商获取短信验证码 @error_tolerate(nil = DefaultJsonErrorResponse) def getCheckCode(request): # type: (WSGIRequest)->JsonResponse payload = json.loads(request.body) toNumber = payload.get('phone', None) agent = Agent.objects(username = toNumber).first() if not agent: return JsonResponse({'result': 0, 'description': u'该代理商用户不存在'}) productName = agent.productName or agent.primary_agent.productName sessionId = payload.get('csessionid', None) sig = payload.get('sig', None) token = payload.get('nc_token', None) result = eval(AliyunSlider().check_validation_results(sessionId, sig, token)) if type(result) is dict: resultCode = result.get('Code', 900) else: resultCode = 900 if resultCode == 100: status, msg = agentRegisterSMSProvider.get(phoneNumber = toNumber, productName = productName, vendor = SysParas.get_sms_vendor(agent.smsVendor)) if not status: return JsonResponse({'result': 0, 'description': msg}) else: return JsonResponse({'result': 1, 'description': ''}) else: return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'}) # 代理商验证短信验证码 @error_tolerate(nil = DefaultJsonErrorResponse) def verifyForgetCode(request): # type: (WSGIRequest)->JsonResponse phone = request.POST.get('phone', None) code = request.POST.get('code', None) password = request.POST.get('password', '') status, desc = agentRegisterSMSProvider.verify(phone, code) if not status: return JsonErrorResponse(desc) if password == '': return JsonErrorResponse(u"请输入密码") agent = Agent.objects(username = phone).first() # type: Optional[Agent] agent.set_password(password) agent.unlock_login() return JsonResponse({"result": 1, "description": None, "payload": {}}) @error_tolerate(nil = DefaultJsonErrorResponse) @permission_required(ROLE.agent) def walletData(request): # type: (WSGIRequest)->JsonResponse agent = request.user # type: Agent customized_source_key = agent.current_wallet_withdraw_source_key inhouse_source_key = Agent.get_inhouse_prime_agent().current_wallet_withdraw_source_key payload = { } withdraw_income_list = [] for source_key, balance in agent.withdrawBalance.iteritems(): if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0): withdraw_income_list.append({ 'id': source_key, 'balance': balance.balance, 'name': current_platform(source_key, customized_source_key), 'current': source_key == customized_source_key }) if len(withdraw_income_list) > 0: payload.update({ AGENT_INCOME_TYPE.DEALER_WITHDRAW_FEE: withdraw_income_list }) traffic_income_list = [] for source_key, balance in agent.trafficBalance.iteritems(): if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0): traffic_income_list.append({ 'id': source_key, 'balance': balance.balance, 'name': current_platform(source_key, inhouse_source_key), 'current': source_key == inhouse_source_key }) if len(traffic_income_list) > 0: payload.update({ AGENT_INCOME_TYPE.DEALER_CARD_FEE: traffic_income_list }) device_income_list = [] for source_key, balance in agent.deviceBalance.iteritems(): if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0): device_income_list.append({ 'id': source_key, 'balance': balance.balance, 'name': current_platform(source_key, customized_source_key), 'current': source_key == customized_source_key }) if len(device_income_list) > 0: payload.update({ AGENT_INCOME_TYPE.DEALER_DEVICE_FEE: device_income_list }) return JsonResponse({'result': 1, 'description': None, 'payload': payload}) @permission_required(ROLE.agent) def getWithdrawCode(request): # type: (WSGIRequest)->JsonResponse phone = request.user.username agentId = str(request.user.id) agent = Agent.objects(id = agentId).first() if not agent: return JsonResponse({"result": 0, "description": u"没有找到代理商", 'payload': {}}) productName = agent.productName status, msg = agentWithdrawSMSProvider.get(phoneNumber = phone, productName = productName, vendor = SysParas.get_sms_vendor(agent.smsVendor)) if not status: return JsonResponse({'result': 0, 'description': msg}) else: return JsonResponse({'result': 1, 'description': ''}) @permission_required(ROLE.agent) def agentWithdraw(request): # type: (WSGIRequest)->JsonResponse logger.info(u'agent(phone=%s) 发起提现,具体数据为 %s' % (str(request.user.username), request.body.decode('utf-8'))) payload = json.loads(request.body) open_id = payload.get('openId') if not open_id: return JsonResponse({"result": 0, "description": u'鉴权失败,请刷新后再试', 'payload': {}}) request.user.withdraw_open_id = open_id amount = RMB(payload.get('amount', 0.0)) pay_type = payload.get('payType') assert pay_type in ( WITHDRAW_PAY_TYPE.WECHAT, WITHDRAW_PAY_TYPE.BANK, WITHDRAW_PAY_TYPE.ALIPAY), 'not support this pay type' assert amount > RMB(0), 'amount must be bigger than zero' status, msg = request.user.withdraw_sms_provider.verify(phoneNumber = request.user.withdraw_sms_phone_number, smsCode = payload.get('code')) if not status: return JsonResponse({"result": 0, "description": msg, 'payload': {}}) withdraw_service = AgentWithdrawService(payee = request.user, income_type = payload.get('sourceType'), amount = amount, pay_type = pay_type, bank_card_no = payload.get('bankAccount', '')) return JsonResponse(withdraw_service.execute(source_key = payload.get('sourceId'), recurrent = False)) @permission_required(ROLE.agent) def withdrawalsHistoryList(request): # type: (WSGIRequest)->JsonResponse pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) agentId = str(request.user.id) total = WithdrawRecord.objects(ownerId = agentId, role = request.user.role).count() if total == 0: return JsonResponse({"result": 1, "description": None, 'payload': {"total": 0, "dataList": []}}) records = WithdrawRecord.objects(ownerId = agentId, role = request.user.role).order_by('-postTime') withdrawalList = [ { 'bankName': record.parentBankName, 'paymentId': str(record.id), 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"), 'amount': record.amount, 'statusText': translate_withdraw_state(record.status) } for record in records.paginate(pageIndex, pageSize) ] return JsonResponse({ "result": 1, "description": None, 'payload': { "total": total, "withdrawalTotal": RMB(records(status = WithdrawStatus.SUCCEEDED).sum('amount')), "dataList": withdrawalList } }) @permission_required(ROLE.agent) def paymentInfo(request): # type: (WSGIRequest)->JsonResponse agentId = str(request.user.id) paymentId = request.GET.get('paymentId', None) record = WithdrawRecord.objects(id = str(paymentId)).first() # type: Optional[WithdrawRecord] if not record: return JsonResponse({'result': 0, 'description': u'没有找到提现记录', 'payload': {}}) return JsonResponse({ 'result': 1, 'description': '', 'payload': { 'type': record.parentBankName, 'amount': record.amount, 'serviceFee': record.serviceFee, 'preBalance': record.balance, 'actualPay': record.actualPay, 'statusText': translate_withdraw_state(record.status), 'refunded': record.refunded, 'description': record.description, 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"), } }) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def getWalletWithdrawInfo(request): source_key = request.GET.get('sourceId') income_type = request.GET.get('sourceType') agent = Agent.objects(id = str(request.user.id)).first() phone = str(request.user.username) result = { "result": 1, "description": None, 'payload': { 'payOpenId': 'placeholder', 'phone': phone, 'balance': agent.sub_balance(income_type, source_key), 'withdrawFeeRatio': Const.PLATFORM_DEFAULT_WITHDRAW_FEE_RATIO, 'support': agent.withdraw_support(source_key) } } return JsonResponse(result) @permission_required(ROLE.agent) def updateInfo(request): # type: (WSGIRequest)->JsonResponse """ 支持代理商更改用户信息 :param request: :return: """ name = request.POST.get('name') if NAME_RE.match(name) is None: logger.info('update agent name doesn\'t fit format, name=%s' % (name.encode('utf-8'),)) return JsonResponse({"result": 0, "description": u'请输入正确格式的名称(2-20位)'}) agent = Agent.objects(id = request.user.id).first() # type: Optional[Agent] if agent is None: return JsonResponse({"result": 0, "description": u'该经销商不存在'}) updated = agent.update(nickname = name) if not updated: logger.info('Agent [updateInfo] failed, name=%s' % (name.encode('utf-8'),)) return JsonResponse({"result": 0, "description": u'更新失败,请重试'}) else: return JsonResponse({"result": 1, "description": None}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请刷新')) @permission_required(ROLE.agent) def getFeatureList(request): # type: (WSGIRequest)->JsonResponse """ :param request: :return: """ currentUser = request.user # type: Agent payload = json.loads(request.body) filter_list = payload['list'] if 'list' in payload else None features = {} all_features = currentUser.feature_boolean_map if filter_list: for feature_name in filter_list: if feature_name in all_features: features[feature_name] = all_features[feature_name] else: features[feature_name] = False else: features = all_features return JsonResponse({'result': 1, 'payload': features, 'description': ''}) @permission_required(ROLE.agent) def adminAgreeWallet(request): # type: (WSGIRequest)->JsonResponse """ 管理后台通过提现按钮,这里暂时继续支持,以作相对事件的应急处理与补充。 :param request: :return: """ def admin_dealer_withdraw(withdraw_record): # type: (WithdrawRecord)->None dealer = Dealer.objects(id = str(withdraw_record.ownerId)).get() # type: Dealer handler = dealer.new_withdraw_handler(withdraw_record) handler.approve() return JsonOkResponse(description = u'提现成功', payload = {}) def admin_agent_withdraw(withdraw_record): # type: (WithdrawRecord)->None """ :type withdraw_record: WithdrawRecord """ agent = Agent.objects(id = str(withdraw_record.ownerId)).get() # type: Agent handler = agent.new_withdraw_handler(withdraw_record) handler.approve() return JsonOkResponse(description = u'提现成功', payload = {}) payload = json.loads(request.body) order = str(payload.get('orderNo')) try: with WithdrawRecord.process_memcache_lock(order) as acquired: if acquired: withdraw_record = WithdrawRecord.objects(order = order).first() # WithdrawRecord try: check_record_when_revoke_or_approve(withdraw_record, str(request.user.id)) except ServiceException as e: return JsonResponse(e.result) if withdraw_record.role == ROLE.dealer: return admin_dealer_withdraw(withdraw_record) elif withdraw_record.role == ROLE.agent: return admin_agent_withdraw(withdraw_record) else: return JsonOkResponse(description = u'参数错误,请刷新后再试', payload = {}) else: # 重复丢弃该请求 logger.debug('duplicate request for WithdrawRecord. orderNo = %s' % order) except Exception, e: logger.exception(e) return JsonOkResponse(description = u'处理提现申请失败,请重试', payload = {}) @permission_required(ROLE.agent) def getWithdrawList(request): # type: (WSGIRequest)->JsonResponse """ 获取提现申请列表 :param request: :return: """ agentId = str(request.user.id) pageIndex = int(request.GET.get('pageIndex', 1)) pageSize = int(request.GET.get('pageSize', 10)) searchKey = request.GET.get('searchKey', None) date_start = request.GET.get('dateStart') date_end = request.GET.get('dateEnd') query = { 'payAgentId': agentId, 'postTime': { '$gte': to_datetime(date_start + " 00:00:00"), '$lte': to_datetime(date_end + " 23:59:59")} } status = int(request.GET.get('status')) if status == 0: query.update({ '$or': [{'status': WithdrawStatus.FAILED}, {'status': WithdrawStatus.PROCESSING, 'manual': True}]}) elif status == -1: pass else: query.update({'status': status}) records = WithdrawRecord.objects(__raw__ = query).search(searchKey).order_by('-postTime') total = records.count() dataList = [ { 'name': r.name, 'tel': r.phone, 'dateTime': r.postTime, 'orderNo': r.order, 'actualPay': r.actualPay, 'cardId': r.accountCode, 'cardUserName': r.cardUserName, 'bankName': r.parentBankName, 'subBankName': r.subBankName, 'operResult': r.status, 'payType': r.payType, 'amount': r.amount, 'remarks': r.remarks, 'manual': r.manual } for r in records.paginate(pageIndex, pageSize) ] return JsonOkResponse(description = '', payload = { 'total': total, 'dataList': dataList }) @error_tolerate(nil = DefaultJsonErrorResponse) @permission_required(ROLE.agent) def revokeWithdrawApplication(request): # type: (WSGIRequest)->JsonResponse """ 对于已经失败的提现单予以关闭 :param request: :return: """ payload = json.loads(request.body) order = str(payload.get('orderNo')) def revoke_dealer_withdraw(withdraw_record, remarks, description): # type: (WithdrawRecord, str, str)->None dealer = Dealer.objects(id = str(withdraw_record.ownerId)).get() # type: Dealer handler = dealer.new_withdraw_handler(withdraw_record) handler.revoke(remarks = remarks, description = description) return JsonOkResponse(description = u'关闭提现申请成功', payload = {}) def revoke_agent_withdraw(withdraw_record, remarks, description): # type: (WithdrawRecord, str, str)->None """ :type withdraw_record: WithdrawRecord """ agent = Agent.objects(id = str(withdraw_record.ownerId)).get() # type: Agent handler = agent.new_withdraw_handler(withdraw_record) handler.revoke(remarks = remarks, description = description) return JsonOkResponse(description = u'关闭提现申请成功', payload = {}) try: with WithdrawRecord.process_memcache_lock(order) as acquired: if acquired: record = WithdrawRecord.objects(order = payload.get('orderNo')).first() # type: WithdrawRecord try: check_record_when_revoke_or_approve(record, str(request.user.id)) except ServiceException as e: return JsonResponse(e.result) if record.role == ROLE.dealer: revoke_dealer_withdraw(record, u'资金池关闭订单', payload.get('reason', '')) elif record.role == ROLE.agent: revoke_agent_withdraw(record, u'资金池关闭订单', payload.get('reason', '')) return JsonOkResponse(description = u'关闭提现申请成功', payload = {}) else: # 重复提现, 丢弃该请求 logger.debug('duplicate request for WithdrawRecord. orderNo = %s' % order) except Exception, e: logger.exception(e) return JsonErrorResponse(description = u'处理提现申请失败,请联系客服处理', payload = {}) @permission_required(ROLE.agent) def getWithdrawDetail(request): # type: (WSGIRequest)->JsonResponse """ 获取经销商提现申请列表 :param request: :return: """ order = request.GET.get('orderNo') r = WithdrawRecord.objects().filter(order = order).first() # type: WithdrawRecord if not r: return JsonErrorResponse(u'提现申请不存在,请刷新') return JsonOkResponse(description = '', payload = { 'name': r.name, 'tel': r.phone, 'dateTime': r.postTime, 'orderNo': r.order, 'actualPay': r.actualPay, 'cardId': r.accountCode, 'cardUserName': r.cardUserName, 'bankName': r.parentBankName, 'subBankName': r.subBankName, 'operResult': r.status, 'payType': r.payType, 'amount': r.amount, 'serviceFee': r.serviceFee, 'actualPay': r.actualPay, 'beforeBalance': r.balance, 'remarks': r.remarks, 'dealerId': r.ownerId, 'manual': r.manual, 'role': r.role }) @error_tolerate(nil = DefaultJsonErrorResponse) @permission_required(ROLE.agent) def setLimitDevNum(request): # type: (WSGIRequest)->JsonResponse """ 设置经销商注册设备个数限制 :param request: :return: """ payload = json.loads(request.body) dealer = Dealer.objects(id = str(payload['id'])).first() if dealer is None: return JsonErrorResponse(description = u'不存在的经销商') dealer.limitDevNum = int(payload['limitDevNum']) dealer.save() return JsonOkResponse(description = u'设置成功', payload = {}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请稍后再试')) def withdrawEntry(request): # type: (WSGIRequest)->JsonResponse user = request.user # type: Agent source_key = request.GET.get('sourceId') if not WithdrawGateway.is_ledger(source_key): return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10003)') source_type = request.GET.get('sourceType') assert source_type in AGENT_INCOME_TYPE.choices(), 'invalid dealer income type' if source_key not in user.balance_dict(source_type): return ErrorResponseRedirect(error = u'提现参数错误,请刷新后重试') is_ledger, agent, withdraw_gateway_list = Agent.withdraw_gateway_list(source_key) if not is_ledger: return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10005)') wechat_withdraw_gateway = withdraw_gateway_list['wechat'] if wechat_withdraw_gateway.support_withdraw and not wechat_withdraw_gateway.manual_withdraw: code = request.GET.get('code', None) if not code: redirect = request.GET.get('redirect') return ExternalResponseRedirect( WechatAuthBridge(wechat_withdraw_gateway.app).generate_auth_url_base_scope(concat_server_end_url( uri = '/agent/withdraw/entry?sourceType={source_type}&sourceId={source_key}'.format( source_type = source_type, source_key = source_key )), payload = base64.b64encode(redirect))) else: auth_bridge = WechatAuthBridge(wechat_withdraw_gateway.app) openId = auth_bridge.authorize(code) if openId is not None: redirect = base64.b64decode(request.GET.get('payload')) redirect = add_query(redirect, { 'sourceType': source_type, 'sourceId': source_key, 'openId': openId }) return FrontEndResponseRedirect(redirect) else: return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试') else: redirect = request.GET.get('redirect') redirect = add_query(redirect, { 'sourceType': source_type, 'sourceId': source_key, 'openId': '' }) return FrontEndResponseRedirect(redirect) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def bindWechatEntry(request): # type: (WSGIRequest)->JsonResponse """ 跳转到微信授权页面绑定 :param request: :return: """ current_agent = request.user # type: cast(Agent) auth_bridge = get_wechat_auth_bridge(source = current_agent, app_type = APP_TYPE.WECHAT_AUTH) auth_code = request.GET.get(auth_bridge.auth_code_key, None) if auth_code: openId = auth_bridge.authorize(auth_code) bound_info = { 'appId': auth_bridge.app.appid, 'openId': openId, 'boundTime': datetime.datetime.now() } logger.debug( 'agent(id={}) is binding wechat, bridge = {}, bound = {}'.format(str(current_agent.id), auth_bridge, str(bound_info))) if 'payload' in request.GET: redirect = base64.b64decode(request.GET.get('payload')) else: redirect = '/agents/bind-id.html' bind_type = request.GET.get('bindType') if bind_type == 'bindCard': bound_info_updated = current_agent.update(cardWechatInfo = bound_info) if bound_info_updated: add_query(redirect, {'result': 'ok'}) return FrontEndResponseRedirect(redirect) else: add_query(redirect, {'result': 'error'}) return FrontEndResponseRedirect(redirect) else: add_query(redirect, {'result': 'error'}) return FrontEndResponseRedirect(redirect) else: bind_type = request.POST.get('bindType') redirect = request.POST.get('redirect', '/agents/bind-id.html') url = auth_bridge.generate_auth_url_base_scope( redirect_uri = concat_server_end_url(uri = '/agent/wechat/bind?bindType={}'.format(bind_type)), payload = base64.b64encode(redirect) if redirect else '') return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'redirect_uri': url } }) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def getBoundWechat(request): # type: (WSGIRequest)->JsonResponse ''' 获取绑定后台openId的用户信息 :param request: :return: ''' current_agent = request.user # type: cast(Agent) bind_type = request.GET.get('bindType') if bind_type == 'bindCard': return JsonResponse( { 'result': 1, 'description': None, 'payload': { 'bound': True if current_agent.cardWechatInfo.get('openId', None) else False, 'avatar': current_agent.cardWechatInfo.get('avatar', ''), 'sex': current_agent.cardWechatInfo.get('sex', ''), 'nickname': current_agent.cardWechatInfo.get('nickname', '') } }) else: return JsonResponse({'result': 0, 'description': u'获取绑定的微信信息失败', 'payload': {}}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def batchBindCard(request): # type: (WSGIRequest)->JsonResponse ''' 批量绑定 :param request: :return: ''' current_agent = request.user # type: cast(Agent) payload = json.loads(request.body) card_name = payload.get('cardName', None) if not card_name: return JsonResponse({'result': 0, 'description': u'绑定卡主姓名为空', 'payload': {}}) phone = payload.get('phone', None) if not check_phone_number(phone): return JsonResponse({'result': 0, 'description': u'绑定卡主手机号为空或者不合法', 'payload': {}}) card_no_list = payload.get('cardNo') dealer_id = payload.get('dealerId') dealer = Dealer.objects(id = dealer_id).first() # type: Dealer if not dealer or dealer.agentId != str(current_agent.id): return JsonResponse({'result': 0, 'description': u'经销商不存在或者不属于本代理商,请刷新数据后再试', 'payload': {}}) group_id = payload.get('groupId') group = Group.objects(id = group_id).first() # type: Group if not group or group.ownerId != dealer_id: return JsonResponse({'result': 0, 'description': u'投放组地址不存在或者不属于选择的经销商,请刷新数据后再试', 'payload': {}}) if 'openId' not in current_agent.cardWechatInfo: return JsonResponse({'result': 0, 'description': u'请先绑定微信', 'payload': {}}) if current_agent.boundCardName != card_name or current_agent.boundCardPhone != phone: current_agent.boundCardName = card_name current_agent.boundCardPhone = phone current_agent.save() err_list = [] request = [] bulker = BulkHandlerEx(Card.get_collection()) # type: BulkHandler for card_no in card_no_list: if not Card.check_card_no(card_no): err_list.append({ 'cardNo': card_no, 'code': 1 }) continue bulker.insert({ 'openId': current_agent.cardWechatInfo['openId'], 'cardNo': card_no, 'agentId': str(current_agent.id), 'cardName': card_name, 'phone': phone, 'groupId': str(group_id), 'dealerId': str(dealer_id) }) result = bulker.execute() if result['success'] == 0: return JsonResponse({'result': 0, 'description': u'全部导入失败,请检查文件格式后重试', 'payload': {}}) else: if len(result['info']['writeErrors']) != 0: for item in result['info']['writeErrors']: code = item['code'] op = item['op'] err_list.append({'cardNo': op.get('cardNo'), 'code': code}) if len(err_list) > 0: if len(err_list) == len(card_no_list): return JsonResponse({'result': 0, 'description': u'导入失败,请检查文件格式后重试', 'payload': {}}) else: return JsonResponse({'result': 1, 'description': u'部分导入成功,请重试', 'payload': {'errorList': err_list}}) else: return JsonResponse({'result': 1, 'description': u'导入成功', 'payload': {'errorList': []}}) @error_tolerate(logger = logger, nil = JsonErrorResponse(u"查询错误")) @features_required("agent_card_management") @permission_required(ROLE.agent) def getUserCardList(request): """ 代理商查看卡列表 :param request: :return: """ # 参数校验 agentId = str(request.user.id) pageSize = int(request.GET.get("pageSize", 10)) pageIndex = int(request.GET.get("pageIndex", 1)) dealerId = request.GET.get("dealerId") searchKey = request.GET.get("searchKey") status = request.GET.get("status") filters = { "productAgentId": agentId, } if dealerId: filters.update({"dealerId": dealerId}) else: filters.update({"dealerId": ""}) if status: status = bool(int(status)) if not status: filters.update({"openId": ""}) else: filters.update({"openId__ne": ""}) cards = Card.objects.filter(**filters).search(searchKey) total = cards.count() dataList = list() for card in cards.skip((pageIndex - 1) * pageSize).limit(pageSize): try: tempData = card.to_dict() except Exception as e: logger.exception(e) continue if not card.boundVirtualCardId: dataList.append(tempData) continue try: vCard = UserVirtualCard.objects.get(id = card.boundVirtualCardId) tempData.update({"vCardNo": vCard.cardNo, "vCardId": card.boundVirtualCardId}) except Exception as e: logger.exception(e) continue dataList.append(tempData) payload = { "total": total, "dataList": dataList, } return JsonOkResponse(payload = payload) @error_tolerate(logger = logger, nil = JsonErrorResponse(u"清除错误")) @features_required("agent_card_management") @permission_required(ROLE.agent) def clearCardBind(request): """ 代理商 清除卡片的经销商绑定信息 :param request: :return: """ payload = json.loads(request.body) cardId = payload.get("cardId", "") try: card = Card.objects.get(id = cardId, productAgentId = str(request.user.id)) except DoesNotExist: return JsonErrorResponse(u"未查询到卡片,请刷新页面试试") card.update( dealerId = "", groupId = "", remarks = "", balance = RMB(0), lastMaxBalance = RMB(0), devNo = "", devTypeCode = "", frozen = False, status = "active", openId = "", cardName = "", phone = "", nickname = "", boundVirtualCardId = None, managerialAppId = "", managerialOpenId = "" ) return JsonOkResponse() @error_tolerate(logger = logger, nil = JsonErrorResponse(u"清除错误")) @features_required("agent_card_management") @permission_required(ROLE.agent) def clearCardVirtualBind(request): """ 解除虚拟卡的绑定 :param request: :return: """ payload = json.loads(request.body) cardId = payload.get("cardId") virtualCardId = payload.get("vCardId") try: card = Card.objects.get(id = cardId, producttAgentId = str(request.user.id)) except DoesNotExist: return JsonErrorResponse(u"未查询到卡片,请刷新页面试试") if virtualCardId is None: 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'解绑失败') @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def setShowBanner(request): """ 设置经销商是否显示代理商的banner :param request: :return: """ payload = json.loads(request.body) dealer = Dealer.objects(id = payload['id']).first() if dealer is None: return JsonErrorResponse(u'不存在的经销商') dealer.isShowBanner = payload['value'] dealer.save() return JsonOkResponse() @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def setHasTempPackageSwitch(request): """ 设置经销商是否启用临时套餐 :param request: :return: """ payload = json.loads(request.body) dealer = Dealer.objects(id = payload['id']).first() if dealer is None: return JsonErrorResponse(u'不存在的经销商') dealer.hasTempPackage = payload['value'] dealer.save() return JsonOkResponse() @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def setAgentProxyServicePhone(request): """ 设置代理商接管客诉 :param request: :return: """ payload = json.loads(request.body) dealer = Dealer.objects(id = payload['id']).first() if dealer is None: return JsonErrorResponse(u'不存在的经销商') dealer.linkageSwitch.agentProxyServicePhone = payload['value'] dealer.save() return JsonOkResponse() @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误')) @permission_required(ROLE.agent) def setBankWithdrawFee(request): """ 设置经销商提现银行卡转账手续费 :param request: :return: """ request.user.dealerBankWithdrawFee = request.GET.get('bankWithdrawFee', False) request.user.save() return JsonOkResponse() @permission_required(ROLE.agent) @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请稍后再试')) def findDevTypeCandidate(request): dealerId = request.GET.get('customerId') dealer = Dealer.objects(id = dealerId).first() if not dealer or dealer.agentId != str(request.user.id): return JsonErrorResponse(description = u'经销商不存在,请刷新重试') logicalCode = request.GET.get('logicalCode') devObj = Device.objects(logicalCode = logicalCode).first() # type: Device if not devObj: return JsonErrorResponse(description = u'设备不存在,请扫正确的设备二维码') _, all = DeviceType.find_candidate(devObj, dealer) return JsonOkResponse(payload = {"total": len(all), "dataList": all})