123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- # -*- encoding: utf-8 -*-
- """
- @File : AgentDeviceController.py
- @Time : 2024/3/8 13:55
- @Author : stephen
- @Email : zhangdongming@asj6.wecom.work
- @Software: PyCharm
- """
- import os
- import csv
- import time
- from datetime import datetime
- from dateutil.relativedelta import relativedelta
- from collections import defaultdict
- from decimal import Decimal
- import traceback
- import threading
- from django.db import transaction
- from django.http import QueryDict
- from django.views import View
- from django.core.paginator import Paginator
- from AgentModel.models import AgentCustomerInfo, AgentDeviceOrder, AgentDevice, AgentCloudServicePackage
- from Model.models import DeviceTypeModel
- from Object.ResponseObject import ResponseObject
- from Ansjer.config import LOGGER
- from Object.TokenObject import TokenObject
- class AgentDeviceView(View):
- def get(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- return self.validation(request.GET, request, operation)
- def post(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- return self.validation(request.POST, request, operation)
- def delete(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- delete = QueryDict(request.body)
- if not delete:
- delete = request.GET
- return self.validation(delete, request, operation)
- def put(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- put = QueryDict(request.body)
- return self.validation(put, request, operation)
- def validation(self, request_dict, request, operation):
- language = request_dict.get('language', 'en')
- response = ResponseObject(language, 'pc')
- # 订单结算界面
- if operation == 'XXXXX':
- pass
- else:
- tko = TokenObject(
- request.META.get('HTTP_AUTHORIZATION'),
- returntpye='pc')
- if tko.code != 0:
- return response.json(tko.code)
- response.lang = tko.lang
- userID = tko.userID
- if operation == 'getAgentDevice':
- return self.get_agent_device(userID, request_dict, response)
- elif operation == 'getAgentDeviceOrder':
- return self.get_agent_device_order(userID, request_dict, response)
- elif operation == 'batchBandDevice':
- return self.batch_band_device(userID, request, request_dict, response)
- else:
- return response.json(444, 'operation')
- def get_agent_device(self, userID, request_dict, response):
- """
- 查询设备明细
- @param userID: userID
- @param request_dict: 请求参数
- @param request_dict ac_id: 代理商id
- @param request_dict device_name: 设备名字
- @param request_dict status: 设备类型
- @param request_dict serial_number: 设备9位序列号
- @param response: 响应对象
- @return:
- """
- device_name = request_dict.get('device_name', None)
- status = request_dict.get('status', None)
- serial_number = request_dict.get('serial_number', None)
- page = int(request_dict.get('page', 1)) # 默认为第一页
- page_size = int(request_dict.get('page_size', 10)) # 默认每页10条记录
- agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
- if agent_customer_info is None:
- return response.json(104, 'Agent customer not found')
- ac_id = agent_customer_info.id
- try:
- agent_device_qs = AgentDevice.objects.filter(ac_id=ac_id).order_by('ac_id', '-created_time')
- if device_name:
- # 根据device_name查询对应的type值
- device_types = list(DeviceTypeModel.objects.filter(name=device_name).values_list('type', flat=True))
- agent_device_qs = agent_device_qs.filter(type__in=device_types)
- if status:
- agent_device_qs = agent_device_qs.filter(status=status)
- if serial_number:
- agent_device_qs = agent_device_qs.filter(serial_number=serial_number)
- # 应用分页
- paginator = Paginator(agent_device_qs, page_size)
- current_page = paginator.get_page(page)
- # 构造返回列表
- device_list = []
- for device in current_page:
- device_type = DeviceTypeModel.objects.filter(type=device.type).first()
- device_name = device_type.name if device_type else device.type
- device_list.append({
- 'id': device.id,
- 'ac_id': device.ac_id,
- 'status': device.status,
- 'serial_number': device.serial_number,
- 'device_name': device_name,
- 'at_time': device.at_time,
- })
- # 包含分页信息的响应
- response_data = {
- 'list': device_list,
- 'total': paginator.count,
- 'page': current_page.number,
- 'page_size': page_size,
- 'num_pages': paginator.num_pages,
- }
- return response.json(0, response_data)
- except Exception as e:
- print(e)
- return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
- def calculate_profit_or_revenue(self, agent_device_orders, package_details, time_unit, metric_type, start_time, end_time):
- """
- 计算利润或者营业额
- @param agent_device_orders: 代理设备订单
- @param package_details: 代理套餐详情
- @param time_unit: 时间单位
- @param metric_type: 利润或者营业额
- @param start_time: 开始时间
- @param end_time: 结束时间
- @return:
- """
- summary = defaultdict(lambda: {"云存": Decimal('0.00'), "4G": Decimal('0.00'), "all": Decimal('0.00')})
- time_format = {
- "month": "%Y-%m",
- "year": "%Y",
- "quarter": lambda x: f"{x.year}年{(x.month - 1) // 3 + 1}季度"
- }
- for order in agent_device_orders:
- package = package_details.get(order.csp_id)
- if not package:
- continue
- # 根据利润类型计算利润或者直接使用营业额
- if metric_type == 1: # 利润
- profit = order.profit
- else: # 营业额
- profit = order.profit_amount
- # 区分云服务 + 4G套餐并加入 summary
- service_type = "云存" if package.type == 1 else "4G"
- time_key = datetime.fromtimestamp(order.created_time).strftime(
- time_format[time_unit]) if time_unit != "quarter" else time_format[time_unit](
- datetime.fromtimestamp(order.created_time))
- summary[time_key][service_type] += profit
- summary[time_key]["all"] += profit
- # 补全时间段内所有可能的时间单位
- current_time = start_time
- end_time += relativedelta(days=1) # 包括结束日期
- while current_time < end_time:
- time_key = current_time.strftime(time_format[time_unit]) if time_unit != "quarter" else time_format[
- time_unit](current_time)
- if time_key not in summary:
- summary[time_key] = {"云存": Decimal('0.00'), "4G": Decimal('0.00'), "all": Decimal('0.00')}
- current_time += relativedelta(months=1) if time_unit == "month" else relativedelta(
- years=1) if time_unit == "year" else relativedelta(months=3)
- return [{"time": time, **data} for time, data in sorted(summary.items())]
- def get_agent_device_order(self, userID, request_dict, response):
- """
- 查询设备订单明细
- @param userID: userID
- @param request_dict: 请求参数
- @param request_dict startTime: 开始时间
- @param request_dict endTime: 结束时间
- @param request_dict timeUnit: 时间单位
- @param request_dict metric_type: 利润或者营业额
- @param response: 响应对象
- @return:
- """
- try:
- startTime = int(request_dict.get('startTime', 1704038400))
- endTime = int(request_dict.get('endTime', 1732982400))
- timeUnit = request_dict.get('timeUnit', 'month')
- metric_type = int(request_dict.get('metric_type', 0))
- agent_customer_info = AgentCustomerInfo.objects.filter(user_id=userID).first()
- if not agent_customer_info:
- return response.json(104, 'Agent customer not found')
- agent_device_orders = AgentDeviceOrder.objects.filter(
- ac_id=agent_customer_info.id, created_time__gte=startTime, created_time__lte=endTime, status__in=[1, 2]
- )
-
- # 获取代理套餐包id
- package_ids = agent_device_orders.values_list('csp_id', flat=True).distinct()
- package_details = {pkg.id: pkg for pkg in AgentCloudServicePackage.objects.filter(id__in=package_ids)}
- start_time = datetime.fromtimestamp(startTime)
- end_time = datetime.fromtimestamp(endTime)
- result = self.calculate_profit_or_revenue(agent_device_orders, package_details, timeUnit, metric_type,
- start_time, end_time)
- total_4G = Decimal('0.00')
- total_cloud = Decimal('0.00')
- # 遍历result列表来累加4G和云存的值
- for item in result:
- total_4G = item['4G'] + total_4G
- total_cloud = item['云存'] + total_cloud
- response_data = {
- "list": result,
- "total_4G": total_4G, # 4G的总和
- "total_云存": total_cloud, # 云存的总和
- }
- return response.json(0, response_data)
- except Exception as e:
- error_msg = f"error_line:{traceback.format_exc()}, error_msg:{str(e)}"
- return response.json(500, error_msg)
- def agent_devices_from_csv(self, ac_id, device_type, userID, file_path):
- """
- 异步批量绑定设备
- """
- try:
- with open(file_path, 'r') as file:
- reader = csv.DictReader(file)
- devices_to_create = []
- existing_serial_numbers = set(AgentDevice.objects.values_list('serial_number', flat=True))
- for row in reader:
- serial_number = row.get('serial_number')
- if serial_number not in existing_serial_numbers:
- device = AgentDevice(
- ac_id=ac_id,
- serial_number=serial_number,
- type=device_type,
- status=0,
- created_time=int(time.time()),
- created_by=userID,
- updated_time=int(time.time()),
- updated_by=userID
- )
- devices_to_create.append(device)
- # 使用Django的bulk_create来批量创建对象
- if devices_to_create:
- with transaction.atomic():
- AgentDevice.objects.bulk_create(devices_to_create, batch_size=200)
- # 删除文件
- os.remove(file_path)
- except Exception as e:
- LOGGER.info('errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
- def batch_band_device(self, userID, request, request_dict, response):
- """
- 批量绑定设备
- @param ac_id: ac_id 代理商id
- @param userID: userID
- @param csv_file_path: 文件路径
- @param response: 响应对象
- @return:
- """
- ac_id = request_dict.get('ac_id', None)
- device_name = request_dict.get('device_name', None)
- csv_file = request.FILES['file']
- upload_dir = os.path.join('static', 'uploaded_files')
- if not all([ac_id, device_name]):
- return response.json(444)
- try:
- device_type_dict = DeviceTypeModel.objects.filter(name=device_name).values('type').first()
- device_type = device_type_dict['type']
- if not os.path.exists(upload_dir):
- os.makedirs(upload_dir)
- file_path = os.path.join(upload_dir, csv_file.name)
- with open(file_path, 'wb+') as destination:
- for chunk in csv_file.chunks():
- destination.write(chunk)
- # 创建并启动线程来异步执行任务
- thread = threading.Thread(target=self.agent_devices_from_csv, args=(ac_id, device_type, userID, file_path))
- thread.start()
- return response.json(0)
- except Exception as e:
- print(e)
- return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
|