215 lines
8.2 KiB
Python
215 lines
8.2 KiB
Python
|
|
import requests
|
|||
|
|
import logging
|
|||
|
|
import time
|
|||
|
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|||
|
|
from rest_framework.response import Response
|
|||
|
|
from rest_framework.views import APIView
|
|||
|
|
from collections import defaultdict
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
from .models import ScannedCode
|
|||
|
|
from .serializers import ScannedCodeSerializer
|
|||
|
|
|
|||
|
|
# Константы API URL и креденшелы
|
|||
|
|
LOGIN_URL_ASPU = "http://192.168.254.10:3428/api/login"
|
|||
|
|
API_URL_ASPU_MANAGEMENT = "http://192.168.254.10:3428/api/Management/"
|
|||
|
|
API_URL_MANAGEMENT_DEVIN = "http://192.168.254.20:3428/api/Management/"
|
|||
|
|
API_URL_MANAGEMENT_JR = "http://192.168.254.30:3428/api/Management/"
|
|||
|
|
API_URL_MANAGEMENT_5L = "http://192.168.254.40:3428/api/Management/"
|
|||
|
|
API_URL_MANAGEMENT_19L = "http://192.168.254.50:3428/api/Management/"
|
|||
|
|
|
|||
|
|
API_URL_ASPU_MASSAGE_LIST_SIPA = "http://192.168.254.10:3428/api/Messages/"
|
|||
|
|
API_URL_ASPU_MASSAGE_LIST_DEVIN = "http://192.168.254.20:3428/api/Messages/"
|
|||
|
|
API_URL_ASPU_MASSAGE_LIST_JR = "http://192.168.254.30:3428/api/Messages/"
|
|||
|
|
API_URL_ASPU_MASSAGE_LIST_5L = "http://192.168.254.40:3428/api/Messages/"
|
|||
|
|
API_URL_ASPU_MASSAGE_LIST_19L = "http://192.168.254.50:3428/api/Messages/"
|
|||
|
|
|
|||
|
|
USERNAME = "superuser"
|
|||
|
|
PASSWORD = "Superuser1105"
|
|||
|
|
|
|||
|
|
# Глобальные переменные для хранения токена
|
|||
|
|
token_cache = {"token": None, "timestamp": 0}
|
|||
|
|
TOKEN_LIFETIME = 1440 * 60 # 24 часа в секундах
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_new_token(url):
|
|||
|
|
"""Получение нового токена с кешированием."""
|
|||
|
|
global token_cache
|
|||
|
|
current_time = time.time()
|
|||
|
|
|
|||
|
|
if token_cache["token"] and (current_time - token_cache["timestamp"] < TOKEN_LIFETIME):
|
|||
|
|
return token_cache["token"]
|
|||
|
|
|
|||
|
|
payload = {"UserName": USERNAME, "Password": PASSWORD}
|
|||
|
|
try:
|
|||
|
|
response = requests.post(url, json=payload, timeout=5)
|
|||
|
|
response_data = response.json()
|
|||
|
|
|
|||
|
|
if response.status_code == 200 and response_data.get("IsSuccess"):
|
|||
|
|
token_cache["token"] = response_data["Value"]["Token"]
|
|||
|
|
token_cache["timestamp"] = current_time
|
|||
|
|
return token_cache["token"]
|
|||
|
|
|
|||
|
|
logging.error(f"Ошибка получения токена: {response_data}")
|
|||
|
|
return None
|
|||
|
|
except requests.RequestException as e:
|
|||
|
|
logging.error(f"Ошибка сети при получении токена: {str(e)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def request_to_api(url, token, payload=None, timeout=10):
|
|||
|
|
"""Отправка запроса к API."""
|
|||
|
|
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
response = requests.post(url, json=payload or {}, headers=headers, timeout=timeout)
|
|||
|
|
response.raise_for_status()
|
|||
|
|
return response.json()
|
|||
|
|
except requests.Timeout:
|
|||
|
|
logging.error(f"Тайм-аут при запросе {url}")
|
|||
|
|
except requests.RequestException as e:
|
|||
|
|
logging.error(f"Ошибка запроса {url}: {str(e)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def extract_product_id(text):
|
|||
|
|
"""Функция извлечения идентификатора продукта из текста."""
|
|||
|
|
import re
|
|||
|
|
match = re.search(r'Product\s*ID:\s*(\d+)', text)
|
|||
|
|
return match.group(1) if match else None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def create_response(status, message=None, data=None, status_code=200):
|
|||
|
|
"""Создание стандартного ответа API."""
|
|||
|
|
return Response({
|
|||
|
|
"status": status,
|
|||
|
|
"message": message,
|
|||
|
|
"data": data
|
|||
|
|
}, status=status_code)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class GetManagementAPIView(APIView):
|
|||
|
|
"""Получение данных управления и сообщений с различных источников."""
|
|||
|
|
|
|||
|
|
def get(self, request):
|
|||
|
|
token = get_new_token(LOGIN_URL_ASPU)
|
|||
|
|
if not token:
|
|||
|
|
return create_response("Error", message="Failed to get token", status_code=500)
|
|||
|
|
|
|||
|
|
management_urls = {
|
|||
|
|
"Sipa": API_URL_ASPU_MANAGEMENT,
|
|||
|
|
"Devin": API_URL_MANAGEMENT_DEVIN,
|
|||
|
|
"JR": API_URL_MANAGEMENT_JR,
|
|||
|
|
"5L": API_URL_MANAGEMENT_5L,
|
|||
|
|
"19L": API_URL_MANAGEMENT_19L
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
message_urls = {
|
|||
|
|
"Sipa": API_URL_ASPU_MASSAGE_LIST_SIPA,
|
|||
|
|
"Devin": API_URL_ASPU_MASSAGE_LIST_DEVIN,
|
|||
|
|
"JR": API_URL_ASPU_MASSAGE_LIST_JR,
|
|||
|
|
"5L": API_URL_ASPU_MASSAGE_LIST_5L,
|
|||
|
|
"19L": API_URL_ASPU_MASSAGE_LIST_19L
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
message_payload = {
|
|||
|
|
"skip": 1,
|
|||
|
|
"take": 50,
|
|||
|
|
"includes": [],
|
|||
|
|
"sort": [{"field": "Time", "dir": "desc"}],
|
|||
|
|
"filter": {"filters": [], "logic": "and"}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Используем defaultdict, чтобы избежать KeyError
|
|||
|
|
all_data = defaultdict(lambda: {
|
|||
|
|
"Name": "",
|
|||
|
|
"ShortName": "",
|
|||
|
|
"BatchName": "",
|
|||
|
|
"Stats": [],
|
|||
|
|
"Sources": [],
|
|||
|
|
"Gtin": "",
|
|||
|
|
"GroupType": "",
|
|||
|
|
"Quantity": 0,
|
|||
|
|
"Messages": []
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
def process_management_response(key, response_data):
|
|||
|
|
"""Обработка данных управления."""
|
|||
|
|
if not response_data or "Value" not in response_data:
|
|||
|
|
logging.error(f"Некорректный ответ от {key}: {response_data}")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
value_data = response_data["Value"]
|
|||
|
|
batch_name = value_data.get("BatchName", "")
|
|||
|
|
|
|||
|
|
for product in value_data.get("ProductTypes", []):
|
|||
|
|
product_id = product.get("Id")
|
|||
|
|
if not product_id:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
all_data[product_id].update({
|
|||
|
|
"Name": product.get("Name", ""),
|
|||
|
|
"ShortName": product.get("ShortName", ""),
|
|||
|
|
"BatchName": batch_name,
|
|||
|
|
"Gtin": product.get("Gtin", ""),
|
|||
|
|
"GroupType": product.get("GroupType", ""),
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
all_data[product_id]["Stats"].extend(product.get("Stats", []))
|
|||
|
|
all_data[product_id]["Sources"].append(key)
|
|||
|
|
|
|||
|
|
if product.get("GroupType") == "Pallet":
|
|||
|
|
all_data[product_id]["Quantity"] = sum(
|
|||
|
|
stat["Value"] for stat in product.get("Stats", []) if stat.get("Type") == "Validated"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def process_message_response(key, response_data):
|
|||
|
|
"""Обработка сообщений."""
|
|||
|
|
if not response_data or "Value" not in response_data:
|
|||
|
|
logging.error(f"Некорректный ответ от {key}: {response_data}")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
for msg in response_data["Value"]:
|
|||
|
|
if "Text" not in msg:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
message = {
|
|||
|
|
"Id": msg["Id"],
|
|||
|
|
"Time": msg["Time"],
|
|||
|
|
"Type": msg["Type"],
|
|||
|
|
"Text": msg["Text"]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Добавляем в общий список сообщений
|
|||
|
|
for product_id in all_data:
|
|||
|
|
all_data[product_id]["Messages"].append(message)
|
|||
|
|
|
|||
|
|
with ThreadPoolExecutor(max_workers=10) as executor:
|
|||
|
|
futures = {
|
|||
|
|
executor.submit(request_to_api, url, token, timeout=2): (key, "management")
|
|||
|
|
for key, url in management_urls.items()
|
|||
|
|
}
|
|||
|
|
futures.update({
|
|||
|
|
executor.submit(request_to_api, url, token, payload=message_payload, timeout=2): (key, "messages")
|
|||
|
|
for key, url in message_urls.items()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
for future in as_completed(futures):
|
|||
|
|
key, request_type = futures[future]
|
|||
|
|
try:
|
|||
|
|
response_data = future.result()
|
|||
|
|
|
|||
|
|
if request_type == "management":
|
|||
|
|
process_management_response(key, response_data)
|
|||
|
|
elif request_type == "messages":
|
|||
|
|
process_message_response(key, response_data)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logging.error(f"Ошибка обработки {key}: {str(e)}")
|
|||
|
|
|
|||
|
|
logging.info(f"Отправляем ответ с {len(all_data)} объектами управления")
|
|||
|
|
|
|||
|
|
return create_response("OK", data=dict(all_data)) if all_data else create_response(
|
|||
|
|
"Error", message="No data found", status_code=404
|
|||
|
|
)
|