# -*- coding: utf-8 -*-
# !/usr/bin/env python
import datetime
import hashlib
import logging
import re
import ssl
import subprocess
import time
import urllib2
import simplejson as json
import xmltodict
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
from django.views.generic.base import View
from pymongo.results import UpdateResult
from typing import TYPE_CHECKING, Iterable, Dict
from voluptuous import MultipleInvalid
from apilib.monetary import RMB
from apilib.utils import generate_RSA_key_pairs
from apilib.utils_datetime import to_datetime
from apilib.utils_string import cn
from apps import serviceCache
from apps.web import district
from apps.web.ad.models import Advertisement, AdStatistics
from apps.web.agent.models import MoniApp
from apps.web.common.models import AddressType, WithdrawRecord, WithdrawBanks, WithdrawDistrict, \
WithdrawBranchBanks, WithdrawBankCard
from apps.web.common.models import FrontendLog, FAQ
from apps.web.common.transaction.pay.alipay import AliPayWithdrawNotifier
from apps.web.common.utils import WechatMessage, WechatText, WechatMenu, WechatSubscribe, WechatUnSubscribe, \
WechatScanEvent, MessageHandler
from apps.web.constant import Const, AppPlatformType, AdSpace, USER_RECHARGE_TYPE
from apps.web.core import ROLE
from apps.web.core.exceptions import InvalidFileSize, InvalidFileName
from apps.web.core.file import AliOssFileUploader, WechatSubscriptionAccountVerifyFileUploader
from apps.web.core.models import WechatPayApp, AliApp
from apps.web.core.utils import DefaultJsonErrorResponse, JsonOkResponse, JsonErrorResponse
from apps.web.dealer.models import Dealer
from apps.web.device.models import Device
from apps.web.device.timescale import PowerManager
from apps.web.user.models import MoniUser, AskRobot
from apps.web.user.models import MyUser
from apps.web.user.utils import get_consume_order
from apps.web.utils import error_tolerate, permission_required, concat_dealer_main_page_url, \
concat_front_end_url, concat_user_center_url, concat_user_login_entry_url
from apps.web.validation import SaveWithdrawBankCardSchema, SaveWithdrawAlipaySchema, SaveWithdrawWechatSchema
from library.misc import BankAPI
if TYPE_CHECKING:
from apps.web.core.db import RoleBaseDocument
from django.core.handlers.wsgi import WSGIRequest
from apps.web.device.models import DeviceDict
from apps.web.core.adapter.bolai_gateway import ChargingGatewayBox
from apps.web.core.payment.ali import AliPayGateway
logger = logging.getLogger(__name__)
@permission_required(ROLE.dealer, ROLE.agent, ROLE.supermanager)
def loadDistrictData(request):
return JsonResponse({'result': 1, 'description': None, 'payload': district.DISTRICT})
@error_tolerate(nil = lambda: JsonResponse({'result': 0, 'description': u'系统错误'}), logger = logger)
def logFrontend(request):
"""
收集来自前端的日志
:param request:
:return:
"""
if not request.body:
return JsonResponse({'result': 1, 'description': u'BODY为空'})
payload = json.loads(request.body)
if 'onlyLog' in payload and payload['onlyLog']:
logger.debug('--[BLUETOOTH]onlyLog--' + str(payload) + '--eof onlyLog--')
else:
FrontendLog(**payload).save()
return JsonResponse({'result': 1, 'description': u'记录成功'})
def getFAQ(request):
"""
使用的常见说明
:param request:
:return:
"""
current_user = request.user # type: RoleBaseDocument
faqs = FAQ.get_by_role(current_user.role)
return JsonResponse({
"result": 1,
"description": None,
"payload": {'dataList': [faq.to_dict() for faq in faqs], 'total': len(faqs)}
})
def getNotifications(request):
"""
做一个临时的用户通知 如果可以使用京东引流 就通知经销商
:param request:
:return:
"""
return JsonResponse(
{
"result": 1,
"description": None,
"payload": {
"total": 0,
"dataList": []
}
}
)
# @trace_call()
# def wx_biz_dispatch(request):
# def response_xml(payload):
# xmlData = dicttoxml.dicttoxml(payload, attr_type = False, custom_root = 'xml', cdata = True)
# return HttpResponse(xmlData)
#
# logger.info('has receive wechat dispatch message')
#
# def check_signature(signature, timestamp, nonce, token):
# args = [token, timestamp, nonce]
# args.sort()
# return hashlib.sha1(''.join(args).encode('utf-8')).hexdigest() == signature
#
# if request.method == 'GET':
# signature = request.GET['signature']
# timestamp = request.GET['timestamp']
# nonce = request.GET['nonce']
# echostr = request.GET['echostr']
# if check_signature(signature, timestamp, nonce, settings.MY_WECHAT_USER_TOKEN):
# return HttpResponse(str(echostr))
# else:
# return HttpResponse('')
# else:
# replyData = event_reply(request)
# logger.info('calc replaydata = %s' % replyData)
# if replyData:
# return response_xml(replyData)
#
# return HttpResponse('success')
@error_tolerate(nil = lambda: JsonResponse({'result': 0, 'description': u'文件操作有误'}), logger = logger)
@permission_required(ROLE.dealer, ROLE.manager, ROLE.myuser, ROLE.advertiser, ROLE.supermanager, ROLE.subaccount)
def uploadFile(request):
"""
公共的文件上传接口
TODO 需要注意安全选项!!
..added 2018/03/21 添加参数判断安全路径
:param request:
:return:
"""
UPLOADER_MAP = {
'wechatValidate': WechatSubscriptionAccountVerifyFileUploader,
'public': AliOssFileUploader
}
Uploader = UPLOADER_MAP.get(request.GET.get('category', 'public'))
uploader = Uploader(inputFile = request.FILES.getlist('file')[0], uploadType = request.GET.get('type', 'others'))
logger.info('[upload] %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': {}})
@error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
@permission_required(ROLE.manager, ROLE.advertisement, ROLE.advertiser, ROLE.dealer, ROLE.agent, ROLE.subaccount)
def getAddressType(request):
# type: (WSGIRequest)->JsonResponse
"""
获取地址类型
:param request:
:return:
"""
addressTypes = AddressType.objects.all().order_by('-showWeight') # type: Iterable[AddressType]
dataList = [{'value': addressType.value, 'label': addressType.label} for addressType in addressTypes]
return JsonResponse(
{
'result': 1,
'description': '',
'payload':
{
'dataList': dataList,
'total': len(dataList)
}
}
)
@error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
def getVersion(request):
version = subprocess.check_output(["git", "log", "-1", "--format=%cd"]).strip()
return JsonOkResponse(payload = {'version': version})
@error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
@permission_required(ROLE.supermanager, ROLE.manager)
def generateNewAppKeyPair(request):
# type: (WSGIRequest)->JsonResponse
"""
生成新的应用私钥公匙对, 返回给前台私钥的地址和公钥的内容 (方便前台去粘贴给支付宝)
:param request:
:return:
"""
payload = json.loads(request.body)
appid = payload.get('appid')
if not appid:
return JsonErrorResponse(description = u'appid未传入')
key = 'alipay_app_private_{appid}_{timestamp}'.format(appid = appid, timestamp = int(time.time() * 1000))
pair = generate_RSA_key_pairs()
serviceCache.set(key, pair.private, 3600)
appPublicKeyContent = re.sub(r'-.*', '', pair.public)
return JsonOkResponse(description = u'生成成功', payload = {'path': key, 'appPublicKeyContent': appPublicKeyContent})
@error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
@permission_required(ROLE.supermanager, ROLE.manager)
def verifyAppKeyPairs(request):
# type: (WSGIRequest)->JsonResponse
"""
:param request:
:return:
"""
return JsonErrorResponse(description = u'暂不开放')
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.supermanager)
def getAliAppList(request):
# type: (WSGIRequest)->JsonResponse
"""
获取阿里APP列表
:param request:
:return:
"""
page_index = int(request.GET.get('pageIndex', 1))
page_size = int(request.GET.get('pageSize', 10))
search_key = request.GET.get('searchKey', None)
total, items = AliApp.list(page_index = page_index, page_size = page_size, search_key = search_key)
return JsonResponse({'result': 1,
'description': None,
'payload': {
'total': total,
'dataList': items
}
})
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.supermanager)
def editAliApp(request):
# type: (WSGIRequest)->JsonResponse
"""
编辑阿里APP
:param request:
:return:
"""
payload = json.loads(request.body) # type: dict
id = payload.pop('id', None)
update = payload
if id:
query = {'_id': id}
else:
query = {'appid': payload.get('appid')}
result = AliApp.get_collection().update_one(query, update, upsert = True) # type: UpdateResult
return JsonResponse({
'result': 1 if (result.modified_count == 1 or result.upserted_id) else 0,
'description': u'修改成功' if (result.modified_count == 1 or result.upserted_id) else u'修改失败',
'payload': {
'id': str(result.upserted_id) if result.upserted_id else id
}})
@error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
@permission_required(ROLE.supermanager, ROLE.manager)
def getWechatFundApp(request):
# type: (WSGIRequest)->JsonResponse
"""
更改微信资金平台APP信息
:param request:
:return:
"""
appid = request.GET.get('appid')
mchid = request.GET.get('mchid')
app = WechatPayApp.objects(appid = appid, mchid = mchid).first() # type: WechatPayApp
if not app:
return JsonOkResponse(payload = {})
else:
return JsonOkResponse(payload = app.to_dict())
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.supermanager, ROLE.manager)
def editWechatFundApp(request):
# type: (WSGIRequest)->JsonResponse
"""
编辑阿里APP
:param request:
:return:
"""
payload = json.loads(request.body) # type: dict
id = payload.pop('id', None)
update = payload
if id:
query = {'_id': id}
else:
query = {'appid': payload.get('appid')}
result = WechatPayApp.get_collection().update_one(query, update, upsert = True) # type: UpdateResult
return JsonResponse({
'result': 1 if (result.modified_count == 1 or result.upserted_id) else 0,
'description': u'修改成功' if (result.modified_count == 1 or result.upserted_id) else u'修改失败',
'payload': {
'id': str(result.upserted_id) if result.upserted_id else id
}})
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.supermanager, ROLE.manager)
def getWechatAppList(request):
# type: (WSGIRequest)->JsonResponse
"""
获取微信支付APP列表
:param request:
:return:
"""
page_index = int(request.GET.get('pageIndex', 1))
page_size = int(request.GET.get('pageSize', 10))
search_key = request.GET.get('searchKey', None)
total, items = WechatPayApp.list(page_index = page_index, page_size = page_size, search_key = search_key)
return JsonResponse({'result': 1,
'description': None,
'payload': {
'total': total,
'dataList': items
}
})
def event_reply(request):
logger.info('has receive event_reply dispatch message = %s' % request.body)
raw = xmltodict.parse(request.body)['xml']
msgType = raw.get('MsgType', '')
event = raw.get('Event', '')
if msgType == 'event' and event in ['subscribe', 'unsubscribe']:
moniOpenId = raw['FromUserName']
rawAppId = raw['ToUserName']
try:
moniApp = MoniApp.objects.get(rawAppId = rawAppId)
except Exception, e:
return ''
try:
moniUser = MoniUser.objects.filter(moniAppId = moniApp.appId, moniOpenId = moniOpenId).first()
if moniUser:
if event == 'subscribe':
moniUser.subTime = datetime.datetime.now()
moniUser.isSubscribe = True
AskRobot.reply(event, moniOpenId, '', moniApp.appId, moniApp.secret, openId = moniUser.openId)
else:
moniUser.unsubTime = datetime.datetime.now()
moniUser.isSubscribe = False
moniUser.save()
else:
user = MyUser.objects.filter(managerialOpenId = raw['FromUserName']).first()
if user is None:
newUser = MoniUser(moniAppId = moniApp.appId, moniOpenId = moniOpenId,
subTime = datetime.datetime.now(), isSubscribe = True)
newUser.save()
else:
AskRobot.reply(event, moniOpenId, '', moniApp.appId, moniApp.secret, openId = user.openId,
agentId = user.agentId)
except Exception, e:
logger.exception('event_reply error=%s' % e)
return ''
elif msgType == 'text':
try:
# 如果是监督号,就直接回复。如果不是监督号,可能是用户的管理app,这个时候,需要走另外的流程。用户付费后关注
moniApp = MoniApp.objects.filter(rawAppId = raw['ToUserName']).first()
if moniApp:
try:
logger.info('111')
moniUser = MoniUser.objects.filter(moniAppId = moniApp.appId,
moniOpenId = raw['FromUserName']).first()
if moniUser and moniUser.openId and moniUser.subAgentId:
logger.info('222')
logger.info('content = %s,openId=%s' % (raw['Content'], moniUser.openId))
AskRobot.reply(event, raw['FromUserName'], raw['Content'], moniApp.appId, moniApp.secret,
openId = moniUser.openId, agentId = moniUser.subAgentId)
else:
logger.info('333')
user = MyUser.objects.filter(managerialOpenId = raw['FromUserName']).first()
if user is None:
logger.info('444')
return {'MsgType': 'text', 'FromUserName': raw['ToUserName'],
'ToUserName': raw['FromUserName'], 'Content': u'没有找到您在平台扫码使用设备的任何信息',
'CreateTime': int(time.time())}
AskRobot.reply(event, raw['FromUserName'], raw['Content'], moniApp.appId, moniApp.secret,
openId = user.openId, agentId = user.agentId)
except Exception, e:
logger.exception('event_reply error=%s' % e)
return ''
logger.info('555')
return ''
except Exception, e:
return ''
return ''
@error_tolerate(logger = logger, nil = JsonErrorResponse(u'故障部件图片存储失败,请重新上传'))
@permission_required(ROLE.dealer, ROLE.subaccount)
def uploadFaultPartPic(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 = 'fault')
logger.info('[uploadFaultPartPic] %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': {}})
def queryExpressInfo(request):
orderNo = request.GET.get('orderNo')
bodys = {}
url = 'https://kuaidid.market.alicloudapi.com/danhao'
bodys['com'] = ''
bodys['src'] = orderNo
from six.moves.urllib import parse
post_data = parse.urlencode(bodys)
request = urllib2.Request(url, post_data)
request.add_header('Authorization', 'APPCODE ' + Const.KUAIDI_API_APPCODE)
request.add_header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
response = urllib2.urlopen(request, timeout = 15, context = ctx)
content = response.read()
if (content):
result = json.loads(content)
if result['status'] == 200:
resultList = []
for info in result['msg']['context']:
resultList.append({'time': datetime.datetime.fromtimestamp(info['time']).strftime(Const.DATETIME_FMT),
'desc': info['desc']})
return JsonOkResponse(payload = {'dataList': resultList})
else:
return JsonErrorResponse(description = u'无法获取到订单详细信息')
else:
return JsonErrorResponse(description = u'无法获取到订单详细信息')
@error_tolerate(logger = logger)
def aliNotify(request):
payload = request.POST.dict() # type: Dict
logger.info('ali common notify: %s' % str(payload))
if 'service' in payload and payload['service'] == 'alipay.service.check':
biz_content = xmltodict.parse(payload['biz_content'])['XML']
app = AliApp.objects(appid = biz_content['AppId']).first() # type: AliApp
gateway = app.new_gateway(app_platform_type = AppPlatformType.ALIPAY) # type: AliPayGateway
if gateway.check(data = payload, pop_sign_type = False):
sign = gateway.client._sign('true')
return HttpResponse(
'true{}{}RSA2'.format(
gateway.client.app_cert_sn, sign))
if payload['msg_method'] == 'alipay.fund.trans.order.changed':
payload['biz_content'] = json.loads(payload['biz_content'])
order_no = payload['biz_content']['out_biz_no']
if WithdrawRecord.is_my(order_no):
return AliPayWithdrawNotifier(record_cls = WithdrawRecord).do(payload)
else:
logger.warn('not support this order. orderNo = {}'.format(order_no))
else:
logger.warn('not support this method = {}'.format(payload['msg_method']))
return HttpResponse('success')
@error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"获取订单失败,请刷新"))
def getReceipt(request): # type: (WSGIRequest)->JsonResponse
"""
获取支付结果
消费单的结果直接跳转回去
"""
user = request.user # type: RoleBaseDocument
order_type = request.GET.get('order_type', 'recharge')
out_trade_no = request.GET.get('out_trade_no')
check_code = request.GET.get('check_code', None)
from apps.web.user.models import RechargeRecord, ConsumeRecord
if order_type == 'consume':
record = get_consume_order(out_trade_no) # type: ConsumeRecord
payload = record.receiptDesc
else:
record = RechargeRecord.objects(__raw__={
'$or': [
{
'wxOrderNo': out_trade_no
},
{
'orderNo': out_trade_no
}
]}).first() # type: RechargeRecord
if not record:
from apps.web.dealer.models import DealerRechargeRecord
record = DealerRechargeRecord.objects(__raw__={
'$or': [
{
'wxOrderNo': out_trade_no
},
{
'orderNo': out_trade_no
}
]}).first() # type: DealerRechargeRecord
if not record:
return JsonErrorResponse(description = u'订单获取失败,请重新获取')
else:
payload = {
'itemName': record.subject,
'orderNo': record.orderNo,
'payment': RMB.fen_to_yuan(record.totalFee),
'homeLink': concat_dealer_main_page_url(),
'finishedTime': record.finishedTime,
'adInfo': {
'adShow': 'noshow'
}
}
if record.product == DealerRechargeRecord.ProductType.SimCard:
payload.update(
{'detailLink': concat_front_end_url(
uri = '/app/payOrderDetail.html?orderNo={}'.format(record.orderNo))})
return JsonOkResponse(payload = payload)
else:
if record.result != RechargeRecord.PayResult.SUCCESS:
return JsonErrorResponse(description = u'订单回调还未调用')
payload = {
'orderNo': record.orderNo,
'payment': record.money,
'finishedTime': record.finished_time
}
from apps.web.device.models import Device
# 是否是启动设备的
start_key = record.startKey
if start_key:
payload.update({
'startKey': start_key,
'devNo': record.devNo,
'logicalCode': record.logicalCode,
'homeLink': concat_user_login_entry_url(l = record.logicalCode),
'serviceLink': concat_user_center_url(l = record.logicalCode)
})
else:
payload.update({
'serviceLink': concat_user_center_url(),
'homeLink': concat_user_center_url(),
'detailLink': concat_front_end_url(
uri = '/user/index.html#/user/chargeRecordDetail?ownerId={}&id={}'.format(record.ownerId,
str(record.id)))
})
if isinstance(record, RechargeRecord):
payload['itemName'] = record.subject
if record.devNo:
device = Device.get_dev(record.devNo)
else:
device = None
else:
device = Device.get_dev(record.devNo)
if record.port:
payload['itemName'] = cn(u'{major_type}/{logicalCode}-端口{port}'.format(
major_type = device.majorDeviceType[0:8], logicalCode = record.logicalCode,
port = record.port))
else:
payload['itemName'] = cn(u'{major_type}/{logicalCode}'.format(
major_type = device.majorDeviceType[0:8], logicalCode = record.logicalCode))
if not check_code:
owner = Dealer.objects(id=record.ownerId).first() # type: Dealer
ad_dict = Advertisement.fetch_payafter_ad(
ua=request.META.get('HTTP_USER_AGENT', ''), user=request.user, dealer=owner, device=device)
logger.debug('ad dict is {}'.format(ad_dict))
payload.update({'adInfo': ad_dict})
else:
AdStatistics.inc_make_count(adSpace=AdSpace.PAYAFTER, showType='payAfter_dianjin', gateway='wechat')
return JsonOkResponse(payload=payload)
def bolaiEvent(request):
payload = json.loads(request.body)
logger.debug('received bolai event: {}'.format(payload))
gateId = payload.get('gateway_id')
gateway_dev = Device.get_dev(gateId) # type: DeviceDict
if gateway_dev is None: # 可能是一体化设备
rcds = Device.get_collection().find({'gateImei': gateId})
if rcds.count() == 0:
return JsonOkResponse()
gateway_dev = Device.get_dev(rcds[0]['devNo'])
logger.info('this is gatewayplug device')
if gateway_dev is None:
return JsonOkResponse()
if 'data' in payload and 'node_index' in payload['data']:
if payload['data']['node_index'] != 0:
logger.info('this is nodeplug device')
gateway_adapter = gateway_dev.deviceAdapter # type: ChargingGatewayBox
node_devno = gateway_adapter.get_node_devNo(str(payload['data']['node_index']))
node_dev = Device.get_dev(node_devno) # type: DeviceDict
if not node_dev:
return JsonOkResponse()
payload.update({
'nodeType': 'node'
})
event = node_dev.eventer.getEvent(payload)
event.do()
else:
logger.info('this is gateway device')
payload.update({
'nodeType': 'node'
})
event = gateway_dev.eventer.getEvent(payload)
event.do()
else:
payload.update({
'nodeType': 'gateway'
})
event = gateway_dev.eventer.getEvent(payload)
event.do()
return JsonOkResponse()
def bolaitenEvent(request):
payload = json.loads(request.body)
logger.debug('received bolai event: {}'.format(payload))
devNo = payload.get('gateway_id')
dev = Device.get_dev(devNo)
if dev is None:
return JsonOkResponse()
if 'data' in payload:
event = dev.eventer.getEvent(payload)
event.do()
return JsonOkResponse()
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.dealer, ROLE.supermanager, ROLE.myuser)
def getPowerGraphByDevice(request):
startTime = to_datetime(request.GET.get('startTime'))
endTime = to_datetime(request.GET.get('endTime'))
port = str(request.GET.get('port', '1'))
device = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: DeviceDict
if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_YUEWANGTONG]:
interval = 600
else:
interval = device.cycle
items = PowerManager.instence().get(devNo = device.devNo, port = port, sTime = startTime, eTime = endTime,
interval = interval)
return JsonOkResponse(payload = {'dataList': items})
class WechatFollowView(View):
def __init__(self, **kwargs):
super(WechatFollowView, self).__init__(**kwargs)
self.app = None
@staticmethod
def auth_request(request, app): # type:(WSGIRequest, MoniApp) -> bool
"""
对微信的请求进行验签
"""
token = app.appToken
signature = request.GET.get('signature')
timestamp = request.GET.get('timestamp')
nonce = request.GET.get('nonce')
params = [token, timestamp, nonce]
params.sort()
return hashlib.sha1("".join(params)).hexdigest() == signature
@staticmethod
def get_followed_app(rawAppId):
return MoniApp.get_app_by_raw(rawAppId)
def dispatch(self, request, *args, **kwargs):
rawAppId = kwargs.pop("rawAppId", "")
app = self.get_followed_app(rawAppId)
# 查找是否是入库的app
if not app:
logger.warning("[WechatFollowView dispatch], not find app! rawAppId = {}".format(rawAppId))
return HttpResponseBadRequest()
# 查找是否通过校验
if not self.auth_request(request, app):
logger.warning("[WechatFollowView dispatch], verify server error! params = {}".format(request.GET))
return HttpResponseBadRequest()
self.app = app
return super(WechatFollowView, self).dispatch(request)
def get(self, request):
"""
微信公众号服务器验证token使用 配置的时候只会访问一次
"""
logger.info("[WechatFollowView GET], verify server success! params = {}, app = {}".format(request.GET, self.app))
echoStr = request.GET["echostr"]
return HttpResponse(echoStr)
def post(self, request):
"""
业务请求都在这里
大致分为两类
1.业务事件(关注、订阅、点击菜单)
2.用户互动文字
"""
logger.info("[WechatFollowView POST], payload = {}, app = {}".format(request.body, self.app))
message = WechatMessage(request.body)
if message.isText:
response = WechatText(message, self.app).handle()
elif message.isEvent:
if message.isScanEvent:
response = WechatScanEvent(message, self.app).handle()
elif message.isSubscribeEvent:
response = WechatSubscribe(message, self.app).handle()
elif message.isUnSubscribeEvent:
response = WechatUnSubscribe(message, self.app).handle()
elif message.isMenuEvent:
response = WechatMenu(message, self.app).handle()
else:
response = MessageHandler.defaultResponse()
else:
response = MessageHandler.defaultResponse()
return response
@permission_required(ROLE.dealer, ROLE.agent, ROLE.supermanager)
def loadWithdrawArea(request):
province = request.GET.get("province", None)
return JsonOkResponse(payload = {'dataList': WithdrawDistrict.get_area(province)})
@error_tolerate(logger = logger, nil = JsonErrorResponse(description = u"获取数据失败,请刷新"))
@permission_required(ROLE.dealer, ROLE.agent, ROLE.supermanager)
def supportedWithdrawBanks(request):
# type: (WSGIRequest)->JsonResponse
keyWord = request.GET.get('keyWord', None)
chooseRange = request.GET.get('range', 'wechat')
if chooseRange == 'all':
return JsonOkResponse(payload = {'dataList': WithdrawBanks.get_all_banks(keyWord)})
elif chooseRange == 'wechat':
return JsonOkResponse(payload = {'dataList': WithdrawBanks.get_wechat_support_banks(keyWord)})
else:
return JsonErrorResponse(description = u'参数错误')
@error_tolerate(logger = logger, nil = JsonErrorResponse(description = u"获取数据失败,请刷新"))
@permission_required(ROLE.dealer, ROLE.agent, ROLE.supermanager)
def getWithdrawBankByAccount(request):
# type: (WSGIRequest)->JsonResponse
accountCode = request.GET.get('accountCode', None)
if not accountCode:
return JsonResponse({'result': 2, 'description': u'银行账号不能为空', 'payload': {}})
bank_info = BankAPI().get_bank_card_info(card_no = accountCode)
if bank_info:
rv = WithdrawBanks.get_by_bank_abbrev_code(bank_info['bankAbbrevCode'])
if rv:
return JsonOkResponse(payload = rv)
else:
logger.warning('not find this bank: {}'.format(bank_info))
return JsonResponse({'result': 2, 'description': u'该银行卡不支持', 'payload': {}})
else:
return JsonResponse({'result': 2, 'description': u'没有查到该银行账号信息', 'payload': {}})
@error_tolerate(logger = logger, nil = JsonErrorResponse(description = u"获取数据失败,请刷新"))
@permission_required(ROLE.dealer, ROLE.agent, ROLE.supermanager)
def withdrawBranchBankList(request):
# type: (WSGIRequest)->JsonResponse
provinceCode = request.GET.get('provinceCode')
cityCode = request.GET.get('cityCode')
bankCode = request.GET.get('bankCode')
keyWord = request.GET.get('keyWord')
queryset = WithdrawBranchBanks.objects(**{
'provinceCode': provinceCode,
'cityCode': cityCode,
'bankCode': bankCode
}).search(keyWord)
rv = [
{
'code': item.code,
'name': item.name
} for item in queryset
]
return JsonOkResponse(payload = {'dataList': rv})
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.dealer, ROLE.agent)
def saveWithdrawBankCard(request):
# type: (WSGIRequest)->JsonResponse
"""
添加银行卡
"""
ownerId = str(request.user.id)
if WithdrawBankCard.objects.filter(ownerId = ownerId, role = request.user.role).count() > 5:
return JsonResponse({"result": 2, "description": u"银行卡数量已添加至上限(5),不允许继续添加"})
try:
payload = SaveWithdrawBankCardSchema(json.loads(request.body))
except MultipleInvalid as e:
logger.exception(e)
return JsonErrorResponse(description = u"信息不完整")
if WithdrawBankCard.objects(ownerId = ownerId, role = request.user.role,
accountCode = payload['accountCode']).first():
return JsonResponse({"result": 2, "description": u"请勿重复添加"})
accountType = payload.pop('accountType')
if accountType == WithdrawBankCard.AccountType.PERSONAL:
item = WithdrawBankCard.new_personal_withdraw_bank_card(ownerId = ownerId, role = request.user.role, **payload)
return JsonOkResponse(payload = {"id": str(item.id)})
else:
return JsonErrorResponse(description = u"不支持添加对公提现银行卡,请您开通商户。")
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.dealer, ROLE.agent)
def unbindWithdrawBankCard(request):
# type: (WSGIRequest)->JsonResponse
ownerId = str(request.user.id)
payload = json.loads(request.body)
accountCode = payload.get('accountCode')
if not accountCode:
return JsonResponse({"result": 2, "description": u"参数错误,请刷新后重试"})
try:
card = WithdrawBankCard.objects.get(ownerId = ownerId, role = request.user.role, accountCode = accountCode)
except Exception as e:
logger.exception(e)
return JsonResponse({"result": 2, "description": u"解绑定失败,请联系客服解决。"})
else:
card.delete()
return JsonOkResponse()
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.dealer, ROLE.agent)
def getWithdrawBankCards(request):
# type: (WSGIRequest)->JsonResponse
ownerId = str(request.user.id)
bankCards = WithdrawBankCard.objects.filter(ownerId = ownerId, role = request.user.role)
dataList = list()
for bankCard in bankCards:
dataList.append(bankCard.to_dict())
return JsonOkResponse(payload = {'dataList': dataList})
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.dealer, ROLE.agent)
def saveAlipayWithdrawInfo(request):
# type: (WSGIRequest)->JsonResponse
try:
payload = SaveWithdrawAlipaySchema(json.loads(request.body))
except MultipleInvalid as e:
logger.exception(e)
return JsonErrorResponse(description = u"参数错误")
else:
request.user.set_withdraw_alipay(**payload)
return JsonOkResponse()
@error_tolerate(nil = DefaultJsonErrorResponse)
@permission_required(ROLE.dealer, ROLE.agent)
def saveWechatWithdrawInfo(request):
# type: (WSGIRequest)->JsonResponse
try:
payload = SaveWithdrawWechatSchema(json.loads(request.body))
except MultipleInvalid as e:
logger.exception(e)
return JsonErrorResponse(description = u"参数错误")
else:
request.user.set_withdraw_wechat(**payload)
return JsonOkResponse()