AgentCustomerController.py 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : AgentCustomerController.py
  4. @Time : 2024/3/7 16:56
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import re
  10. import time
  11. import json
  12. from decimal import Decimal
  13. from django.db.models import Sum, F, Q
  14. from django.http import QueryDict
  15. from django.views import View
  16. from django.core.paginator import Paginator
  17. from datetime import datetime, timedelta
  18. from Ansjer.config import CONFIG_CN, LOGGER, CONFIG_INFO
  19. from AgentModel.models import AgentCustomerInfo, AgentCustomerCard, AgentCustomerPackage, AgentCloudServicePackage, \
  20. AgentDeviceOrder, AgentAccountWithdraw, AgentDevice, AgentAccount, ApplyAgent, AgentDeviceOrderInstallment
  21. from Model.models import UnicomCombo, Store_Meal, Device_User, CouponCombo
  22. from Object.ResponseObject import ResponseObject
  23. from Object.TokenObject import TokenObject
  24. class AgentCustomerView(View):
  25. def get(self, request, *args, **kwargs):
  26. request.encoding = 'utf-8'
  27. operation = kwargs.get('operation')
  28. return self.validation(request.GET, request, operation)
  29. def post(self, request, *args, **kwargs):
  30. request.encoding = 'utf-8'
  31. operation = kwargs.get('operation')
  32. return self.validation(request.POST, request, operation)
  33. def delete(self, request, *args, **kwargs):
  34. request.encoding = 'utf-8'
  35. operation = kwargs.get('operation')
  36. delete = QueryDict(request.body)
  37. if not delete:
  38. delete = request.GET
  39. return self.validation(delete, request, operation)
  40. def put(self, request, *args, **kwargs):
  41. request.encoding = 'utf-8'
  42. operation = kwargs.get('operation')
  43. put = QueryDict(request.body)
  44. return self.validation(put, request, operation)
  45. def validation(self, request_dict, request, operation):
  46. AgentCustomerInfo.objects.filter()
  47. language = request_dict.get('language', 'en')
  48. response = ResponseObject(language, 'pc')
  49. if operation == 'getUnicomAndIcloud':
  50. return self.get_unicom_and_icloud(request_dict, response)
  51. elif operation == 'applyAgent':
  52. return self.apply_agent(request_dict, response)
  53. else:
  54. tko = TokenObject(
  55. request.META.get('HTTP_AUTHORIZATION'),
  56. returntpye='pc')
  57. if tko.code != 0:
  58. return response.json(tko.code)
  59. response.lang = tko.lang
  60. userID = tko.userID
  61. # 代理用户界面(代理顾客个人信息)
  62. if operation == 'getAgentInfo':
  63. return self.get_agent_info(userID, response)
  64. # 代理云存套餐
  65. elif operation == 'getAgentServicePackage':
  66. return self.get_agent_service_package(request_dict, response)
  67. elif operation == 'addAgentServicePackage':
  68. return self.add_agent_service_package(userID, request_dict, response)
  69. elif operation == 'updateAgentServicePackage':
  70. return self.update_agent_service_package(userID, request_dict, response)
  71. elif operation == 'delAgentServicePackage':
  72. return self.del_agent_service_package(request_dict, response)
  73. # 代理客户绑定套餐
  74. elif operation == 'getCustomerList':
  75. return self.get_customer_list(request_dict, response)
  76. elif operation == 'getCompanyNameList':#下拉框查询专用
  77. return self.get_company_name_list(request_dict, response)
  78. elif operation == 'getCustomerPackageList':
  79. return self.get_cumstomer_package_list(request_dict, response)
  80. elif operation == 'batchRebindCustomerPackage':
  81. return self.batch_rebind_customer_packages(userID, request_dict, response)
  82. elif operation == 'getAgentServicePackageList':
  83. return self.get_agent_service_package_list(response)
  84. elif operation == 'getAgentSettleOrders':
  85. return self.get_agent_settle_order(userID, request_dict, response)
  86. elif operation == 'getDataStatistics':
  87. return self.get_data_statistics(userID, response)
  88. # 代理商提现功能
  89. elif operation == 'getAgentAccountWithdraw':
  90. return self.get_agent_account_withdraw(userID, request_dict, response)
  91. elif operation == 'getCheckBalance':
  92. return self.get_check_balance(userID, response)
  93. elif operation == 'agentApplyWithdraw':
  94. return self.agent_apply_withdraw(userID, request_dict, response)
  95. elif operation == 'getWithdrawalReview':
  96. return self.get_withdrawal_review(request_dict, response)
  97. elif operation == 'updateWithdrawalReview':
  98. return self.update_withdrawal_review(userID, request_dict, response)
  99. else:
  100. return response.json(444, 'operation')
  101. @classmethod
  102. def get_unicom_and_icloud(cls, request_dict, response):
  103. """
  104. 查询云存储套餐和物联网卡套餐列表
  105. @param response: 响应对象
  106. @return: 包含套餐信息的响应
  107. """
  108. try:
  109. lang = request_dict.get('lang', 'cn')
  110. # 1. 优化查询 - 云存储套餐
  111. store_meals_qs = Store_Meal.objects.filter(
  112. ~Q(pay_type__in=[10, 11]),
  113. lang__lang=lang,
  114. is_show=0
  115. ).exclude(app_type=2)
  116. # 根据配置区分国内外套餐
  117. if CONFIG_INFO == CONFIG_CN:
  118. store_meals_qs = store_meals_qs.filter(is_ai=0, bucket__mold=0)
  119. else:
  120. store_meals_qs = store_meals_qs.filter(bucket__mold=1)
  121. # 一次性获取所有需要的字段和关联数据
  122. store_meals = store_meals_qs.annotate(
  123. title=F('lang__title'),
  124. content=F('lang__content'),
  125. new_title=F('lang__new_title'),
  126. discount_content=F('lang__discount_content'),
  127. store_day=F('bucket__storeDay'),
  128. bucket_name=F('bucket__bucket'),
  129. bucket_area=F('bucket__area')
  130. ).order_by('-pixel_level', '-is_ai').values(
  131. "id", "title", "content", "price", "day", "currency", "store_day",
  132. "new_title", "bucket_name", "bucket_area", "commodity_code", "commodity_type",
  133. "is_discounts", "virtual_price", "expire", "discount_price",
  134. "discount_content", "symbol", "cycle_config_id",
  135. 'pixel_level', 'is_ai', 'app_type'
  136. )
  137. # 2. 批量处理优惠券信息 - 避免N+1查询
  138. ios_meal_ids = [meal['id'] for meal in store_meals if meal.get('app_type') == 1]
  139. coupon_map = {}
  140. if ios_meal_ids:
  141. coupon_combos = CouponCombo.objects.filter(
  142. combo_id__in=ios_meal_ids
  143. ).values_list('combo_id', flat=True).distinct()
  144. coupon_map = {combo_id: True for combo_id in coupon_combos}
  145. # 3. 使用列表推导式构建套餐列表
  146. store_meal_list = []
  147. for meal in store_meals:
  148. # 构建基础名称
  149. name_parts = [meal['title'],
  150. f'{meal.get("symbol")}{meal["price"]}',
  151. f"({str(meal['expire'])}month+",
  152. '≥4K' if meal.get('pixel_level') == 1 else '<4K']
  153. # 添加AI标识
  154. if meal.get('is_ai') == 1:
  155. name_parts.append('+AI')
  156. # 处理iOS套餐
  157. if meal.get('app_type') == 1:
  158. name_parts.append('+ios')
  159. # 检查优惠券 - 使用预处理的映射
  160. if meal['id'] in coupon_map:
  161. name_parts.append('+discount')
  162. # 添加周期订阅标识
  163. if meal.get('cycle_config_id', 0) == 1:
  164. name_parts.append('+cycle')
  165. # 关闭括号并连接字符串
  166. name_parts.append(')')
  167. full_name = ''.join(name_parts)
  168. store_meal_list.append({
  169. 'id': meal['id'],
  170. 'name': full_name
  171. })
  172. # 4. 物联网卡套餐查询
  173. unicom_combo_list = list(
  174. UnicomCombo.objects.filter(
  175. is_show=1,
  176. is_del=False
  177. ).distinct().values('id', 'combo_name')
  178. )
  179. # 统一字段名
  180. for combo in unicom_combo_list:
  181. combo['name'] = combo.pop('combo_name')
  182. return response.json(0, {
  183. 'storeMeals': store_meal_list,
  184. 'unicomCombos': unicom_combo_list,
  185. })
  186. except Exception as e:
  187. LOGGER.error(f"get_unicom_and_icloud error: {str(e)}", exc_info=True)
  188. return response.json(500, 'Server error')
  189. def get_agent_info(self, userID, response):
  190. """
  191. 查询用户信息
  192. @param userID: userID
  193. @param response: 响应对象
  194. @return:
  195. """
  196. try:
  197. # 使用userID查询AgentCustomerInfo获取基本信息
  198. agent_info = AgentCustomerInfo.objects.filter(user_id=userID, status=1).first()
  199. if not agent_info:
  200. return response.json(444, {'error': '没有找到这个代理用户'})
  201. # userID查询用户电话
  202. device_user_qs = Device_User.objects.filter(userID=userID).first()
  203. # 代理客户ID(ac_id)查询AgentCustomerCard获取银行卡信息。
  204. card_details = AgentCustomerCard.objects.filter(ac_id=agent_info.id, status=1).first()
  205. # ac_id查询AgentCustomerPackage来找到关联的云服务套餐ID(cs_id)
  206. package_ids = AgentCustomerPackage.objects.filter(ac_id=agent_info.id).values_list('cs_id',
  207. flat=True)
  208. # cs_id查询AgentCloudServicePackage获取服务套餐详情。
  209. service_packages = AgentCloudServicePackage.objects.filter(id__in=package_ids, status=1).values()
  210. result = {
  211. 'agent_info': {
  212. 'ac_id': agent_info.id,
  213. 'company_name': agent_info.company_name,
  214. 'phone': device_user_qs.phone,
  215. 'created_time': agent_info.created_time,
  216. 'service_packages': list(service_packages),
  217. }
  218. }
  219. if card_details:
  220. # 获取银行卡号
  221. card_no = card_details.card_no
  222. # 检查银行卡号字符串长度,如果小于等于8,则返回"null"
  223. if len(card_no) <= 8:
  224. masked_card_no = "null"
  225. else:
  226. # 保留前四位和后四位,用"*"代替中间的数字
  227. masked_card_no = card_no[:4] + '*' * (len(card_no) - 8) + card_no[-4:]
  228. result['agent_info'].update({
  229. 'card_name': card_details.name,
  230. 'card_no': masked_card_no,
  231. 'card_address': card_details.card_address,
  232. })
  233. return response.json(0, result)
  234. except Exception as e:
  235. return response.json(500, {'error': str(e)})
  236. def get_agent_service_package(self, request_dict, response):
  237. """
  238. 查询所有代理云服务套餐
  239. @param request_dict: 请求参数
  240. @request_dict page: 页码
  241. @request_dict page_size: 查询分页数
  242. @param response: 响应对象
  243. @return:
  244. """
  245. page = int(request_dict.get('page', 1))
  246. page_size = int(request_dict.get('page_size', 10))
  247. try:
  248. # 查询所有有效的代理云服务套餐
  249. all_packages = AgentCloudServicePackage.objects.filter(status=1).order_by('type', '-created_time')
  250. # 创建分页对象
  251. paginator = Paginator(all_packages, page_size)
  252. # 获取请求页的数据
  253. packages_page = paginator.page(page)
  254. # 准备响应数据,转换查询集为列表形式
  255. agents_list = []
  256. for agent_info in packages_page:
  257. package_name = agent_info.package_id
  258. if agent_info.type == 1:
  259. store_meals = Store_Meal.objects.filter(id=agent_info.package_id).values('bucket__bucket').first()
  260. if store_meals:
  261. package_name = store_meals['bucket__bucket']
  262. else:
  263. unicom_combos = UnicomCombo.objects.filter(id=agent_info.package_id).first()
  264. if unicom_combos:
  265. package_name = unicom_combos.combo_name
  266. agents = {
  267. 'id': agent_info.id,
  268. 'service_name': agent_info.service_name,
  269. 'package_name': package_name,
  270. 'type': agent_info.type,
  271. 'profit_type': agent_info.profit_type,
  272. 'cost': agent_info.cost,
  273. 'profit': agent_info.profit,
  274. 'status': agent_info.status,
  275. 'created_time': agent_info.created_time
  276. }
  277. agents_list.append(agents)
  278. # 返回分页数据
  279. return response.json(0, {
  280. 'page': page,
  281. 'page_size': page_size,
  282. 'total': paginator.count,
  283. 'num_pages': paginator.num_pages,
  284. 'list': agents_list
  285. })
  286. except Exception as e:
  287. # 出错时返回错误信息
  288. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  289. def add_agent_service_package(self, userID, request_dict, response):
  290. """
  291. 添加代理云服务套餐
  292. @param request_dict: 请求参数
  293. @request_dict package_id: 代理服务id
  294. @request_dict service_name: 代理服务名称
  295. @request_dict package_type: 套餐类型 1:云存,2:4G
  296. @response_dict profit_type: 利润分配类型 1:固定值,2:百分比
  297. @response_dict cost: 成本
  298. @response_dict profit: 利润值
  299. @param response: 响应对象
  300. @return:
  301. """
  302. package_id = request_dict.get('package_id', None)
  303. service_name = request_dict.get('service_name', None)
  304. package_type = int(request_dict.get('package_type', 0)) # 默认为0,确保类型安全
  305. profit_type = int(request_dict.get('profit_type', 1)) # 默认值为1
  306. profit = request_dict.get('profit', 0)
  307. cost = request_dict.get('cost', 0)
  308. try:
  309. # 创建AgentCloudServicePackage实例并保存
  310. if not all([package_id, service_name]):
  311. return response.json(444)
  312. if package_type == 1:
  313. query_set = Store_Meal.objects.filter(is_show=0, id=package_id)
  314. elif package_type == 2:
  315. query_set = UnicomCombo.objects.filter(is_show=1, is_del=False, id=package_id)
  316. else:
  317. return response.json(444, 'error package_type')
  318. if not query_set.exists():
  319. return response.json(173)
  320. AgentCloudServicePackage.objects.create(
  321. service_name=service_name,
  322. package_id=package_id,
  323. type=package_type,
  324. profit_type=profit_type,
  325. profit=profit,
  326. status=1,
  327. cost=cost,
  328. created_by=userID,
  329. created_time=int(time.time()),
  330. updated_by=userID,
  331. updated_time=int(time.time())
  332. )
  333. return response.json(0)
  334. except Exception as e:
  335. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  336. def update_agent_service_package(self, userID, request_dict, response):
  337. """
  338. 更新代理云服务套餐
  339. @param request_dict: 请求参数
  340. @request_dict package_id: 代理服务id
  341. @request_dict service_name: 代理服务名称
  342. @response_dict profit_type: 利润分配类型 1:固定值,2:百分比
  343. @response_dict cost: 成本
  344. @response_dict profit: 利润值
  345. @param response: 响应对象
  346. @return:
  347. """
  348. id = request_dict.get('id', None)
  349. service_name = request_dict.get('service_name', None)
  350. profit_type = request_dict.get('profit_type', None)
  351. cost = request_dict.get('cost', None)
  352. profit = request_dict.get('profit', None)
  353. if not all([id, service_name, profit_type, cost, profit]):
  354. return response.json(444)
  355. try:
  356. ac_service_package = AgentCloudServicePackage.objects.get(pk=id)
  357. ac_service_package.service_name = service_name
  358. ac_service_package.profit_type = profit_type
  359. ac_service_package.cost = cost
  360. ac_service_package.profit = profit
  361. ac_service_package.updated_time = int(time.time())
  362. ac_service_package.updated_by = userID
  363. ac_service_package.save()
  364. return response.json(0)
  365. except AgentCloudServicePackage.DoesNotExist:
  366. return response.json(173)
  367. except Exception as e:
  368. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  369. def del_agent_service_package(self, request_dict, response):
  370. """
  371. 删除代理云服务套餐
  372. @param userID: 用户ID(执行删除操作的用户)
  373. @param request_dict: 请求参数
  374. @request_dict package_id: 代理服务id
  375. @param response: 响应对象
  376. @return:
  377. """
  378. id = request_dict.get('id', None)
  379. if not id:
  380. return response.json(444, 'Missing package_id')
  381. try:
  382. ac_service_package = AgentCloudServicePackage.objects.get(pk=id)
  383. # 假删除,否则查利润会出问题
  384. ac_service_package.status = 0
  385. ac_service_package.save()
  386. return response.json(0)
  387. except AgentCloudServicePackage.DoesNotExist:
  388. return response.json(173, 'Package does not exist.')
  389. except Exception as e:
  390. return response.json(500, {'error': str(e)})
  391. def get_customer_list(self, request_dict, response):
  392. """
  393. 查询代理商信息,并进行分页处理
  394. @param request_dict: 请求对象,用于接收分页参数
  395. @param response: 响应对象
  396. @return:
  397. """
  398. # 接收分页参数
  399. page = int(request_dict.get('page', 1))
  400. page_size = int(request_dict.get('page_size', 10))
  401. search_query = request_dict.get('search_query', '')
  402. user_id = request_dict.get('user_id', None)
  403. phone = request_dict.get('phone', None)
  404. userEmail = request_dict.get('userEmail', None)
  405. try:
  406. # 基础查询条件
  407. agent_infos_query = AgentCustomerInfo.objects.filter(status=1)
  408. # 精确查询条件
  409. if user_id:
  410. agent_infos_query = agent_infos_query.filter(user_id=user_id)
  411. # 获取所有符合条件的AgentCustomerInfo记录
  412. agent_infos = agent_infos_query.values('id', 'user_id', 'company_name').order_by('id')
  413. # 对结果进行分页
  414. paginator = Paginator(agent_infos, page_size)
  415. packages_page = paginator.page(page)
  416. # 准备最终的代理商列表
  417. agents_list = []
  418. for agent_info in packages_page:
  419. # 模糊查询
  420. if search_query:
  421. card_info_query = AgentCustomerCard.objects.filter(ac_id=agent_info['id'],
  422. name__icontains=search_query)
  423. if not card_info_query.exists() and search_query not in agent_info['company_name']:
  424. continue
  425. else:
  426. card_info_query = AgentCustomerCard.objects.filter(ac_id=agent_info['id'])
  427. # 获取卡信息
  428. card_info = card_info_query.values('name', 'card_no', 'card_address').first()
  429. # 获取用户信息,根据需要进行精确查询
  430. user_info_query = Device_User.objects.filter(userID=agent_info['user_id'])
  431. if phone:
  432. user_info_query = user_info_query.filter(phone=phone)
  433. if userEmail:
  434. user_info_query = user_info_query.filter(userEmail=userEmail)
  435. user_info = user_info_query.values('phone', 'userEmail').first()
  436. # 组合信息
  437. agent_record = {
  438. 'id': agent_info['id'],
  439. 'company_name': agent_info['company_name'],
  440. 'user_id': agent_info['user_id'],
  441. 'phone': user_info.get('phone') if user_info else None,
  442. 'userEmail': user_info.get('userEmail') if user_info else None,
  443. 'card_name': card_info.get('name') if card_info else None,
  444. 'card_no': card_info.get('card_no') if card_info else None,
  445. 'card_address': card_info.get('card_address') if card_info else None,
  446. }
  447. agents_list.append(agent_record)
  448. # 返回分页后的结果
  449. return response.json(0, {
  450. 'page': page,
  451. 'page_size': page_size,
  452. 'total': paginator.count,
  453. 'num_pages': paginator.num_pages,
  454. 'list': agents_list
  455. })
  456. except Exception as e:
  457. print(e)
  458. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  459. def get_cumstomer_package_list(self, request_dict, response):
  460. """
  461. 查询代理商服务套餐列表
  462. @param response: 响应对象
  463. @return:
  464. """
  465. ac_id = request_dict.get('id', None)
  466. try:
  467. if ac_id is None:
  468. return response.json(444, 'Missing ac_id')
  469. # ac_id查询AgentCustomerPackage来找到关联的云服务套餐ID(cs_id)
  470. package_ids = AgentCustomerPackage.objects.filter(ac_id=ac_id).values_list('cs_id', flat=True)
  471. # cs_id查询AgentCloudServicePackage获取服务套餐详情。
  472. service_packages = AgentCloudServicePackage.objects.filter(id__in=package_ids, status=1).values(
  473. 'id', 'service_name', 'type'
  474. )
  475. service_packages_list = list(service_packages)
  476. return response.json(0, {'service_packages': service_packages_list})
  477. except Exception as e:
  478. print(e)
  479. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  480. def batch_rebind_customer_packages(self, userID, request_dict, response):
  481. """
  482. 清空并重新绑定代理商服务套餐
  483. @param userID: 操作用户的ID
  484. @param request_dict: 请求参数,包含代理商ID和新的服务套餐ID列表
  485. @param response: 响应对象
  486. @return:
  487. """
  488. ac_id = request_dict.get('ac_id', None) # 代理客户ID
  489. new_cs_ids = json.loads(request_dict.get('cs_ids', '[]')) # 新的服务套餐ID列表
  490. if not ac_id:
  491. return response.json(444, 'Missing agent customer ID.')
  492. if not new_cs_ids:
  493. return response.json(444, 'Service package IDs are required.')
  494. try:
  495. # 删除该代理客户的所有现有绑定
  496. AgentCustomerPackage.objects.filter(ac_id=ac_id).delete()
  497. # 过滤出存在且状态为有效的套餐ID
  498. valid_new_cs_ids = AgentCloudServicePackage.objects.filter(id__in=new_cs_ids, status=1).values_list('id',
  499. flat=True)
  500. # 准备批量创建的数据
  501. packages_to_bind = [
  502. AgentCustomerPackage(
  503. ac_id=ac_id,
  504. cs_id=cs_id,
  505. created_by=userID,
  506. updated_by=userID,
  507. created_time=int(time.time()),
  508. updated_time=int(time.time())
  509. )
  510. for cs_id in valid_new_cs_ids
  511. ]
  512. # 批量创建新的绑定关系
  513. AgentCustomerPackage.objects.bulk_create(packages_to_bind)
  514. return response.json(0)
  515. except Exception as e:
  516. print(e)
  517. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  518. def get_agent_service_package_list(self, response):
  519. """
  520. 查询云服务套餐列表 id + service_name
  521. @param response: 响应对象
  522. @return:
  523. """
  524. try:
  525. # 查询所有有效的代理云服务套餐
  526. all_packages = AgentCloudServicePackage.objects.filter(status=1).order_by('-created_time').values('id',
  527. 'service_name')
  528. # 转换查询集为列表形式
  529. packages_list = list(all_packages)
  530. # 返回数据
  531. return response.json(0, {'packages': packages_list})
  532. except Exception as e:
  533. # 出错时返回错误信息
  534. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  535. def get_agent_settle_order(self, userID, request_dict, response):
  536. """
  537. 查询结算明细
  538. @param userID: userID
  539. @param request_dict: 请求参数
  540. @param request_dict status: 结算状态
  541. @param request_dict time: 年-季度 2023-1
  542. @param response: 响应对象
  543. @return:
  544. """
  545. status = request_dict.get('status', None)
  546. time_str = request_dict.get('time', None)
  547. package_type = request_dict.get('package_type', None)
  548. startTime = int(request_dict.get('start_time', 1))
  549. endTime = int(request_dict.get('end_time', 0))
  550. page = int(request_dict.get('page', 1)) # 默认为第一页
  551. page_size = int(request_dict.get('page_size', 10)) # 默认每页10条记录
  552. try:
  553. agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
  554. if agent_customer_info is None:
  555. agent_device_orders_qs = AgentDeviceOrder.objects.filter(is_del=False)
  556. else:
  557. ac_id = agent_customer_info.id
  558. agent_device_orders_qs = AgentDeviceOrder.objects.filter(ac_id=ac_id, is_del=False)
  559. if time_str:
  560. year, quarter = map(int, time_str.split('-'))
  561. start_month = 3 * (quarter - 1) + 1
  562. end_month = start_month + 2
  563. start_date = datetime(year, start_month, 1)
  564. end_date = datetime(year + 1, 1, 2) if end_month == 12 else datetime(year, end_month + 1, 1)
  565. start_time = int(start_date.timestamp())
  566. end_time = int(end_date.timestamp()) - 1
  567. agent_device_orders_qs = agent_device_orders_qs.filter(created_time__gte=start_time,
  568. created_time__lte=end_time)
  569. if startTime < endTime:
  570. agent_device_orders_qs = agent_device_orders_qs.filter(created_time__gte=startTime,
  571. created_time__lte=endTime)
  572. if package_type:
  573. csp_ids = list(
  574. AgentCloudServicePackage.objects.filter(type=int(package_type)).values_list('id', flat=True))
  575. agent_device_orders_qs = agent_device_orders_qs.filter(csp_id__in=csp_ids)
  576. if status is None:
  577. total_profit = agent_device_orders_qs.aggregate(Sum('profit'))['profit__sum'] or 0
  578. else:
  579. # 计算特定状态的device_orders总额
  580. full_profit = agent_device_orders_qs.filter(status=status).aggregate(Sum('profit'))[
  581. 'profit__sum'] or 0
  582. # 初始化total_profit
  583. total_profit = full_profit
  584. # 对于状态1和2,计算部分结算的利润
  585. if status in ["1", "2"]:
  586. partial_settled_profit = AgentDeviceOrderInstallment.objects.filter(
  587. ado_id__in=agent_device_orders_qs.filter(status=1).values_list('id', flat=True),
  588. status=2
  589. ).aggregate(total=Sum('amount'))['total'] or 0
  590. # 根据状态调整total_profit
  591. if status == "1":
  592. total_profit -= partial_settled_profit
  593. else: # 当status为"2"时,添加partial_settled_profit(根据业务逻辑,这可能需要调整)
  594. total_profit += partial_settled_profit
  595. agent_device_orders_qs = agent_device_orders_qs.filter(status=status)
  596. # 应用分页
  597. agent_device_orders_qs = agent_device_orders_qs.order_by('-created_time')
  598. paginator = Paginator(agent_device_orders_qs, page_size)
  599. current_page = paginator.get_page(page)
  600. orders = []
  601. for order in current_page:
  602. csp = AgentCloudServicePackage.objects.filter(id=order.csp_id).first()
  603. service_name = csp.service_name if csp else order.csp_id
  604. agent_customer_info = AgentCustomerInfo.objects.filter(id=order.ac_id).first()
  605. company_name = agent_customer_info.company_name if agent_customer_info else order.ac_id
  606. ado_id = order.id
  607. settled_profit = \
  608. AgentDeviceOrderInstallment.objects.filter(ado_id=ado_id, status=2).aggregate(Sum('amount'))[
  609. 'amount__sum'] or 0
  610. orders.append({
  611. 'id': order.id,
  612. 'company_name': company_name,
  613. 'serial_number': order.serial_number,
  614. 'status': order.status,
  615. 'service_name': service_name,
  616. 'profit_amount': order.profit_amount,
  617. 'profit': order.profit,
  618. 'settled_profit': settled_profit,
  619. 'settlement_time': order.settlement_time,
  620. 'remark': order.remark,
  621. 'created_time': order.created_time
  622. })
  623. response_data = {
  624. 'list': orders,
  625. 'total_profit': total_profit,
  626. 'total': paginator.count,
  627. 'page': current_page.number,
  628. 'page_size': page_size,
  629. 'num_pages': paginator.num_pages,
  630. }
  631. return response.json(0, response_data)
  632. except Exception as e:
  633. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  634. def get_agent_account_withdraw(self, userID, request_dict, response):
  635. """
  636. 查询提现明细
  637. @param userID: userID
  638. @param request_dict: 请求参数
  639. @param response: 响应对象
  640. @return:
  641. """
  642. agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
  643. if not agent_customer_info:
  644. return response.json(104, 'Agent customer not found')
  645. ac_id = agent_customer_info.id
  646. try:
  647. agent_account_withdraw_qs = AgentAccountWithdraw.objects.filter(ac_id=ac_id).order_by('-updated_time')
  648. page = int(request_dict.get('page', 1)) # 默认为第一页
  649. page_size = int(request_dict.get('page_size', 10)) # 默认每页10条记录
  650. # 应用分页
  651. paginator = Paginator(agent_account_withdraw_qs, page_size)
  652. current_page = paginator.get_page(page)
  653. withdraw_list = []
  654. for withdraw in current_page:
  655. agent_customer_card = AgentCustomerCard.objects.filter(ac_id=ac_id).first()
  656. card_no = agent_customer_card.card_no
  657. masked_card_no = card_no[:4] + '*' * (len(card_no) - 8) + card_no[-4:]
  658. withdraw_list.append({
  659. 'id': withdraw.id,
  660. 'amount': withdraw.amount,
  661. 'created_time': withdraw.created_time,
  662. 'card_no': masked_card_no,
  663. 'status': withdraw.status,
  664. 'remark': withdraw.remark,
  665. 'arrival_time': withdraw.arrival_time
  666. })
  667. response_data = {
  668. 'list': withdraw_list,
  669. 'total': paginator.count,
  670. 'page': current_page.number,
  671. 'page_size': page_size,
  672. 'num_pages': paginator.num_pages,
  673. }
  674. return response.json(0, response_data)
  675. except Exception as e:
  676. # 出错时返回错误信息
  677. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  678. def get_check_balance(self, userID, response):
  679. """
  680. 查询余额
  681. @param userID: userID
  682. @param response: 响应对象
  683. @return:
  684. """
  685. agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
  686. if not agent_customer_info:
  687. return response.json(104, 'Agent customer not found')
  688. ac_id = agent_customer_info.id
  689. try:
  690. # 计算冻结金额
  691. frozen_amount_qs = AgentAccountWithdraw.objects.filter(ac_id=ac_id, status__in=[1, 2, 3])
  692. frozen_amount = frozen_amount_qs.aggregate(total=Sum('amount'))['total'] or Decimal('0.00')
  693. # 计算余额:已结算 - (退款+已打款)
  694. incomes_qs = AgentAccount.objects.filter(ac_id=ac_id, status=1)
  695. expense_qs = AgentAccount.objects.filter(ac_id=ac_id, status__in=[2, 3])
  696. incomes_all = incomes_qs.aggregate(total=Sum('amount'))['total'] or Decimal('0.00')
  697. expense_all = expense_qs.aggregate(total=Sum('amount'))['total'] or Decimal('0.00')
  698. total_profit = incomes_all - expense_all
  699. # 可用余额 = 总余额 - 冻结金额
  700. available_balance = total_profit - frozen_amount
  701. # 构造返回数据
  702. balance_data = {
  703. 'frozen_amount': frozen_amount, # 冻结金额
  704. 'total_profit': total_profit, # 总余额
  705. 'available_balance': available_balance # 可用余额
  706. }
  707. return response.json(0, balance_data)
  708. except Exception as e:
  709. # 出错时返回错误信息
  710. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  711. def get_data_statistics(self, userID, response):
  712. """
  713. 首页总览
  714. @param userID: userID
  715. @param response: 响应对象
  716. @return:
  717. """
  718. agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
  719. if agent_customer_info is None:
  720. agent_device_orders_qs = AgentDeviceOrder.objects.filter(is_del=False)
  721. agent_device_qs = AgentDevice.objects.filter()
  722. else:
  723. ac_id = agent_customer_info.id
  724. agent_device_orders_qs = AgentDeviceOrder.objects.filter(ac_id=ac_id, is_del=False)
  725. agent_device_qs = AgentDevice.objects.filter(ac_id=ac_id)
  726. now = datetime.now()
  727. today_start = datetime(now.year, now.month, now.day)
  728. yesterday_start = today_start - timedelta(days=1)
  729. tomorrow_start = today_start + timedelta(days=1)
  730. try:
  731. # 计算AgentDeviceOrderInstallment表 结算金额
  732. partial_settled_profit = AgentDeviceOrderInstallment.objects.filter(
  733. ado_id__in=agent_device_orders_qs.filter(status=1).values_list('id', flat=True),
  734. status=2
  735. ).aggregate(total=Sum('amount'))['total'] or 0
  736. # 总利润
  737. total_profit_all = \
  738. agent_device_orders_qs.filter(status__in=[1, 2], is_del=False).aggregate(
  739. total=Sum('profit'))[
  740. 'total'] or Decimal('0.00')
  741. total_profit_no = \
  742. agent_device_orders_qs.filter(status=1, is_del=False).aggregate(total=Sum('profit'))[
  743. 'total'] or Decimal('0.00')
  744. total_profit_no = total_profit_no - partial_settled_profit
  745. total_profit_yes = \
  746. agent_device_orders_qs.filter(status=2, is_del=False).aggregate(total=Sum('profit'))[
  747. 'total'] or Decimal('0.00')
  748. total_profit_yes = total_profit_yes + partial_settled_profit
  749. # 总营业额
  750. profit_amount_all = agent_device_orders_qs.filter(status__in=[1, 2], is_del=False).aggregate(
  751. total=Sum('profit_amount'))['total'] or Decimal('0.00')
  752. # 今日总营业额
  753. profit_amount_today_all = agent_device_orders_qs.filter(
  754. status__in=[1, 2],
  755. is_del=False,
  756. created_time__gte=int(today_start.timestamp()),
  757. created_time__lt=int(tomorrow_start.timestamp())
  758. ).aggregate(total=Sum('profit_amount'))['total'] or Decimal('0.00')
  759. # 昨日总营业额
  760. profit_amount_yesterday_all = agent_device_orders_qs.filter(
  761. status__in=[1, 2],
  762. is_del=False,
  763. created_time__gte=int(yesterday_start.timestamp()),
  764. created_time__lt=int(today_start.timestamp())
  765. ).aggregate(total=Sum('profit_amount'))['total'] or Decimal('0.00')
  766. # 激活设备数
  767. active_device_count_today = agent_device_qs.filter(
  768. status=1,
  769. created_time__gte=int(today_start.timestamp()),
  770. created_time__lt=int(tomorrow_start.timestamp())
  771. ).count()
  772. active_device_count_yesterday = agent_device_qs.filter(
  773. status=1,
  774. created_time__gte=int(yesterday_start.timestamp()),
  775. created_time__lt=int(today_start.timestamp())
  776. ).count()
  777. # 总设备数
  778. active_device_count = agent_device_qs.filter(status=1).count()
  779. inactive_device_count = agent_device_qs.filter(status=0).count()
  780. return response.json(0, {
  781. 'total_profit_all': total_profit_all,
  782. 'total_profit_no': total_profit_no,
  783. 'total_profit_yes': total_profit_yes,
  784. 'profit_amount_all': profit_amount_all,
  785. 'profit_amount_today_all': profit_amount_today_all,
  786. 'profit_amount_yesterday_all': profit_amount_yesterday_all,
  787. 'active_device_count_today': active_device_count_today,
  788. 'active_device_count_yesterday': active_device_count_yesterday,
  789. 'active_device_count': active_device_count,
  790. 'inactive_device_count': inactive_device_count,
  791. 'all_device_count': active_device_count + inactive_device_count
  792. })
  793. except Exception as e:
  794. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  795. def agent_apply_withdraw(self, userID, request_dict, response):
  796. """
  797. 用户提现申请
  798. @param userID: userID
  799. @param request_dict: 请求参数
  800. @param request_dict amount: 金额
  801. @param response: 响应对象
  802. @return:
  803. """
  804. amount = Decimal(request_dict.get('amount', '0.00'))
  805. if amount == Decimal('0.00'):
  806. return response.json(444)
  807. agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
  808. if not agent_customer_info:
  809. return response.json(104, 'Agent customer not found')
  810. ac_id = agent_customer_info.id
  811. try:
  812. # 计算余额:已结算 - (退款+已打款)
  813. incomes_qs = AgentAccount.objects.filter(ac_id=ac_id, status=1)
  814. expense_qs = AgentAccount.objects.filter(ac_id=ac_id, status__in=[2, 3])
  815. incomes_all = incomes_qs.aggregate(total=Sum('amount'))['total'] or Decimal('0.00')
  816. expense_all = expense_qs.aggregate(total=Sum('amount'))['total'] or Decimal('0.00')
  817. total_profit = incomes_all - expense_all
  818. # 冻结余额
  819. frozen_amount_qs = AgentAccountWithdraw.objects.filter(ac_id=ac_id, status__in=[1, 2, 3])
  820. frozen_amount = frozen_amount_qs.aggregate(total=Sum('amount'))['total'] or Decimal('0.00')
  821. # 可提现余额 = 总余额 - 冻结金额
  822. available_balance = total_profit - frozen_amount
  823. if amount < Decimal('1000.00'):
  824. return response.json(10, '每次提现最少为1000元')
  825. if amount > available_balance:
  826. return response.json(10, '余额不足,无法提现')
  827. # 提交提现申请
  828. acc = AgentCustomerCard.objects.filter(ac_id=ac_id).first()
  829. AgentAccountWithdraw.objects.create(ac_id=ac_id, status=1, card_id=acc.id, amount=amount,
  830. created_time=int(time.time()), updated_time=int(time.time()))
  831. return response.json(0)
  832. except Exception as e:
  833. print(e)
  834. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  835. def get_withdrawal_review(self, request_dict, response):
  836. """
  837. 后台用户提现申请审核列表
  838. @param request_dict: 请求参数
  839. @param request_dict company_name: 公司名称
  840. @param request_dict status: 审核状态
  841. @param response: 响应对象
  842. @return:
  843. """
  844. company_name = request_dict.get('company_name', None)
  845. status = request_dict.get('status', None)
  846. page = int(request_dict.get('page', 1)) # 默认为第一页
  847. page_size = int(request_dict.get('page_size', 10)) # 默认每页10条记录
  848. try:
  849. agent_account_withdraw_qs = AgentAccountWithdraw.objects.filter().order_by('updated_time')
  850. if company_name:
  851. agent_customer_info = AgentCustomerInfo.objects.filter(company_name=company_name).first()
  852. ac_id = agent_customer_info.id
  853. agent_account_withdraw_qs = agent_account_withdraw_qs.filter(ac_id=ac_id)
  854. if status:
  855. agent_account_withdraw_qs = agent_account_withdraw_qs.filter(status=status)
  856. # 提现id 公司名 审核状态 提现金额 余额
  857. paginator = Paginator(agent_account_withdraw_qs, page_size)
  858. current_page = paginator.get_page(page)
  859. review_list = []
  860. for review in current_page:
  861. ac_id = review.ac_id
  862. agent_customer_info = AgentCustomerInfo.objects.filter(id=ac_id).first()
  863. company_name = agent_customer_info.company_name
  864. review_list.append({
  865. "id": review.id,
  866. "company_name": company_name,
  867. "status": review.status,
  868. "amount": review.amount,
  869. "remark": review.remark,
  870. })
  871. response_data = {
  872. 'list': review_list,
  873. 'total': paginator.count,
  874. 'page': current_page.number,
  875. 'page_size': page_size,
  876. 'num_pages': paginator.num_pages,
  877. }
  878. return response.json(0, response_data)
  879. except Exception as e:
  880. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  881. def update_withdrawal_review(self, userID, request_dict, response):
  882. """
  883. 后台提现审核
  884. @param request_dict: 请求参数
  885. @param request_dict id: 提现单id
  886. @param request_dict status: 提现单状态
  887. @param request_dict remark: 提现单备注
  888. @param response: 响应对象
  889. @return:
  890. """
  891. id = request_dict.get('id', None)
  892. status = request_dict.get('status', None)
  893. remark = request_dict.get('remark', "")
  894. if not all([id, status]):
  895. return response.json(444)
  896. try:
  897. agent_account_withdraw = AgentAccountWithdraw.objects.get(pk=id)
  898. agent_account_withdraw.status = status
  899. agent_account_withdraw.remark = remark
  900. agent_account_withdraw.save()
  901. if int(status) == 4:
  902. AgentAccount.objects.create(ac_id=agent_account_withdraw.ac_id,
  903. amount=agent_account_withdraw.amount,
  904. status=3,
  905. created_time=int(time.time()),
  906. updated_time=int(time.time()),
  907. remark=f"{userID}修改为已提现")
  908. return response.json(0)
  909. except Exception as e:
  910. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  911. def apply_agent(self, request_dict, response):
  912. """
  913. 代理申请
  914. @param request_dict: 请求参数
  915. @param request_dict name: 名字
  916. @param request_dict phone: 电话
  917. @param request_dict regin: 地区
  918. @param request_dict remark: 备注
  919. @param response: 响应对象
  920. @return:
  921. """
  922. name = request_dict.get('name', None)
  923. phone = request_dict.get('phone', None)
  924. regin = request_dict.get('regin', None)
  925. remark = request_dict.get('remark', "")
  926. if not all([name, phone, regin]):
  927. return response.json(444)
  928. # 去除非数字字符
  929. clean_phone = re.sub(r'\D', '', phone)
  930. if ApplyAgent.objects.filter(phone=clean_phone).exists():
  931. return response.json(174, 'Phone number already exists')
  932. ApplyAgent.objects.create(name=name, phone=clean_phone, regin=regin, remark=remark)
  933. return response.json(0, '申请已提交')
  934. def get_company_name_list(self, request_dict, response):
  935. """下拉框用于查询代理公司信息,避免分页"""
  936. try:
  937. agent_infos_query = (AgentCustomerInfo.objects.filter(status=1)
  938. .values("id", "company_name")
  939. .order_by('-id'))
  940. data = list(agent_infos_query)
  941. return response.json(0, data)
  942. except Exception as e:
  943. error_msg: str = f'查询代理商数据异常: {str(e)}'
  944. error_line: int = e.__traceback__.tb_lineno
  945. LOGGER.error(f'{error_msg} 行号: {error_line}')
  946. return response.json(500)