220 lines
11 KiB
Python
220 lines
11 KiB
Python
"""
|
||
Сервисы (бизнес-логика)
|
||
"""
|
||
import tempfile
|
||
import os
|
||
from typing import Dict, Type
|
||
|
||
from core.models import UploadRequest, UploadResult, DataRequest, DataResult
|
||
from core.ports import ParserPort, StoragePort
|
||
|
||
|
||
# Глобальный словарь парсеров
|
||
PARSERS: Dict[str, Type[ParserPort]] = {}
|
||
|
||
|
||
def get_parser(report_type: str) -> ParserPort:
|
||
"""Получение парсера по типу отчета"""
|
||
if report_type not in PARSERS:
|
||
available_parsers = list(PARSERS.keys())
|
||
raise ValueError(f"Неизвестный тип отчета '{report_type}'. Доступные типы: {available_parsers}")
|
||
|
||
return PARSERS[report_type]()
|
||
|
||
|
||
class ReportService:
|
||
"""Сервис для работы с отчетами (только S3)"""
|
||
|
||
def __init__(self, storage: StoragePort):
|
||
self.storage = storage
|
||
|
||
def upload_report(self, request: UploadRequest) -> UploadResult:
|
||
"""Загрузка отчета"""
|
||
try:
|
||
# Получаем парсер для данного типа отчета
|
||
parser = get_parser(request.report_type)
|
||
|
||
# Сохраняем файл во временную директорию
|
||
suff = "." + str(request.file_name.split('.')[-1])
|
||
with tempfile.NamedTemporaryFile(delete=False, suffix=suff) as temp_file:
|
||
temp_file.write(request.file_content)
|
||
temp_file_path = temp_file.name
|
||
|
||
try:
|
||
# Парсим файл
|
||
parse_params = request.parse_params or {}
|
||
parse_result = parser.parse(temp_file_path, parse_params)
|
||
|
||
# Генерируем object_id
|
||
object_id = f"nin_excel_data_{request.report_type}"
|
||
|
||
# Удаляем старый объект, если он существует и хранилище доступно
|
||
if self.storage.object_exists(object_id):
|
||
self.storage.delete_object(object_id)
|
||
print(f"Старый объект удален: {object_id}")
|
||
|
||
# Сохраняем в хранилище
|
||
if self.storage.save_dataframe(parse_result, object_id):
|
||
return UploadResult(
|
||
success=True,
|
||
message="Отчет успешно загружен",
|
||
object_id=object_id
|
||
)
|
||
else:
|
||
return UploadResult(
|
||
success=False,
|
||
message="Ошибка при сохранении в хранилище. Возможно, MinIO недоступен."
|
||
)
|
||
|
||
finally:
|
||
# Удаляем временный файл
|
||
os.unlink(temp_file_path)
|
||
|
||
except Exception as e:
|
||
return UploadResult(
|
||
success=False,
|
||
message=f"Ошибка при обработке отчета: {str(e)}"
|
||
)
|
||
|
||
def get_data(self, request: DataRequest) -> DataResult:
|
||
"""Получение данных из отчета"""
|
||
try:
|
||
# Генерируем object_id
|
||
object_id = f"nin_excel_data_{request.report_type}"
|
||
|
||
# Проверяем существование объекта
|
||
if not self.storage.object_exists(object_id):
|
||
return DataResult(
|
||
success=False,
|
||
message=f"Отчет типа '{request.report_type}' не найден. Возможно, MinIO недоступен или отчет не был загружен."
|
||
)
|
||
|
||
# Загружаем данные из хранилища
|
||
loaded_data = self.storage.load_dataframe(object_id)
|
||
if loaded_data is None:
|
||
return DataResult(
|
||
success=False,
|
||
message="Ошибка при загрузке данных из хранилища. Возможно, MinIO недоступен."
|
||
)
|
||
|
||
# Получаем парсер
|
||
parser = get_parser(request.report_type)
|
||
|
||
# Устанавливаем данные в парсер для использования в геттерах
|
||
parser.df = loaded_data
|
||
print(f"🔍 DEBUG: ReportService.get_data - установлены данные в парсер {request.report_type}")
|
||
|
||
# Проверяем тип загруженных данных
|
||
if hasattr(loaded_data, 'shape'):
|
||
# Это DataFrame
|
||
print(f"🔍 DEBUG: DataFrame shape: {loaded_data.shape}")
|
||
print(f"🔍 DEBUG: DataFrame columns: {list(loaded_data.columns) if not loaded_data.empty else 'Empty'}")
|
||
elif isinstance(loaded_data, dict):
|
||
# Это словарь (для парсера ПМ)
|
||
print(f"🔍 DEBUG: Словарь с ключами: {list(loaded_data.keys())}")
|
||
else:
|
||
print(f"🔍 DEBUG: Неизвестный тип данных: {type(loaded_data)}")
|
||
|
||
# Получаем параметры запроса
|
||
get_params = request.get_params or {}
|
||
|
||
# Для svodka_ca определяем режим из данных или используем 'fact' по умолчанию
|
||
if request.report_type == 'svodka_ca':
|
||
# Извлекаем режим из DataFrame или используем 'fact' по умолчанию
|
||
if hasattr(parser, 'df') and parser.df is not None and not parser.df.empty:
|
||
modes_in_df = parser.df['mode'].unique() if 'mode' in parser.df.columns else ['fact']
|
||
# Используем первый найденный режим или 'fact' по умолчанию
|
||
default_mode = modes_in_df[0] if len(modes_in_df) > 0 else 'fact'
|
||
else:
|
||
default_mode = 'fact'
|
||
|
||
# Устанавливаем режим в параметры, если он не указан
|
||
if 'mode' not in get_params:
|
||
get_params['mode'] = default_mode
|
||
|
||
# Определяем имя геттера
|
||
if request.report_type == 'svodka_ca':
|
||
# Для svodka_ca используем геттер get_ca_data
|
||
getter_name = 'get_ca_data'
|
||
elif request.report_type == 'svodka_repair_ca':
|
||
# Для svodka_repair_ca используем геттер get_repair_data
|
||
getter_name = 'get_repair_data'
|
||
elif request.report_type == 'statuses_repair_ca':
|
||
# Для statuses_repair_ca используем геттер get_repair_statuses
|
||
getter_name = 'get_repair_statuses'
|
||
elif request.report_type == 'monitoring_tar':
|
||
# Для monitoring_tar определяем геттер по параметрам
|
||
if 'mode' in get_params:
|
||
# Если есть параметр mode, используем get_tar_data
|
||
getter_name = 'get_tar_data'
|
||
else:
|
||
# Если нет параметра mode, используем get_tar_full_data
|
||
getter_name = 'get_tar_full_data'
|
||
elif request.report_type == 'monitoring_fuel':
|
||
# Для monitoring_fuel определяем геттер из параметра mode
|
||
getter_name = get_params.pop("mode", None)
|
||
if not getter_name:
|
||
# Если режим не указан, берем первый доступный
|
||
available_getters = list(parser.getters.keys())
|
||
if available_getters:
|
||
getter_name = available_getters[0]
|
||
print(f"⚠️ Режим не указан, используем первый доступный: {getter_name}")
|
||
else:
|
||
return DataResult(
|
||
success=False,
|
||
message="Парсер не имеет доступных геттеров"
|
||
)
|
||
elif request.report_type == 'svodka_pm':
|
||
# Для svodka_pm определяем геттер из параметра mode
|
||
getter_name = get_params.pop("mode", None)
|
||
if not getter_name:
|
||
# Если режим не указан, берем первый доступный
|
||
available_getters = list(parser.getters.keys())
|
||
if available_getters:
|
||
getter_name = available_getters[0]
|
||
print(f"⚠️ Режим не указан, используем первый доступный: {getter_name}")
|
||
else:
|
||
return DataResult(
|
||
success=False,
|
||
message="Парсер не имеет доступных геттеров"
|
||
)
|
||
else:
|
||
# Для других парсеров определяем из параметра mode
|
||
getter_name = get_params.pop("mode", None)
|
||
if not getter_name:
|
||
# Если режим не указан, берем первый доступный
|
||
available_getters = list(parser.getters.keys())
|
||
if available_getters:
|
||
getter_name = available_getters[0]
|
||
print(f"⚠️ Режим не указан, используем первый доступный: {getter_name}")
|
||
else:
|
||
return DataResult(
|
||
success=False,
|
||
message="Парсер не имеет доступных геттеров"
|
||
)
|
||
|
||
# Получаем значение через указанный геттер
|
||
try:
|
||
value = parser.get_value(getter_name, get_params)
|
||
except ValueError as e:
|
||
return DataResult(
|
||
success=False,
|
||
message=f"Ошибка параметров: {str(e)}"
|
||
)
|
||
|
||
# Формируем результат
|
||
if value is not None:
|
||
if hasattr(value, 'to_dict'):
|
||
result_data = dict(value)
|
||
else:
|
||
result_data = {"value": value}
|
||
return DataResult(success=True, data=result_data)
|
||
else:
|
||
return DataResult(success=False, message="Значение не найдено")
|
||
|
||
except Exception as e:
|
||
return DataResult(
|
||
success=False,
|
||
message=f"Ошибка при получении данных: {str(e)}"
|
||
)
|