views.py 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. """
  4. web.agent.views
  5. ~~~~~~~~~
  6. """
  7. import base64
  8. import logging
  9. import datetime
  10. import simplejson as json
  11. from bson.objectid import ObjectId
  12. from django.conf import settings
  13. from django.contrib import auth
  14. from django.core.handlers.wsgi import WSGIRequest
  15. from mongoengine.errors import DoesNotExist, NotUniqueError
  16. from operator import itemgetter
  17. from typing import Optional, cast
  18. from voluptuous import MultipleInvalid
  19. from apilib.monetary import RMB, Percent, Ratio
  20. from apilib.utils_datetime import to_datetime
  21. from apilib.utils_json import JsonResponse
  22. from apilib.utils_mongo import BulkHandler, BulkHandlerEx
  23. from apilib.utils_url import add_query
  24. from apps.thirdparties.aliyun import AliyunSlider
  25. from apps.web.agent.define import AGENT_INCOME_SOURCE, AGENT_INCOME_TYPE
  26. from apps.web.agent.models import Agent, AgentIncomeReport
  27. from apps.web.agent.withdraw import AgentWithdrawService, check_record_when_revoke_or_approve
  28. from apps.web.common.models import WithdrawRecord
  29. from apps.web.common.transaction import WithdrawStatus, WITHDRAW_PAY_TYPE, translate_withdraw_state
  30. from apps.web.common.validation import NAME_RE, check_phone_number
  31. from apps.web.constant import Const, DeviceCmdCode, APP_TYPE, ErrorCode
  32. from apps.web.core import ROLE
  33. from apps.web.core.auth.wechat import WechatAuthBridge
  34. from apps.web.core.db import prepare_query
  35. from apps.web.core.exceptions import ServiceException, InvalidFileSize, InvalidFileName
  36. from apps.web.core.file import AliOssFileUploader
  37. from apps.web.core.helpers import ActionDeviceBuilder
  38. from apps.web.core.messages.sms import agentRegisterSMSProvider, agentWithdrawSMSProvider
  39. from apps.web.core.networking import MessageSender
  40. from apps.web.core.payment import WithdrawGateway
  41. from apps.web.core.sysparas import SysParas
  42. from apps.web.core.utils import DefaultJsonErrorResponse, JsonErrorResponse, JsonOkResponse
  43. from apps.web.dealer.models import Dealer
  44. from apps.web.device.models import Device, Group, DeviceType, CheckDevice
  45. from apps.web.helpers import get_wx_config, current_platform, get_wechat_auth_bridge
  46. from apps.web.user.models import Card, UserVirtualCard
  47. from apps.web.utils import (
  48. agent_login, error_tolerate, permission_required, features_required, concat_server_end_url,
  49. ErrorResponseRedirect, FrontEndResponseRedirect, ExternalResponseRedirect)
  50. logger = logging.getLogger(__name__)
  51. def login(request):
  52. # type: (WSGIRequest)->JsonResponse
  53. username = request.POST.get('username', None)
  54. password = request.POST.get('password', None)
  55. if not all([username, password]):
  56. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  57. else:
  58. response = agent_login(request, logger, username, password)
  59. response.delete_cookie(key = 'JSESSIONID')
  60. return response
  61. @permission_required(ROLE.agent)
  62. def accountInfo(request):
  63. # type: (WSGIRequest)->JsonResponse
  64. currentAgent = request.user # type: Agent
  65. try:
  66. return JsonResponse({
  67. 'result': 1,
  68. 'description': None,
  69. 'payload': {
  70. 'description': None,
  71. 'nickname': currentAgent.nickname,
  72. 'username': currentAgent.username,
  73. 'balance': currentAgent.total_balance,
  74. 'agentId': str(currentAgent.id),
  75. 'forceFollowGzh': currentAgent.forceFollowGzh,
  76. 'cardWechatInfo': {
  77. 'bound': True if 'openId' in currentAgent.cardWechatInfo else False,
  78. 'avatar': currentAgent.cardWechatInfo.get('avatar', ''),
  79. 'sex': currentAgent.cardWechatInfo.get('sex', ''),
  80. 'nickname': currentAgent.cardWechatInfo.get('nickname', '')
  81. },
  82. 'boundCardName': currentAgent.boundCardName,
  83. 'boundCardPhone': currentAgent.boundCardPhone,
  84. 'avatar': currentAgent.my_avatar
  85. }
  86. })
  87. except Exception, e:
  88. logger.exception('unable to get agent account info, error=%s' % e)
  89. return JsonResponse({'result': 0, 'description': u'无法获取代理商信息', 'payload': {}})
  90. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  91. @permission_required(ROLE.agent)
  92. def resetPassword(request):
  93. # type: (WSGIRequest)->JsonResponse
  94. oldPassword = request.POST.get('oldPassword')
  95. password = request.POST.get('password')
  96. agent = request.user # type: Agent
  97. if agent.check_password(oldPassword):
  98. agent.set_password(password)
  99. else:
  100. return JsonResponse({'result': 0, 'description': u'原密码错误'})
  101. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  102. @permission_required(ROLE.agent)
  103. def homePageData(request):
  104. # type: (WSGIRequest)->JsonResponse
  105. current_agent = request.user # type: Agent
  106. response = JsonResponse(
  107. {
  108. 'result': 1, 'description': None,
  109. 'payload': {
  110. 'permission': {'adShow': current_agent.adShow, 'deviceIncome': current_agent.deviceIncomeShow},
  111. 'totalIncome': current_agent.today_income(),
  112. 'adIncome': current_agent.today_income(AGENT_INCOME_SOURCE.AD),
  113. 'cardFeeIncome': current_agent.today_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE),
  114. 'withdrawIncome': current_agent.today_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE),
  115. 'deviceIncome': current_agent.today_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE),
  116. 'bankwithdraw': current_agent.dealerBankWithdrawFee
  117. }
  118. })
  119. response = Agent.record_cookie(str(request.user.id), response)
  120. return response
  121. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  122. @permission_required(ROLE.agent)
  123. def getIncome(request):
  124. # type: (WSGIRequest)->JsonResponse
  125. current_agent = request.user # type: Agent
  126. return JsonResponse(
  127. {
  128. 'result': 1,
  129. 'description': None,
  130. 'payload': {
  131. 'adShow': current_agent.adShow,
  132. 'totalIncome': current_agent.aggregate_income(),
  133. 'totalAdIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.AD),
  134. 'totalCardFeeIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE),
  135. 'totalWithdrawIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE),
  136. 'totalDeviceIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE),
  137. 'totalInsuranceIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.INSURANCE),
  138. 'yesterdayTotalIncome': current_agent.yesterday_income(),
  139. 'yesterdayAdIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.AD),
  140. 'yesterdayCardFeeIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE),
  141. 'yesterdayWithdrawIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE),
  142. 'yesterdayDeviceIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE),
  143. 'yesterdayInsuranceIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.INSURANCE),
  144. }
  145. }
  146. )
  147. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  148. @permission_required(ROLE.agent)
  149. def getIncomeStatistics(request):
  150. # type: (WSGIRequest)->JsonResponse
  151. current_agent = request.user # type: Agent
  152. source = request.GET.get('source')
  153. if source not in AGENT_INCOME_SOURCE.choices() and source:
  154. return JsonResponse({'result': 0, 'description': u'收入请求来源不明', 'payload': {}})
  155. else:
  156. return JsonResponse(
  157. {
  158. 'result': 1,
  159. 'description': None,
  160. 'payload': {
  161. 'totalIncome': current_agent.aggregate_income(source),
  162. 'yesterdayIncome': current_agent.yesterday_income(source),
  163. 'currentMonthIncome': current_agent.current_month_income(source)
  164. }
  165. }
  166. )
  167. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  168. @permission_required(ROLE.agent)
  169. def getIncomeList(request):
  170. # type: (WSGIRequest)->JsonResponse
  171. source = request.GET.get('source')
  172. if source not in AGENT_INCOME_SOURCE.choices() and source:
  173. return JsonResponse({'result': 0, 'description': u'收入请求来源不明', 'payload': {}})
  174. query = prepare_query(request.GET, ('random',))
  175. current_agent = request.user # type: Agent
  176. reports = AgentIncomeReport.objects(agentId = str(current_agent.id), **query.attrs).order_by('-dateTimeAdded')
  177. total = reports.count()
  178. monthlyIncome = current_agent.monthly_income(specific_source = source)
  179. dataList = [
  180. {
  181. 'title': r.title,
  182. 'createdTime': r.date,
  183. 'monthlyIncome': monthlyIncome[(r.dateTimeAdded.year, r.dateTimeAdded.month)],
  184. 'amount': RMB(r.amount)
  185. }
  186. for r in reports.paginate(pageIndex = query.pageIndex, pageSize = query.pageSize)
  187. ]
  188. return JsonResponse(
  189. {
  190. 'result': 1,
  191. 'description': None,
  192. 'payload': {
  193. 'total': total,
  194. 'dataList': dataList
  195. }
  196. })
  197. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  198. @permission_required(ROLE.agent)
  199. def withdrawIncome(request):
  200. # type: (WSGIRequest)->JsonResponse
  201. current_agent = request.user # type: Agent
  202. return JsonResponse(
  203. {
  204. 'result': 1,
  205. 'description': None,
  206. 'payload': {
  207. 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE),
  208. 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE),
  209. 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE)
  210. }
  211. }
  212. )
  213. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  214. @permission_required(ROLE.agent)
  215. def withdrawIncomeList(request):
  216. # type: (WSGIRequest)->JsonResponse
  217. pageIndex = int(request.GET.get('pageIndex', 1))
  218. pageSize = int(request.GET.get('pageSize', 10))
  219. endDate = request.GET.get('endDate')
  220. current_agent = request.user # type: Agent
  221. reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id),
  222. source = AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE,
  223. endDate = endDate)
  224. total = reports.count()
  225. monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.DEALER_WITHDRAW_FEE)
  226. dataList = [
  227. {
  228. 'title': r.detail.get('name', '') + r.detail.get('withdrawAmount', ''),
  229. 'withdraw': r.detail.get('withdrawAmount'),
  230. 'time': r.date,
  231. 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)],
  232. 'amount': r.amount
  233. }
  234. for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize)
  235. ]
  236. return JsonResponse(
  237. {
  238. 'result': 1,
  239. 'description': None,
  240. 'payload': {
  241. 'total': total,
  242. 'dataList': dataList
  243. }
  244. })
  245. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  246. @permission_required(ROLE.agent)
  247. def cardFeeIncome(request):
  248. # type: (WSGIRequest)->JsonResponse
  249. current_agent = request.user # type: Agent
  250. return JsonResponse(
  251. {
  252. 'result': 1,
  253. 'description': None,
  254. 'payload': {
  255. 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE),
  256. 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE),
  257. 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.DEALER_CARD_FEE)
  258. }
  259. }
  260. )
  261. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  262. @permission_required(ROLE.agent)
  263. def cardFeeIncomeList(request):
  264. # type: (WSGIRequest)->JsonResponse
  265. pageIndex = int(request.GET.get('pageIndex', 1))
  266. pageSize = int(request.GET.get('pageSize', 10))
  267. endDate = request.GET.get('endDate')
  268. current_agent = request.user # type: Agent
  269. reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id),
  270. source = AGENT_INCOME_SOURCE.DEALER_CARD_FEE,
  271. endDate = endDate)
  272. total = reports.count()
  273. monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.DEALER_CARD_FEE)
  274. dataList = [
  275. {
  276. 'title': r.detail.get('name', ''),
  277. 'time': r.date,
  278. 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)],
  279. 'amount': r.amount
  280. }
  281. for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize)
  282. ]
  283. return JsonResponse(
  284. {
  285. 'result': 1,
  286. 'description': None,
  287. 'payload': {
  288. 'total': total,
  289. 'dataList': dataList
  290. }
  291. })
  292. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  293. @permission_required(ROLE.agent)
  294. def adIncome(request):
  295. # type: (WSGIRequest)->JsonResponse
  296. current_agent = request.user # type: Agent
  297. return JsonResponse(
  298. {
  299. 'result': 1,
  300. 'description': None,
  301. 'payload': {
  302. 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.AD),
  303. 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.AD),
  304. 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.AD)
  305. }
  306. }
  307. )
  308. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  309. @permission_required(ROLE.agent)
  310. def adIncomeList(request):
  311. # type: (WSGIRequest)->JsonResponse
  312. pageIndex = int(request.GET.get('pageIndex', 1))
  313. pageSize = int(request.GET.get('pageSize', 10))
  314. endDate = request.GET.get('endDate')
  315. current_agent = request.user # type: Agent
  316. reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id),
  317. source = AGENT_INCOME_SOURCE.AD,
  318. endDate = endDate)
  319. total = reports.count()
  320. monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.AD)
  321. dataList = [
  322. {
  323. 'title': u'经销商:%s,设备编号:%s,访问ID:%s, 广告ID: %s'
  324. % (r.detail.get('dealer'), r.detail.get('logicalCode'), r.detail.get('openId'),
  325. r.detail.get('adId', '')),
  326. 'time': r.date,
  327. 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)],
  328. 'amount': r.amount
  329. }
  330. for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize)
  331. ]
  332. return JsonResponse(
  333. {
  334. 'result': 1,
  335. 'description': None,
  336. 'payload': {
  337. 'total': total,
  338. 'dataList': dataList
  339. }
  340. })
  341. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  342. @permission_required(ROLE.agent)
  343. def deviceIncome(request):
  344. # type: (WSGIRequest)->JsonResponse
  345. current_agent = request.user # type: Agent
  346. return JsonResponse(
  347. {
  348. 'result': 1,
  349. 'description': None,
  350. 'payload': {
  351. 'totalIncome': current_agent.aggregate_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE),
  352. 'yesterdayIncome': current_agent.yesterday_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE),
  353. 'currentMonthIncome': current_agent.current_month_income(AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE)
  354. }
  355. }
  356. )
  357. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  358. @permission_required(ROLE.agent)
  359. def deviceIncomeList(request):
  360. # type: (WSGIRequest)->JsonResponse
  361. pageIndex = int(request.GET.get('pageIndex', 1))
  362. pageSize = int(request.GET.get('pageSize', 10))
  363. endDate = request.GET.get('endDate')
  364. current_agent = request.user # type: Agent
  365. reports = AgentIncomeReport.get_income_list(agentId = str(current_agent.id),
  366. source = AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE,
  367. endDate = endDate)
  368. total = reports.count()
  369. monthlyIncome = current_agent.monthly_income(specific_source = AGENT_INCOME_SOURCE.DEALER_DEVICE_FEE)
  370. dataList = [
  371. {
  372. 'title': r.detail.get('name', ''),
  373. 'time': r.date,
  374. 'monthlyIncome': monthlyIncome[(r.createdTime.year, r.createdTime.month)],
  375. 'amount': r.amount
  376. }
  377. for r in reports.paginate(pageIndex = pageIndex, pageSize = pageSize)
  378. ]
  379. return JsonResponse(
  380. {
  381. 'result': 1,
  382. 'description': None,
  383. 'payload': {
  384. 'total': total,
  385. 'dataList': dataList
  386. }
  387. })
  388. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  389. @permission_required(ROLE.agent)
  390. def groupListByDealer(request):
  391. # type: (WSGIRequest)->JsonResponse
  392. ownerId = str(request.user.id)
  393. pageIndex = int(request.GET.get('pageIndex', 1))
  394. pageSize = int(request.GET.get('pageSize', 10))
  395. groupIds = Group.get_group_ids_of_dealer(ownerId)
  396. groupList = Group.get_groups_by_group_ids(groupIds).values()
  397. for grp in groupList:
  398. devNos = Device.get_devNos_by_group([grp['groupId']])
  399. grp['equipmentCount'] = len(devNos)
  400. groupList.sort()
  401. return JsonResponse({
  402. 'result': 1,
  403. 'description': None,
  404. 'payload': {
  405. 'total': len(groupList),
  406. 'dataList': groupList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  407. }
  408. })
  409. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  410. @permission_required(ROLE.agent)
  411. def getDealerList(request):
  412. # type: (WSGIRequest)->JsonResponse
  413. """
  414. 代理商查看下辖经销商
  415. :param request:
  416. :return:
  417. """
  418. pageIndex = int(request.GET.get('pageIndex', 1))
  419. pageSize = int(request.GET.get('pageSize', 10))
  420. searchKey = request.GET.get('searchKey')
  421. def count_devices(ownerId):
  422. devNoList = [device['devNo'] for device in
  423. Device.get_collection().find({'ownerId': ownerId, 'groupId': {'$ne': ''}}, {'devNo': 1, '_id': 0})]
  424. allCount = len(devNoList)
  425. devDict = Device.get_dev_by_nos(devNoList)
  426. if not devDict:
  427. return 0, 0, 0, 0, 0
  428. onlineCount = 0
  429. expire_count = 0
  430. to_expire_count = 0
  431. for devNo, dev in devDict.items():
  432. if dev.online:
  433. onlineCount += 1
  434. if dev.is_expired:
  435. expire_count += 1
  436. if dev.is_to_expired:
  437. to_expire_count += 1
  438. offlineCount = allCount - onlineCount
  439. return onlineCount, offlineCount, allCount, expire_count, to_expire_count
  440. dealers = Dealer.objects(agentId = str(request.user.id)).search(searchKey)
  441. dataList = []
  442. dealers_per_page = dealers.paginate(pageIndex, pageSize)
  443. for dealer in dealers_per_page:
  444. onlineCount, offlineCount, allCount, expireCount, toExpireCount = count_devices(str(dealer.id))
  445. dataList.append({
  446. 'name': dealer.nickname,
  447. 'id': str(dealer.id),
  448. 'tel': dealer.username,
  449. 'onCount': onlineCount,
  450. 'offlineCount': offlineCount,
  451. 'deviceCount': allCount,
  452. 'expireCount': expireCount,
  453. 'toExpireCount': toExpireCount,
  454. 'adShow': dealer.adShow,
  455. 'annualTrafficCost': dealer.annualTrafficCost,
  456. })
  457. #: 暂时保持偏序,全序列需要优化实现
  458. dataList.sort(key = itemgetter('deviceCount'), reverse = True)
  459. return JsonResponse({
  460. 'result': 1,
  461. 'payload': {
  462. 'dataList': dataList,
  463. 'total': dealers.count()
  464. },
  465. 'description': None
  466. })
  467. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  468. @permission_required(ROLE.agent)
  469. def getReferralDealerList(request):
  470. # type: (WSGIRequest)->JsonResponse
  471. """
  472. 代理商获取旗下经销商列表
  473. :param request:
  474. :return:
  475. """
  476. dealers = Dealer.objects(agentId = str(request.user.id))
  477. dealerNameIdMaps = [{'text': d.nickname, 'value': str(d.id)} for d in dealers]
  478. return JsonResponse({'result': 1,
  479. 'description': None,
  480. 'payload': {'dataList': dealerNameIdMaps}})
  481. @permission_required(ROLE.agent)
  482. def verifyRegisterCode(request):
  483. # type: (WSGIRequest)->JsonResponse
  484. """
  485. 代理商创建旗下经销商
  486. :param request:
  487. :return:
  488. """
  489. try:
  490. nickname = request.POST.get('userName')
  491. password = request.POST.get('password')
  492. phone = request.POST.get('phoneNumber')
  493. remark = request.POST.get('remark')
  494. agent = Agent.objects(id = str(request.user.id)).first()
  495. if agent is None:
  496. return JsonErrorResponse()
  497. Dealer.create_user(
  498. username = phone,
  499. password = password,
  500. nickname = nickname,
  501. remark = remark,
  502. agentId = str(agent.id),
  503. adShow = True,
  504. noAdPolicy = 'banner',
  505. annualTrafficCost = agent.annualTrafficCost if \
  506. agent.annualTrafficCost > agent.trafficCardCost else agent.trafficCardCost,
  507. trafficCardCost = agent.trafficCardCost,
  508. withdrawFeeRatio = agent.withdrawFeeRatio if \
  509. agent.withdrawFeeRatio > agent.withdrawFeeRatioCost else agent.withdrawFeeRatioCost
  510. )
  511. logger.info('a new Dealer(nickname=%s) was created by Agent(id=%s)' % (nickname, str(request.user.id)))
  512. return JsonResponse({'result': 1, 'description': 'ok', 'payload': {}})
  513. except NotUniqueError:
  514. return JsonResponse({'result': 0, 'description': u'已有相同手机号注册为经销商!', 'payload': {}})
  515. except Exception, e:
  516. logger.exception(u'agent(name=%s) failed to create dealers, error=%s' % (request.user.nickname, str(e)))
  517. return JsonResponse({'result': 0, 'description': u'系统错误,请重试', 'payload': {}})
  518. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'LOGO文件存储失败,请重新试试'))
  519. @permission_required(ROLE.agent)
  520. def uploadLogo(request):
  521. # type: (WSGIRequest)->JsonResponse
  522. files = request.FILES.getlist('file')
  523. if not len(files):
  524. return JsonResponse({'result': 0, 'description': u'未知的logo文件文件信息,请重新试试', 'payload': {}})
  525. uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'logo')
  526. logger.info('[uploadLogo] %s is being used' % (repr(uploader),))
  527. try:
  528. outputUrl = uploader.upload()
  529. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  530. except InvalidFileSize as e:
  531. logger.info(
  532. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  533. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  534. except InvalidFileName as e:
  535. logger.info(
  536. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  537. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  538. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'二维码文件存储失败,请重新试试'))
  539. @permission_required(ROLE.agent)
  540. def uploadServiceQrcodeUrl(request):
  541. # type: (WSGIRequest)->JsonResponse
  542. files = request.FILES.getlist('file')
  543. if not len(files):
  544. return JsonResponse({'result': 0, 'description': u'未知的二维码文件信息,请重新试试', 'payload': ''})
  545. uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'qrcode')
  546. logger.info('[uploadServiceQrcodeUrl] %s is being used' % (repr(uploader),))
  547. try:
  548. outputUrl = uploader.upload()
  549. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  550. except InvalidFileSize as e:
  551. logger.info(
  552. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  553. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  554. except InvalidFileName as e:
  555. logger.info(
  556. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  557. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  558. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'二维码文件存储失败,请重新试试'))
  559. @permission_required(ROLE.agent)
  560. def uploadServiceGzhQrcodeUrl(request):
  561. # type: (WSGIRequest)->JsonResponse
  562. files = request.FILES.getlist('file')
  563. if not len(files):
  564. return JsonResponse({'result': 0, 'description': u'未知的二维码文件信息,请重新试试', 'payload': ''})
  565. uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'qrcode')
  566. logger.info('[uploadServiceGzhQrcodeUrl] %s is being used' % (repr(uploader),))
  567. try:
  568. outputUrl = uploader.upload()
  569. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  570. except InvalidFileSize as e:
  571. logger.info(
  572. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  573. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  574. except InvalidFileName as e:
  575. logger.info(
  576. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  577. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  578. @permission_required(ROLE.agent)
  579. def getAgentInfo(request):
  580. # type: (WSGIRequest)->JsonResponse
  581. currentAgent = request.user # type: Agent
  582. para = {
  583. 'productName': currentAgent.productName,
  584. 'productLogo': currentAgent.productLogo,
  585. 'serviceName': currentAgent.serviceName,
  586. 'servicePhone': currentAgent.servicePhone,
  587. 'serviceQrcodeUrl': currentAgent.serviceQrcodeUrl,
  588. 'gzhServiceQrcodeUrl': currentAgent.gzhServiceQrcodeUrl,
  589. 'title': currentAgent.title,
  590. 'desc': currentAgent.desc
  591. }
  592. return JsonResponse({'result': 1, 'description': u'', 'payload': para})
  593. @permission_required(ROLE.agent)
  594. def saveAgentInfo(request):
  595. # type: (WSGIRequest)->JsonResponse
  596. agentId = str(request.user.id)
  597. try:
  598. brandData = json.loads(request.body)
  599. if NAME_RE.match(brandData['productName']) is None:
  600. logger.error('productName formatting error, name=%s' % brandData['productName'])
  601. return JsonResponse({"result": 0, "description": u"请输入正确格式的品牌名称"})
  602. if brandData['serviceName']:
  603. if NAME_RE.match(brandData['serviceName']) is None:
  604. logger.error('serviceName formatting error, name=%s' % brandData['serviceName'])
  605. return JsonResponse({"result": 0, "description": u"请输入正确格式的客服名称"})
  606. if brandData['servicePhone']:
  607. import re
  608. if re.match(r'^\d{5,}$', brandData['servicePhone']) is None:
  609. logger.error('servicePhone number format error, phone=%s' % brandData['servicePhone'])
  610. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  611. servicePhone = brandData['servicePhone']
  612. status, desc = agentRegisterSMSProvider.verify(servicePhone, brandData['code'])
  613. if not status:
  614. return JsonErrorResponse(desc)
  615. Agent.update_agent(agentId, brandData)
  616. except Exception, e:
  617. logger.exception('update Agent product information error=%s,agentId=%s' % (e, agentId))
  618. return JsonResponse({'result': 0, 'description': u'更新代理商产品信息错误', 'payload': {}})
  619. response = JsonResponse({'result': 1, 'description': '', 'payload': {}})
  620. response = Agent.record_cookie(agentId, response)
  621. return response
  622. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  623. @permission_required(ROLE.agent)
  624. def getDealerInfo(request):
  625. # type: (WSGIRequest)->JsonResponse
  626. """
  627. 获取旗下经销商的配置信息(提现费率,流量费用...)
  628. :param request:
  629. :return:
  630. """
  631. dealerId = request.GET.get('id')
  632. try:
  633. dealer = Dealer.objects(id = dealerId).get() # type: Dealer
  634. return JsonResponse(
  635. {
  636. 'result': 1,
  637. 'description': None,
  638. 'payload': {
  639. 'withdrawFeeRatio': dealer.withdrawFeeRatio,
  640. 'withdrawFeeRatioCost': request.user.withdrawFeeRatio,
  641. 'annualTrafficCost': dealer.annualTrafficCost,
  642. 'adShow': dealer.adShow,
  643. 'agentProfitShare': dealer.agentProfitShare,
  644. 'agentMerProfitShare': dealer.agentMerProfitShare,
  645. 'limitDevNum': dealer.limitDevNum,
  646. 'isShowBanner': dealer.isShowBanner,
  647. 'hasTempPackage': dealer.hasTempPackage,
  648. 'agentProxyServicePhone': dealer.linkageSwitch.agentProxyServicePhone
  649. }
  650. }
  651. )
  652. except DoesNotExist:
  653. return JsonResponse({'result': 0, 'description': u'经销商不存在,请刷新后再试', 'payload': {}})
  654. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  655. @permission_required(ROLE.agent)
  656. def setDealerWithdrawFeeRatio(request):
  657. # type: (WSGIRequest)->JsonResponse
  658. """
  659. 设置旗下经销商提现手续费用
  660. :param request:
  661. :return:
  662. """
  663. payload = json.loads(request.body)
  664. dealer = Dealer.objects(id = str(payload['id'])).get()
  665. if 'withdrawFeeRatio' not in payload:
  666. return JsonErrorResponse(description = u'提现手续费没有输入')
  667. withdrawFeeRatio = Ratio(payload.get('withdrawFeeRatio'))
  668. if withdrawFeeRatio < Const.MIN_DEALER_WITHDRAW_FEE_RATIO or withdrawFeeRatio > Const.MAX_DEALER_WITHDRAW_FEE_RATIO:
  669. return JsonErrorResponse(description = u'提现手续费输入错误')
  670. # 有资金池客户可以自行设置提现费率, 平台不做限制
  671. if request.user.customizedWechatCashflowAllowable is not True:
  672. agent = Agent.objects(id = dealer.agentId).first()
  673. if not agent:
  674. return JsonErrorResponse(description = u'不存在的代理商')
  675. if withdrawFeeRatio < agent.withdrawFeeRatio:
  676. return JsonErrorResponse(description = u'提现手续费不能低于厂商提现手续费下限(千分之{})'.format(agent.withdrawFeeRatio))
  677. if withdrawFeeRatio < agent.withdrawFeeRatioCost:
  678. return JsonErrorResponse(description = u'提现手续费不能低于平台手续费最低值(千分之{})'.format(agent.withdrawFeeRatioCost))
  679. updated = dealer.update(withdrawFeeRatio = withdrawFeeRatio.mongo_amount)
  680. if updated:
  681. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  682. else:
  683. return JsonErrorResponse(description = u'设置失败,请重试')
  684. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  685. @permission_required(ROLE.agent)
  686. def setDealerAnnualTrafficCost(request):
  687. # type: (WSGIRequest)->JsonResponse
  688. """
  689. 设置旗下经销商每年流量费用
  690. :param request:
  691. :return:
  692. """
  693. currentAgent = request.user # type: Agent
  694. payload = json.loads(request.body)
  695. dealerId = payload['id']
  696. annualTrafficCost = RMB(payload['annualTrafficCost'])
  697. if annualTrafficCost < currentAgent.annualTrafficCost:
  698. return JsonResponse(
  699. {'result': 0, 'description': u'流量卡年费不能少于%.02f元' % currentAgent.annualTrafficCost, 'payload': {}})
  700. try:
  701. dealer = Dealer.objects.get(id = dealerId) # type: Dealer
  702. dealer.annualTrafficCost = annualTrafficCost
  703. dealer.save()
  704. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  705. except DoesNotExist:
  706. return JsonResponse({'result': 0, 'description': u'经销商不存在,请刷新后再试', 'payload': {}})
  707. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  708. @permission_required(ROLE.agent)
  709. def setBatchDealerAnnualTrafficCost(request):
  710. # type: (WSGIRequest)->JsonResponse
  711. currentAgent = request.user # type: Agent
  712. payload = json.loads(request.body)
  713. dealerIds = [ObjectId(id_) for id_ in payload['ids']]
  714. annualTrafficCost = RMB(payload['annualTrafficCost'])
  715. if annualTrafficCost < currentAgent.annualTrafficCost:
  716. return JsonErrorResponse(description = u'流量卡年费不能少于%s元' % currentAgent.annualTrafficCost)
  717. Dealer.set_traffic_costs_multiply(dealer_ids = dealerIds, cost = annualTrafficCost)
  718. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  719. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  720. @permission_required(ROLE.agent)
  721. def setDealerAgentProfitShare(request):
  722. # type: (WSGIRequest)->JsonResponse
  723. """
  724. 代理商设置经销商设备经营提成比例
  725. :param request:
  726. :return:
  727. """
  728. payload = json.loads(request.body)
  729. dealer = Dealer.objects.get(id = payload['id']) # type: Dealer
  730. agentProfitShare = Percent(payload['agentProfitShare'])
  731. try:
  732. maxProfitShare = Percent("100.0")
  733. minProfitShare = Percent('0.0')
  734. if agentProfitShare < minProfitShare or agentProfitShare > maxProfitShare:
  735. return JsonErrorResponse(
  736. description = u'分成比例错误,当前最大分成比例 {},最小分成比例 {}'.format(maxProfitShare, minProfitShare))
  737. updated = dealer.set_agent_profit_share(agentProfitShare)
  738. if not updated:
  739. return JsonErrorResponse(description = u'更新错误,请重试')
  740. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  741. except DoesNotExist:
  742. return JsonErrorResponse(description = u'经销商不存在,请刷新后再试')
  743. @error_tolerate(nil = JsonErrorResponse(u'设备类型不支持'), logger = logger)
  744. @permission_required(ROLE.agent)
  745. def getPackageList(request):
  746. # type: (WSGIRequest)->JsonResponse
  747. devTypeId = request.GET.get('typeId', None)
  748. if not devTypeId:
  749. return JsonErrorResponse(description = u'设备类型为空')
  750. dealerId = request.GET.get('dealerId', None)
  751. from apps.web.dealer.models import Dealer
  752. try:
  753. dealer = Dealer.objects.get(id = dealerId) # type: Dealer
  754. except DoesNotExist:
  755. return JsonErrorResponse(description = u'经销商不存在')
  756. if devTypeId in dealer.defaultWashConfig:
  757. dataList = dealer.defaultWashConfig[devTypeId]
  758. else:
  759. dataList = DeviceType.objects(id = str(devTypeId)).get().package
  760. return JsonResponse({'result': 1, 'description': None, 'payload': dataList})
  761. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  762. @permission_required(ROLE.agent)
  763. def onPoints(request):
  764. # type: (WSGIRequest)->JsonResponse
  765. """
  766. 远程上分, 代理商通过上分测试机器系统流程正确。
  767. :param request:
  768. :return:
  769. """
  770. logicalCode = request.POST.get('logicalCode', None)
  771. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  772. dev = Device.get_dev(devNo)
  773. if not dev:
  774. return JsonErrorResponse(description = u'设备不存在')
  775. ruleId = request.POST.get('ruleId', 1)
  776. # 到设备上获取驱动编码信息
  777. devInfo = MessageSender.send(device = dev, cmd = DeviceCmdCode.GET_DEVINFO, payload = {'IMEI': dev['devNo']})
  778. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  779. if devInfo['rst'] == -1:
  780. return JsonResponse({'result': 0, 'description': u'设备正在玩命找网络,设备是否上线有问题?'})
  781. elif devInfo['rst'] == 1:
  782. return JsonResponse({'result': 0, 'description': u'模块之间的串口通讯有问题, 设备的串口接线是否有问题?'})
  783. if devInfo.has_key('driverCode'):
  784. type_code = devInfo['driverCode']
  785. else:
  786. type_code = Const.DEVICE_TYPE_CODE_PULSE
  787. try:
  788. device_adapter = ActionDeviceBuilder.create_action_device(dev, typeCode = type_code)
  789. result = device_adapter.test(coins = ruleId)
  790. if 'rst' in result and result['rst'] != 0:
  791. if result['rst'] == -1:
  792. return JsonResponse({'result': 0, 'description': u'设备正在玩命找网络,设备是否上线有问题?'})
  793. elif result['rst'] == 1:
  794. return JsonResponse({'result': 0, 'description': u'模块之间的串口通讯有问题, 设备的串口接线是否有问题?'})
  795. else:
  796. return JsonResponse({'result': 0, 'description': u'错误{}'.format(result['rst'])})
  797. except ServiceException as e:
  798. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  799. return JsonResponse({'result': 1, 'description': u'success'})
  800. @permission_required(ROLE.agent)
  801. def labelBadDevice(request):
  802. # type: (WSGIRequest)->JsonResponse
  803. """
  804. 标记坏的设备,便于我们记录错误信息
  805. :param request:
  806. :return:
  807. """
  808. logicalCode = request.POST.get('value', None)
  809. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  810. desc = request.POST.get('desc', '')
  811. if not devNo:
  812. return JsonResponse({'result': 0, 'description': u'设备不存在'})
  813. try:
  814. CheckDevice.get_collection().update_one({'imei': devNo},
  815. {'$set': {'testResultDesc': desc}}, upsert = False)
  816. except Exception as e:
  817. logger.info('update check device error = %s' % e)
  818. return JsonResponse({'result': 0, 'description': 'update check device error=%s' % e})
  819. return JsonResponse({'result': 1, 'description': u'success'})
  820. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  821. @permission_required(ROLE.manager, ROLE.advertisement, ROLE.advertiser)
  822. def getAgentsDetailList(request):
  823. # type: (WSGIRequest)->JsonResponse
  824. """
  825. 渲染代理商列表
  826. :param request:
  827. :return:
  828. """
  829. manager_id = str(request.user.id)
  830. page_index = int(request.GET.get('pageIndex', 1))
  831. page_size = int(request.GET.get('pageSize', 100000))
  832. search_key = request.GET.get('searchKey', None)
  833. total, items = Agent.filter(manager_id = manager_id, search_key = search_key, page_index = page_index,
  834. page_size = page_size)
  835. return JsonOkResponse(payload = {'total': total, 'dataList': items})
  836. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  837. @permission_required(ROLE.agent)
  838. def equipmentList(request):
  839. """
  840. 查看旗下经销商设备
  841. :param request:
  842. :return:
  843. """
  844. agentId = str(request.user.id)
  845. dealerId = request.GET.get("dealerId")
  846. online = request.GET.get("online")
  847. expireStatus = request.GET.get("expireStatus", "all")
  848. groupId = request.GET.get("equipmentGroupId")
  849. searchKey = request.GET.get("searchKey")
  850. dealer = Dealer.objects.get(id = dealerId)
  851. if dealer.agentId != agentId:
  852. return JsonErrorResponse(description = u"无权限")
  853. groupIds, devList = Device.filter(
  854. dealerId = dealerId,
  855. searchKey = searchKey,
  856. online = online,
  857. expireStatus = expireStatus,
  858. equipmentGroupId = groupId
  859. )
  860. return JsonResponse({
  861. 'result': 1,
  862. 'description': None,
  863. 'payload': {
  864. 'total': len(groupIds),
  865. 'groupCount': len(devList),
  866. 'dataList': devList
  867. }
  868. })
  869. @permission_required(ROLE.agent)
  870. def logout(request):
  871. # type: (WSGIRequest)->JsonResponse
  872. agentId = str(request.user.id)
  873. auth.logout(request)
  874. response = JsonResponse({'result': 1}) # type: JsonResponse
  875. response.set_cookie(key = 'agentId', value = agentId, max_age = 30 * 24 * 3600, domain = settings.COOKIE_DOMAIN)
  876. return response
  877. @permission_required(ROLE.agent)
  878. def wxconfig(request):
  879. # type: (WSGIRequest)->JsonResponse
  880. url = request.GET.get('href')
  881. if not url:
  882. return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}})
  883. currentAgent = request.user # type: cast(Agent)
  884. value = get_wx_config(currentAgent, url)
  885. return JsonResponse({'result': 1, 'description': None, 'payload': {'wxconfig': value}})
  886. @permission_required(ROLE.agent)
  887. def toggleSwitches(request):
  888. # type: (WSGIRequest)->JsonResponse
  889. agentId = str(request.user.id)
  890. try:
  891. Agent.update_agent(agentId, json.loads(request.body))
  892. except Exception, e:
  893. logger.exception('update Agent product information error=%s,agentId=%s' % (e, agentId))
  894. return JsonResponse({'result': 0, 'description': u'更新代理商产品信息错误', 'payload': {}})
  895. response = JsonResponse({'result': 1, 'description': '', 'payload': {}})
  896. return response
  897. # 代理商获取短信验证码
  898. @error_tolerate(nil = DefaultJsonErrorResponse)
  899. def getCheckCode(request):
  900. # type: (WSGIRequest)->JsonResponse
  901. payload = json.loads(request.body)
  902. toNumber = payload.get('phone', None)
  903. agent = Agent.objects(username = toNumber).first()
  904. if not agent:
  905. return JsonResponse({'result': 0, 'description': u'该代理商用户不存在'})
  906. productName = agent.productName or agent.primary_agent.productName
  907. sessionId = payload.get('csessionid', None)
  908. sig = payload.get('sig', None)
  909. token = payload.get('nc_token', None)
  910. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  911. if type(result) is dict:
  912. resultCode = result.get('Code', 900)
  913. else:
  914. resultCode = 900
  915. if resultCode == 100:
  916. status, msg = agentRegisterSMSProvider.get(phoneNumber = toNumber,
  917. productName = productName,
  918. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  919. if not status:
  920. return JsonResponse({'result': 0, 'description': msg})
  921. else:
  922. return JsonResponse({'result': 1, 'description': ''})
  923. else:
  924. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  925. # 代理商验证短信验证码
  926. @error_tolerate(nil = DefaultJsonErrorResponse)
  927. def verifyForgetCode(request):
  928. # type: (WSGIRequest)->JsonResponse
  929. phone = request.POST.get('phone', None)
  930. code = request.POST.get('code', None)
  931. password = request.POST.get('password', '')
  932. status, desc = agentRegisterSMSProvider.verify(phone, code)
  933. if not status:
  934. return JsonErrorResponse(desc)
  935. if password == '':
  936. return JsonErrorResponse(u"请输入密码")
  937. agent = Agent.objects(username = phone).first() # type: Optional[Agent]
  938. agent.set_password(password)
  939. agent.unlock_login()
  940. return JsonResponse({"result": 1, "description": None, "payload": {}})
  941. @error_tolerate(nil = DefaultJsonErrorResponse)
  942. @permission_required(ROLE.agent)
  943. def walletData(request):
  944. # type: (WSGIRequest)->JsonResponse
  945. agent = request.user # type: Agent
  946. customized_source_key = agent.current_wallet_withdraw_source_key
  947. inhouse_source_key = Agent.get_inhouse_prime_agent().current_wallet_withdraw_source_key
  948. payload = {
  949. }
  950. withdraw_income_list = []
  951. for source_key, balance in agent.withdrawBalance.iteritems():
  952. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  953. withdraw_income_list.append({
  954. 'id': source_key,
  955. 'balance': balance.balance,
  956. 'name': current_platform(source_key, customized_source_key),
  957. 'current': source_key == customized_source_key
  958. })
  959. if len(withdraw_income_list) > 0:
  960. payload.update({
  961. AGENT_INCOME_TYPE.DEALER_WITHDRAW_FEE: withdraw_income_list
  962. })
  963. traffic_income_list = []
  964. for source_key, balance in agent.trafficBalance.iteritems():
  965. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  966. traffic_income_list.append({
  967. 'id': source_key,
  968. 'balance': balance.balance,
  969. 'name': current_platform(source_key, inhouse_source_key),
  970. 'current': source_key == inhouse_source_key
  971. })
  972. if len(traffic_income_list) > 0:
  973. payload.update({
  974. AGENT_INCOME_TYPE.DEALER_CARD_FEE: traffic_income_list
  975. })
  976. device_income_list = []
  977. for source_key, balance in agent.deviceBalance.iteritems():
  978. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  979. device_income_list.append({
  980. 'id': source_key,
  981. 'balance': balance.balance,
  982. 'name': current_platform(source_key, customized_source_key),
  983. 'current': source_key == customized_source_key
  984. })
  985. if len(device_income_list) > 0:
  986. payload.update({
  987. AGENT_INCOME_TYPE.DEALER_DEVICE_FEE: device_income_list
  988. })
  989. return JsonResponse({'result': 1, 'description': None, 'payload': payload})
  990. @permission_required(ROLE.agent)
  991. def getWithdrawCode(request):
  992. # type: (WSGIRequest)->JsonResponse
  993. phone = request.user.username
  994. agentId = str(request.user.id)
  995. agent = Agent.objects(id = agentId).first()
  996. if not agent:
  997. return JsonResponse({"result": 0, "description": u"没有找到代理商", 'payload': {}})
  998. productName = agent.productName
  999. status, msg = agentWithdrawSMSProvider.get(phoneNumber = phone,
  1000. productName = productName,
  1001. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  1002. if not status:
  1003. return JsonResponse({'result': 0, 'description': msg})
  1004. else:
  1005. return JsonResponse({'result': 1, 'description': ''})
  1006. @permission_required(ROLE.agent)
  1007. def agentWithdraw(request):
  1008. # type: (WSGIRequest)->JsonResponse
  1009. logger.info(u'agent(phone=%s) 发起提现,具体数据为 %s' % (str(request.user.username), request.body.decode('utf-8')))
  1010. payload = json.loads(request.body)
  1011. pay_type = payload.get('payType')
  1012. assert pay_type in (
  1013. WITHDRAW_PAY_TYPE.WECHAT, WITHDRAW_PAY_TYPE.BANK, WITHDRAW_PAY_TYPE.ALIPAY), 'not support this pay type'
  1014. if pay_type == WITHDRAW_PAY_TYPE.WECHAT:
  1015. open_id = payload.get('openId')
  1016. if not open_id:
  1017. return JsonResponse({"result": 0, "description": u'鉴权失败,请刷新后再试', 'payload': {}})
  1018. request.user.withdraw_open_id = open_id
  1019. amount = RMB(payload.get('amount', 0.0))
  1020. assert amount > RMB(0), 'amount must be bigger than zero'
  1021. status, msg = request.user.withdraw_sms_provider.verify(phoneNumber = request.user.withdraw_sms_phone_number,
  1022. smsCode = payload.get('code'))
  1023. if not status:
  1024. return JsonResponse({"result": 0, "description": msg, 'payload': {}})
  1025. withdraw_service = AgentWithdrawService(payee = request.user,
  1026. income_type = payload.get('sourceType'),
  1027. amount = amount,
  1028. pay_type = pay_type,
  1029. bank_card_no = payload.get('bankAccount', ''))
  1030. return JsonResponse(withdraw_service.execute(source_key = payload.get('sourceId'), recurrent = False))
  1031. @permission_required(ROLE.agent)
  1032. def withdrawalsHistoryList(request):
  1033. # type: (WSGIRequest)->JsonResponse
  1034. pageIndex = int(request.GET.get('pageIndex', 1))
  1035. pageSize = int(request.GET.get('pageSize', 10))
  1036. agentId = str(request.user.id)
  1037. total = WithdrawRecord.objects(ownerId = agentId, role = request.user.role).count()
  1038. if total == 0:
  1039. return JsonResponse({"result": 1, "description": None, 'payload': {"total": 0, "dataList": []}})
  1040. records = WithdrawRecord.objects(ownerId = agentId, role = request.user.role).order_by('-postTime')
  1041. withdrawalList = [
  1042. {
  1043. 'bankName': record.parentBankName,
  1044. 'paymentId': str(record.id),
  1045. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"),
  1046. 'amount': record.amount,
  1047. 'statusText': translate_withdraw_state(record.status)
  1048. } for record in records.paginate(pageIndex, pageSize)
  1049. ]
  1050. return JsonResponse({
  1051. "result": 1,
  1052. "description": None,
  1053. 'payload': {
  1054. "total": total,
  1055. "withdrawalTotal": RMB(records(status = WithdrawStatus.SUCCEEDED).sum('amount')),
  1056. "dataList": withdrawalList
  1057. }
  1058. })
  1059. @permission_required(ROLE.agent)
  1060. def paymentInfo(request):
  1061. # type: (WSGIRequest)->JsonResponse
  1062. agentId = str(request.user.id)
  1063. paymentId = request.GET.get('paymentId', None)
  1064. record = WithdrawRecord.objects(id = str(paymentId)).first() # type: Optional[WithdrawRecord]
  1065. if not record:
  1066. return JsonResponse({'result': 0, 'description': u'没有找到提现记录', 'payload': {}})
  1067. return JsonResponse({
  1068. 'result': 1,
  1069. 'description': '',
  1070. 'payload': {
  1071. 'type': record.parentBankName,
  1072. 'amount': record.amount,
  1073. 'serviceFee': record.serviceFee,
  1074. 'preBalance': record.balance,
  1075. 'actualPay': record.actualPay,
  1076. 'statusText': translate_withdraw_state(record.status),
  1077. 'refunded': record.refunded,
  1078. 'description': record.description,
  1079. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"),
  1080. }
  1081. })
  1082. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1083. @permission_required(ROLE.agent)
  1084. def getWalletWithdrawInfo(request):
  1085. source_key = request.GET.get('sourceId')
  1086. income_type = request.GET.get('sourceType')
  1087. agent = Agent.objects(id = str(request.user.id)).first()
  1088. phone = str(request.user.username)
  1089. result = {
  1090. "result": 1,
  1091. "description": None,
  1092. 'payload': {
  1093. 'payOpenId': 'placeholder',
  1094. 'phone': phone,
  1095. 'balance': agent.sub_balance(income_type, source_key),
  1096. 'withdrawFeeRatio': Const.PLATFORM_DEFAULT_WITHDRAW_FEE_RATIO,
  1097. 'support': agent.withdraw_support(source_key)
  1098. }
  1099. }
  1100. return JsonResponse(result)
  1101. @permission_required(ROLE.agent)
  1102. def updateInfo(request):
  1103. # type: (WSGIRequest)->JsonResponse
  1104. """
  1105. 支持代理商更改用户信息
  1106. :param request:
  1107. :return:
  1108. """
  1109. name = request.POST.get('name')
  1110. if NAME_RE.match(name) is None:
  1111. logger.info('update agent name doesn\'t fit format, name=%s' % (name.encode('utf-8'),))
  1112. return JsonResponse({"result": 0, "description": u'请输入正确格式的名称(2-20位)'})
  1113. agent = Agent.objects(id = request.user.id).first() # type: Optional[Agent]
  1114. if agent is None:
  1115. return JsonResponse({"result": 0, "description": u'该经销商不存在'})
  1116. updated = agent.update(nickname = name)
  1117. if not updated:
  1118. logger.info('Agent [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1119. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1120. else:
  1121. return JsonResponse({"result": 1, "description": None})
  1122. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请刷新'))
  1123. @permission_required(ROLE.agent)
  1124. def getFeatureList(request):
  1125. # type: (WSGIRequest)->JsonResponse
  1126. """
  1127. :param request:
  1128. :return:
  1129. """
  1130. currentUser = request.user # type: Agent
  1131. payload = json.loads(request.body)
  1132. filter_list = payload['list'] if 'list' in payload else None
  1133. features = {}
  1134. all_features = currentUser.feature_boolean_map
  1135. if filter_list:
  1136. for feature_name in filter_list:
  1137. if feature_name in all_features:
  1138. features[feature_name] = all_features[feature_name]
  1139. else:
  1140. features[feature_name] = False
  1141. else:
  1142. features = all_features
  1143. return JsonResponse({'result': 1, 'payload': features, 'description': ''})
  1144. @permission_required(ROLE.agent)
  1145. def adminAgreeWallet(request):
  1146. # type: (WSGIRequest)->JsonResponse
  1147. """
  1148. 管理后台通过提现按钮,这里暂时继续支持,以作相对事件的应急处理与补充。
  1149. :param request:
  1150. :return:
  1151. """
  1152. def admin_dealer_withdraw(withdraw_record):
  1153. # type: (WithdrawRecord)->None
  1154. dealer = Dealer.objects(id = str(withdraw_record.ownerId)).get() # type: Dealer
  1155. handler = dealer.new_withdraw_handler(withdraw_record)
  1156. handler.approve()
  1157. return JsonOkResponse(description = u'提现成功', payload = {})
  1158. def admin_agent_withdraw(withdraw_record):
  1159. # type: (WithdrawRecord)->None
  1160. """
  1161. :type withdraw_record: WithdrawRecord
  1162. """
  1163. agent = Agent.objects(id = str(withdraw_record.ownerId)).get() # type: Agent
  1164. handler = agent.new_withdraw_handler(withdraw_record)
  1165. handler.approve()
  1166. return JsonOkResponse(description = u'提现成功', payload = {})
  1167. payload = json.loads(request.body)
  1168. order = str(payload.get('orderNo'))
  1169. try:
  1170. with WithdrawRecord.process_memcache_lock(order) as acquired:
  1171. if acquired:
  1172. withdraw_record = WithdrawRecord.objects(order = order).first() # WithdrawRecord
  1173. try:
  1174. check_record_when_revoke_or_approve(withdraw_record, str(request.user.id))
  1175. except ServiceException as e:
  1176. return JsonResponse(e.result)
  1177. if withdraw_record.role == ROLE.dealer:
  1178. return admin_dealer_withdraw(withdraw_record)
  1179. elif withdraw_record.role == ROLE.agent:
  1180. return admin_agent_withdraw(withdraw_record)
  1181. else:
  1182. return JsonOkResponse(description = u'参数错误,请刷新后再试', payload = {})
  1183. else:
  1184. # 重复丢弃该请求
  1185. logger.debug('duplicate request for WithdrawRecord. orderNo = %s' % order)
  1186. except Exception, e:
  1187. logger.exception(e)
  1188. return JsonOkResponse(description = u'处理提现申请失败,请重试', payload = {})
  1189. @permission_required(ROLE.agent)
  1190. def getWithdrawList(request):
  1191. # type: (WSGIRequest)->JsonResponse
  1192. """
  1193. 获取提现申请列表
  1194. :param request:
  1195. :return:
  1196. """
  1197. agentId = str(request.user.id)
  1198. pageIndex = int(request.GET.get('pageIndex', 1))
  1199. pageSize = int(request.GET.get('pageSize', 10))
  1200. searchKey = request.GET.get('searchKey', None)
  1201. date_start = request.GET.get('dateStart')
  1202. date_end = request.GET.get('dateEnd')
  1203. query = {
  1204. 'payAgentId': agentId,
  1205. 'postTime': {
  1206. '$gte': to_datetime(date_start + " 00:00:00"),
  1207. '$lte': to_datetime(date_end + " 23:59:59")}
  1208. }
  1209. status = int(request.GET.get('status'))
  1210. if status == 0:
  1211. query.update({
  1212. '$or': [{'status': WithdrawStatus.FAILED},
  1213. {'status': WithdrawStatus.PROCESSING, 'manual': True}]})
  1214. elif status == -1:
  1215. pass
  1216. else:
  1217. query.update({'status': status})
  1218. records = WithdrawRecord.objects(__raw__ = query).search(searchKey).order_by('-postTime')
  1219. total = records.count()
  1220. dataList = [
  1221. {
  1222. 'name': r.name,
  1223. 'tel': r.phone,
  1224. 'dateTime': r.postTime,
  1225. 'orderNo': r.order,
  1226. 'actualPay': r.actualPay,
  1227. 'cardId': r.accountCode,
  1228. 'cardUserName': r.cardUserName,
  1229. 'bankName': r.parentBankName,
  1230. 'subBankName': r.subBankName,
  1231. 'operResult': r.status,
  1232. 'payType': r.payType,
  1233. 'amount': r.amount,
  1234. 'remarks': r.remarks,
  1235. 'manual': r.manual
  1236. } for r in records.paginate(pageIndex, pageSize)
  1237. ]
  1238. return JsonOkResponse(description = '', payload = {
  1239. 'total': total,
  1240. 'dataList': dataList
  1241. })
  1242. @error_tolerate(nil = DefaultJsonErrorResponse)
  1243. @permission_required(ROLE.agent)
  1244. def revokeWithdrawApplication(request):
  1245. # type: (WSGIRequest)->JsonResponse
  1246. """
  1247. 对于已经失败的提现单予以关闭
  1248. :param request:
  1249. :return:
  1250. """
  1251. payload = json.loads(request.body)
  1252. order = str(payload.get('orderNo'))
  1253. def revoke_dealer_withdraw(withdraw_record, remarks, description):
  1254. # type: (WithdrawRecord, str, str)->None
  1255. dealer = Dealer.objects(id = str(withdraw_record.ownerId)).get() # type: Dealer
  1256. handler = dealer.new_withdraw_handler(withdraw_record)
  1257. handler.revoke(remarks = remarks, description = description)
  1258. return JsonOkResponse(description = u'关闭提现申请成功', payload = {})
  1259. def revoke_agent_withdraw(withdraw_record, remarks, description):
  1260. # type: (WithdrawRecord, str, str)->None
  1261. """
  1262. :type withdraw_record: WithdrawRecord
  1263. """
  1264. agent = Agent.objects(id = str(withdraw_record.ownerId)).get() # type: Agent
  1265. handler = agent.new_withdraw_handler(withdraw_record)
  1266. handler.revoke(remarks = remarks, description = description)
  1267. return JsonOkResponse(description = u'关闭提现申请成功', payload = {})
  1268. try:
  1269. with WithdrawRecord.process_memcache_lock(order) as acquired:
  1270. if acquired:
  1271. record = WithdrawRecord.objects(order = payload.get('orderNo')).first() # type: WithdrawRecord
  1272. try:
  1273. check_record_when_revoke_or_approve(record, str(request.user.id))
  1274. except ServiceException as e:
  1275. return JsonResponse(e.result)
  1276. if record.role == ROLE.dealer:
  1277. revoke_dealer_withdraw(record, u'资金池关闭订单', payload.get('reason', ''))
  1278. elif record.role == ROLE.agent:
  1279. revoke_agent_withdraw(record, u'资金池关闭订单', payload.get('reason', ''))
  1280. return JsonOkResponse(description = u'关闭提现申请成功', payload = {})
  1281. else:
  1282. # 重复提现, 丢弃该请求
  1283. logger.debug('duplicate request for WithdrawRecord. orderNo = %s' % order)
  1284. except Exception, e:
  1285. logger.exception(e)
  1286. return JsonErrorResponse(description = u'处理提现申请失败,请联系客服处理', payload = {})
  1287. @permission_required(ROLE.agent)
  1288. def getWithdrawDetail(request):
  1289. # type: (WSGIRequest)->JsonResponse
  1290. """
  1291. 获取经销商提现申请列表
  1292. :param request:
  1293. :return:
  1294. """
  1295. order = request.GET.get('orderNo')
  1296. r = WithdrawRecord.objects().filter(order = order).first() # type: WithdrawRecord
  1297. if not r:
  1298. return JsonErrorResponse(u'提现申请不存在,请刷新')
  1299. return JsonOkResponse(description = '', payload = {
  1300. 'name': r.name,
  1301. 'tel': r.phone,
  1302. 'dateTime': r.postTime,
  1303. 'orderNo': r.order,
  1304. 'actualPay': r.actualPay,
  1305. 'cardId': r.accountCode,
  1306. 'cardUserName': r.cardUserName,
  1307. 'bankName': r.parentBankName,
  1308. 'subBankName': r.subBankName,
  1309. 'operResult': r.status,
  1310. 'payType': r.payType,
  1311. 'amount': r.amount,
  1312. 'serviceFee': r.serviceFee,
  1313. 'actualPay': r.actualPay,
  1314. 'beforeBalance': r.balance,
  1315. 'remarks': r.remarks,
  1316. 'dealerId': r.ownerId,
  1317. 'manual': r.manual,
  1318. 'role': r.role
  1319. })
  1320. @error_tolerate(nil = DefaultJsonErrorResponse)
  1321. @permission_required(ROLE.agent)
  1322. def setLimitDevNum(request):
  1323. # type: (WSGIRequest)->JsonResponse
  1324. """
  1325. 设置经销商注册设备个数限制
  1326. :param request:
  1327. :return:
  1328. """
  1329. payload = json.loads(request.body)
  1330. dealer = Dealer.objects(id = str(payload['id'])).first()
  1331. if dealer is None:
  1332. return JsonErrorResponse(description = u'不存在的经销商')
  1333. dealer.limitDevNum = int(payload['limitDevNum'])
  1334. dealer.save()
  1335. return JsonOkResponse(description = u'设置成功', payload = {})
  1336. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请稍后再试'))
  1337. def withdrawEntry(request):
  1338. # type: (WSGIRequest)->JsonResponse
  1339. user = request.user # type: Agent
  1340. source_key = request.GET.get('sourceId')
  1341. if not WithdrawGateway.is_ledger(source_key):
  1342. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10003)')
  1343. source_type = request.GET.get('sourceType')
  1344. assert source_type in AGENT_INCOME_TYPE.choices(), 'invalid dealer income type'
  1345. if source_key not in user.balance_dict(source_type):
  1346. return ErrorResponseRedirect(error = u'提现参数错误,请刷新后重试')
  1347. is_ledger, agent, withdraw_gateway_list = Agent.withdraw_gateway_list(source_key)
  1348. if not is_ledger:
  1349. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10005)')
  1350. wechat_withdraw_gateway = withdraw_gateway_list['wechat'] # type: WithdrawGateway
  1351. if wechat_withdraw_gateway.support_withdraw and not wechat_withdraw_gateway.manual_withdraw:
  1352. code = request.GET.get('code', None)
  1353. if not code:
  1354. redirect = request.GET.get('redirect')
  1355. return ExternalResponseRedirect(
  1356. WechatAuthBridge(wechat_withdraw_gateway.app).generate_auth_url_base_scope(concat_server_end_url(
  1357. uri = '/agent/withdraw/entry?sourceType={source_type}&sourceId={source_key}'.format(
  1358. source_type = source_type,
  1359. source_key = source_key
  1360. )), payload = base64.b64encode(redirect)))
  1361. else:
  1362. auth_bridge = WechatAuthBridge(wechat_withdraw_gateway.app)
  1363. openId = auth_bridge.authorize(code)
  1364. if openId is not None:
  1365. redirect = base64.b64decode(request.GET.get('payload'))
  1366. redirect = add_query(redirect, {
  1367. 'sourceType': source_type,
  1368. 'sourceId': source_key,
  1369. 'openId': openId
  1370. })
  1371. return FrontEndResponseRedirect(redirect)
  1372. else:
  1373. return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试')
  1374. else:
  1375. redirect = request.GET.get('redirect')
  1376. redirect = add_query(redirect, {
  1377. 'sourceType': source_type,
  1378. 'sourceId': source_key,
  1379. 'openId': ''
  1380. })
  1381. return FrontEndResponseRedirect(redirect)
  1382. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1383. @permission_required(ROLE.agent)
  1384. def bindWechatEntry(request):
  1385. # type: (WSGIRequest)->JsonResponse
  1386. """
  1387. 跳转到微信授权页面绑定
  1388. :param request:
  1389. :return:
  1390. """
  1391. current_agent = request.user # type: cast(Agent)
  1392. auth_bridge = get_wechat_auth_bridge(source = current_agent, app_type = APP_TYPE.WECHAT_AUTH)
  1393. auth_code = request.GET.get(auth_bridge.auth_code_key, None)
  1394. if auth_code:
  1395. openId = auth_bridge.authorize(auth_code)
  1396. bound_info = {
  1397. 'appId': auth_bridge.app.appid,
  1398. 'openId': openId,
  1399. 'boundTime': datetime.datetime.now()
  1400. }
  1401. logger.debug(
  1402. 'agent(id={}) is binding wechat, bridge = {}, bound = {}'.format(str(current_agent.id), auth_bridge,
  1403. str(bound_info)))
  1404. if 'payload' in request.GET:
  1405. redirect = base64.b64decode(request.GET.get('payload'))
  1406. else:
  1407. redirect = '/agents/bind-id.html'
  1408. bind_type = request.GET.get('bindType')
  1409. if bind_type == 'bindCard':
  1410. bound_info_updated = current_agent.update(cardWechatInfo = bound_info)
  1411. if bound_info_updated:
  1412. add_query(redirect, {'result': 'ok'})
  1413. return FrontEndResponseRedirect(redirect)
  1414. else:
  1415. add_query(redirect, {'result': 'error'})
  1416. return FrontEndResponseRedirect(redirect)
  1417. else:
  1418. add_query(redirect, {'result': 'error'})
  1419. return FrontEndResponseRedirect(redirect)
  1420. else:
  1421. bind_type = request.POST.get('bindType')
  1422. redirect = request.POST.get('redirect', '/agents/bind-id.html')
  1423. url = auth_bridge.generate_auth_url_base_scope(
  1424. redirect_uri = concat_server_end_url(uri = '/agent/wechat/bind?bindType={}'.format(bind_type)),
  1425. payload = base64.b64encode(redirect) if redirect else '')
  1426. return JsonResponse(
  1427. {
  1428. 'result': 1,
  1429. 'description': None,
  1430. 'payload': {
  1431. 'redirect_uri': url
  1432. }
  1433. })
  1434. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1435. @permission_required(ROLE.agent)
  1436. def getBoundWechat(request):
  1437. # type: (WSGIRequest)->JsonResponse
  1438. '''
  1439. 获取绑定后台openId的用户信息
  1440. :param request:
  1441. :return:
  1442. '''
  1443. current_agent = request.user # type: cast(Agent)
  1444. bind_type = request.GET.get('bindType')
  1445. if bind_type == 'bindCard':
  1446. return JsonResponse(
  1447. {
  1448. 'result': 1,
  1449. 'description': None,
  1450. 'payload': {
  1451. 'bound': True if current_agent.cardWechatInfo.get('openId', None) else False,
  1452. 'avatar': current_agent.cardWechatInfo.get('avatar', ''),
  1453. 'sex': current_agent.cardWechatInfo.get('sex', ''),
  1454. 'nickname': current_agent.cardWechatInfo.get('nickname', '')
  1455. }
  1456. })
  1457. else:
  1458. return JsonResponse({'result': 0, 'description': u'获取绑定的微信信息失败', 'payload': {}})
  1459. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1460. @permission_required(ROLE.agent)
  1461. def batchBindCard(request):
  1462. # type: (WSGIRequest)->JsonResponse
  1463. '''
  1464. 批量绑定
  1465. :param request:
  1466. :return:
  1467. '''
  1468. current_agent = request.user # type: cast(Agent)
  1469. payload = json.loads(request.body)
  1470. card_name = payload.get('cardName', None)
  1471. if not card_name:
  1472. return JsonResponse({'result': 0, 'description': u'绑定卡主姓名为空', 'payload': {}})
  1473. phone = payload.get('phone', None)
  1474. if not check_phone_number(phone):
  1475. return JsonResponse({'result': 0, 'description': u'绑定卡主手机号为空或者不合法', 'payload': {}})
  1476. card_no_list = payload.get('cardNo')
  1477. dealer_id = payload.get('dealerId')
  1478. dealer = Dealer.objects(id = dealer_id).first() # type: Dealer
  1479. if not dealer or dealer.agentId != str(current_agent.id):
  1480. return JsonResponse({'result': 0, 'description': u'经销商不存在或者不属于本代理商,请刷新数据后再试', 'payload': {}})
  1481. group_id = payload.get('groupId')
  1482. group = Group.objects(id = group_id).first() # type: Group
  1483. if not group or group.ownerId != dealer_id:
  1484. return JsonResponse({'result': 0, 'description': u'投放组地址不存在或者不属于选择的经销商,请刷新数据后再试', 'payload': {}})
  1485. if 'openId' not in current_agent.cardWechatInfo:
  1486. return JsonResponse({'result': 0, 'description': u'请先绑定微信', 'payload': {}})
  1487. if current_agent.boundCardName != card_name or current_agent.boundCardPhone != phone:
  1488. current_agent.boundCardName = card_name
  1489. current_agent.boundCardPhone = phone
  1490. current_agent.save()
  1491. err_list = []
  1492. request = []
  1493. bulker = BulkHandlerEx(Card.get_collection()) # type: BulkHandler
  1494. for card_no in card_no_list:
  1495. if not Card.check_card_no(card_no):
  1496. err_list.append({
  1497. 'cardNo': card_no,
  1498. 'code': 1
  1499. })
  1500. continue
  1501. bulker.insert({
  1502. 'openId': current_agent.cardWechatInfo['openId'],
  1503. 'cardNo': card_no,
  1504. 'agentId': str(current_agent.id),
  1505. 'cardName': card_name,
  1506. 'phone': phone,
  1507. 'groupId': str(group_id),
  1508. 'dealerId': str(dealer_id)
  1509. })
  1510. result = bulker.execute()
  1511. if result['success'] == 0:
  1512. return JsonResponse({'result': 0, 'description': u'全部导入失败,请检查文件格式后重试', 'payload': {}})
  1513. else:
  1514. if len(result['info']['writeErrors']) != 0:
  1515. for item in result['info']['writeErrors']:
  1516. code = item['code']
  1517. op = item['op']
  1518. err_list.append({'cardNo': op.get('cardNo'), 'code': code})
  1519. if len(err_list) > 0:
  1520. if len(err_list) == len(card_no_list):
  1521. return JsonResponse({'result': 0, 'description': u'导入失败,请检查文件格式后重试', 'payload': {}})
  1522. else:
  1523. return JsonResponse({'result': 1, 'description': u'部分导入成功,请重试', 'payload': {'errorList': err_list}})
  1524. else:
  1525. return JsonResponse({'result': 1, 'description': u'导入成功', 'payload': {'errorList': []}})
  1526. @error_tolerate(logger = logger, nil = JsonErrorResponse(u"查询错误"))
  1527. @features_required("agent_card_management")
  1528. @permission_required(ROLE.agent)
  1529. def getUserCardList(request):
  1530. """
  1531. 代理商查看卡列表
  1532. :param request:
  1533. :return:
  1534. """
  1535. # 参数校验
  1536. agentId = str(request.user.id)
  1537. pageSize = int(request.GET.get("pageSize", 10))
  1538. pageIndex = int(request.GET.get("pageIndex", 1))
  1539. dealerId = request.GET.get("dealerId")
  1540. searchKey = request.GET.get("searchKey")
  1541. status = request.GET.get("status")
  1542. filters = {
  1543. "productAgentId": agentId,
  1544. }
  1545. if dealerId:
  1546. filters.update({"dealerId": dealerId})
  1547. else:
  1548. filters.update({"dealerId": ""})
  1549. if status:
  1550. status = bool(int(status))
  1551. if not status:
  1552. filters.update({"openId": ""})
  1553. else:
  1554. filters.update({"openId__ne": ""})
  1555. cards = Card.objects.filter(**filters).search(searchKey)
  1556. total = cards.count()
  1557. dataList = list()
  1558. for card in cards.skip((pageIndex - 1) * pageSize).limit(pageSize):
  1559. try:
  1560. tempData = card.to_dict()
  1561. except Exception as e:
  1562. logger.exception(e)
  1563. continue
  1564. if not card.boundVirtualCardId:
  1565. dataList.append(tempData)
  1566. continue
  1567. try:
  1568. vCard = UserVirtualCard.objects.get(id = card.boundVirtualCardId)
  1569. tempData.update({"vCardNo": vCard.cardNo, "vCardId": card.boundVirtualCardId})
  1570. except Exception as e:
  1571. logger.exception(e)
  1572. continue
  1573. dataList.append(tempData)
  1574. payload = {
  1575. "total": total,
  1576. "dataList": dataList,
  1577. }
  1578. return JsonOkResponse(payload = payload)
  1579. @error_tolerate(logger = logger, nil = JsonErrorResponse(u"清除错误"))
  1580. @features_required("agent_card_management")
  1581. @permission_required(ROLE.agent)
  1582. def clearCardBind(request):
  1583. """
  1584. 代理商 清除卡片的经销商绑定信息
  1585. :param request:
  1586. :return:
  1587. """
  1588. payload = json.loads(request.body)
  1589. cardId = payload.get("cardId", "")
  1590. try:
  1591. card = Card.objects.get(id = cardId, productAgentId = str(request.user.id))
  1592. except DoesNotExist:
  1593. return JsonErrorResponse(u"未查询到卡片,请刷新页面试试")
  1594. card.update(
  1595. dealerId = "",
  1596. groupId = "",
  1597. remarks = "",
  1598. balance = RMB(0),
  1599. lastMaxBalance = RMB(0),
  1600. devNo = "",
  1601. devTypeCode = "",
  1602. frozen = False,
  1603. status = "active",
  1604. openId = "",
  1605. cardName = "",
  1606. phone = "",
  1607. nickname = "",
  1608. boundVirtualCardId = None,
  1609. managerialAppId = "",
  1610. managerialOpenId = ""
  1611. )
  1612. return JsonOkResponse()
  1613. @error_tolerate(logger = logger, nil = JsonErrorResponse(u"清除错误"))
  1614. @features_required("agent_card_management")
  1615. @permission_required(ROLE.agent)
  1616. def clearCardVirtualBind(request):
  1617. """
  1618. 解除虚拟卡的绑定
  1619. :param request:
  1620. :return:
  1621. """
  1622. payload = json.loads(request.body)
  1623. cardId = payload.get("cardId")
  1624. virtualCardId = payload.get("vCardId")
  1625. try:
  1626. card = Card.objects.get(id = cardId, producttAgentId = str(request.user.id))
  1627. except DoesNotExist:
  1628. return JsonErrorResponse(u"未查询到卡片,请刷新页面试试")
  1629. if virtualCardId is None:
  1630. return JsonErrorResponse(description = u'未找到虚拟卡ID')
  1631. virtualCard = UserVirtualCard.objects(id = virtualCardId).first()
  1632. if virtualCard is None:
  1633. return JsonErrorResponse(description = u'未找到虚拟卡')
  1634. updated = card.unbind_virtual_card(virtualCard)
  1635. if updated:
  1636. return JsonOkResponse()
  1637. else:
  1638. return JsonErrorResponse(description = u'解绑失败')
  1639. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1640. @permission_required(ROLE.agent)
  1641. def setShowBanner(request):
  1642. """
  1643. 设置经销商是否显示代理商的banner
  1644. :param request:
  1645. :return:
  1646. """
  1647. payload = json.loads(request.body)
  1648. dealer = Dealer.objects(id = payload['id']).first()
  1649. if dealer is None:
  1650. return JsonErrorResponse(u'不存在的经销商')
  1651. dealer.isShowBanner = payload['value']
  1652. dealer.save()
  1653. return JsonOkResponse()
  1654. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1655. @permission_required(ROLE.agent)
  1656. def setHasTempPackageSwitch(request):
  1657. """
  1658. 设置经销商是否启用临时套餐
  1659. :param request:
  1660. :return:
  1661. """
  1662. payload = json.loads(request.body)
  1663. dealer = Dealer.objects(id = payload['id']).first()
  1664. if dealer is None:
  1665. return JsonErrorResponse(u'不存在的经销商')
  1666. dealer.hasTempPackage = payload['value']
  1667. dealer.save()
  1668. return JsonOkResponse()
  1669. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1670. @permission_required(ROLE.agent)
  1671. def setAgentProxyServicePhone(request):
  1672. """
  1673. 设置代理商接管客诉
  1674. :param request:
  1675. :return:
  1676. """
  1677. payload = json.loads(request.body)
  1678. dealer = Dealer.objects(id = payload['id']).first()
  1679. if dealer is None:
  1680. return JsonErrorResponse(u'不存在的经销商')
  1681. dealer.linkageSwitch.agentProxyServicePhone = payload['value']
  1682. dealer.save()
  1683. return JsonOkResponse()
  1684. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误'))
  1685. @permission_required(ROLE.agent)
  1686. def setBankWithdrawFee(request):
  1687. """
  1688. 设置经销商提现银行卡转账手续费
  1689. :param request:
  1690. :return:
  1691. """
  1692. request.user.dealerBankWithdrawFee = request.GET.get('bankWithdrawFee', False)
  1693. request.user.save()
  1694. return JsonOkResponse()
  1695. @permission_required(ROLE.agent)
  1696. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请稍后再试'))
  1697. def findDevTypeCandidate(request):
  1698. dealerId = request.GET.get('customerId')
  1699. dealer = Dealer.objects(id = dealerId).first()
  1700. if not dealer or dealer.agentId != str(request.user.id):
  1701. return JsonErrorResponse(description = u'经销商不存在,请刷新重试')
  1702. logicalCode = request.GET.get('logicalCode')
  1703. devObj = Device.objects(logicalCode = logicalCode).first() # type: Device
  1704. if not devObj:
  1705. return JsonErrorResponse(description = u'设备不存在,请扫正确的设备二维码')
  1706. _, all = DeviceType.find_candidate(devObj, dealer)
  1707. return JsonOkResponse(payload = {"total": len(all), "dataList": all})