AgentCustomerController.py 46 KB

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