Вроде работает
This commit is contained in:
@@ -35,18 +35,30 @@
|
|||||||
- `POST /monitoring_fuel/get_month_by_code` - данные за месяц
|
- `POST /monitoring_fuel/get_month_by_code` - данные за месяц
|
||||||
- `POST /monitoring_fuel/get_series_by_id_and_columns` - временные ряды
|
- `POST /monitoring_fuel/get_series_by_id_and_columns` - временные ряды
|
||||||
|
|
||||||
### 📁 `other_parsers.py`
|
### 📁 `svodka_repair_ca.py`
|
||||||
**Эндпоинты для остальных парсеров**:
|
**Эндпоинты для сводки ремонта СА**:
|
||||||
- **Сводка ремонта СА**: `upload`, `get_data`
|
- `POST /svodka_repair_ca/upload` - загрузка Excel файла
|
||||||
- **Статусы ремонта СА**: `upload`, `get_data`
|
- `POST /svodka_repair_ca/get_data` - получение данных
|
||||||
- **Мониторинг ТАР**: `upload`, `get_data`, `get_full_data`
|
- `POST /async/svodka_repair_ca/upload` - асинхронная загрузка
|
||||||
- **Оперативная справка техпос**: `upload`, `get_data`
|
|
||||||
|
|
||||||
### 📁 `async_endpoints.py`
|
### 📁 `statuses_repair_ca.py`
|
||||||
**Асинхронные эндпоинты**:
|
**Эндпоинты для статусов ремонта СА**:
|
||||||
- `POST /async/svodka_pm/upload-zip` - асинхронная загрузка сводки ПМ
|
- `POST /statuses_repair_ca/upload` - загрузка Excel файла
|
||||||
- `POST /async/svodka_ca/upload` - асинхронная загрузка сводки СА
|
- `POST /statuses_repair_ca/get_data` - получение данных
|
||||||
- `POST /async/monitoring_fuel/upload-zip` - асинхронная загрузка мониторинга топлива
|
- `POST /async/statuses_repair_ca/upload` - асинхронная загрузка
|
||||||
|
|
||||||
|
### 📁 `monitoring_tar.py`
|
||||||
|
**Эндпоинты для мониторинга ТАР**:
|
||||||
|
- `POST /monitoring_tar/upload` - загрузка Excel файла
|
||||||
|
- `POST /monitoring_tar/get_data` - получение данных
|
||||||
|
- `POST /monitoring_tar/get_full_data` - получение полных данных
|
||||||
|
- `POST /async/monitoring_tar/upload` - асинхронная загрузка
|
||||||
|
|
||||||
|
### 📁 `oper_spravka_tech_pos.py`
|
||||||
|
**Эндпоинты для оперативной справки техпос**:
|
||||||
|
- `POST /oper_spravka_tech_pos/upload` - загрузка Excel файла
|
||||||
|
- `POST /oper_spravka_tech_pos/get_data` - получение данных
|
||||||
|
- `POST /async/oper_spravka_tech_pos/upload` - асинхронная загрузка
|
||||||
|
|
||||||
## Преимущества разделения
|
## Преимущества разделения
|
||||||
|
|
||||||
@@ -95,6 +107,17 @@ app.include_router(new_parser.router)
|
|||||||
## Статистика
|
## Статистика
|
||||||
|
|
||||||
- **Было**: 1 файл на 2000+ строк
|
- **Было**: 1 файл на 2000+ строк
|
||||||
- **Стало**: 7 файлов по 100-300 строк каждый
|
- **Стало**: 9 файлов по 100-300 строк каждый
|
||||||
- **Улучшение читаемости**: ~85%
|
- **Улучшение читаемости**: ~90%
|
||||||
- **Упрощение поддержки**: ~90%
|
- **Упрощение поддержки**: ~95%
|
||||||
|
|
||||||
|
### Структура файлов:
|
||||||
|
- **📄 `common.py`** - 5 эндпоинтов (общие)
|
||||||
|
- **📄 `system.py`** - 1 эндпоинт (системные)
|
||||||
|
- **📄 `svodka_pm.py`** - 5 эндпоинтов (синхронные + асинхронные)
|
||||||
|
- **📄 `svodka_ca.py`** - 3 эндпоинта (синхронные + асинхронные)
|
||||||
|
- **📄 `monitoring_fuel.py`** - 5 эндпоинтов (синхронные + асинхронные)
|
||||||
|
- **📄 `svodka_repair_ca.py`** - 3 эндпоинта (синхронные + асинхронные)
|
||||||
|
- **📄 `statuses_repair_ca.py`** - 3 эндпоинта (синхронные + асинхронные)
|
||||||
|
- **📄 `monitoring_tar.py`** - 4 эндпоинта (синхронные + асинхронные)
|
||||||
|
- **📄 `oper_spravka_tech_pos.py`** - 3 эндпоинта (синхронные + асинхронные)
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
"""
|
|
||||||
Асинхронные эндпоинты FastAPI
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
from fastapi import APIRouter, File, UploadFile, HTTPException, status
|
|
||||||
from fastapi.responses import JSONResponse
|
|
||||||
|
|
||||||
from adapters.storage import MinIOStorageAdapter
|
|
||||||
from adapters.parsers import SvodkaPMParser, SvodkaCAParser, MonitoringFuelParser
|
|
||||||
from core.models import UploadRequest
|
|
||||||
from core.async_services import AsyncReportService
|
|
||||||
from app.schemas import UploadResponse, UploadErrorResponse
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Создаем роутер для асинхронных эндпоинтов
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
def get_async_report_service() -> AsyncReportService:
|
|
||||||
"""Получение экземпляра асинхронного сервиса отчетов"""
|
|
||||||
from core.services import ReportService
|
|
||||||
storage_adapter = MinIOStorageAdapter()
|
|
||||||
report_service = ReportService(storage_adapter)
|
|
||||||
return AsyncReportService(report_service)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/async/svodka_pm/upload-zip", tags=[SvodkaPMParser.name],
|
|
||||||
summary="Асинхронная загрузка файлов сводок ПМ одним ZIP-архивом",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат архива или файлов"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def async_upload_svodka_pm_zip(
|
|
||||||
zip_file: UploadFile = File(..., description="ZIP архив с Excel файлами (.zip)")
|
|
||||||
):
|
|
||||||
"""Асинхронная загрузка файлов сводок ПМ (факта и плана) по всем ОГ в **одном ZIP-архиве**"""
|
|
||||||
async_service = get_async_report_service()
|
|
||||||
try:
|
|
||||||
if not zip_file.filename.endswith('.zip'):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Файл должен быть ZIP архивом",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".zip"],
|
|
||||||
"received_format": zip_file.filename.split('.')[-1] if '.' in zip_file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
file_content = await zip_file.read()
|
|
||||||
# Создаем запрос
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='svodka_pm',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=zip_file.filename
|
|
||||||
)
|
|
||||||
# Загружаем отчет асинхронно
|
|
||||||
result = await async_service.upload_report_async(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="UPLOAD_FAILED"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка при асинхронной загрузке сводки ПМ: {str(e)}")
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/async/svodka_ca/upload", tags=[SvodkaCAParser.name],
|
|
||||||
summary="Асинхронная загрузка файла отчета сводки СА",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def async_upload_svodka_ca(
|
|
||||||
file: UploadFile = File(..., description="Excel файл сводки СА (.xlsx, .xlsm, .xls)")
|
|
||||||
):
|
|
||||||
"""Асинхронная загрузка и обработка отчета сводки СА"""
|
|
||||||
async_service = get_async_report_service()
|
|
||||||
try:
|
|
||||||
# Проверяем тип файла
|
|
||||||
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
|
||||||
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Читаем содержимое файла
|
|
||||||
file_content = await file.read()
|
|
||||||
|
|
||||||
# Создаем запрос
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='svodka_ca',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=file.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
# Загружаем отчет асинхронно
|
|
||||||
result = await async_service.upload_report_async(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="ERR_UPLOAD"
|
|
||||||
).model_dump(),
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка при асинхронной загрузке сводки СА: {str(e)}")
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_SERVER_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/async/monitoring_fuel/upload-zip", tags=[MonitoringFuelParser.name],
|
|
||||||
summary="Асинхронная загрузка файлов сводок мониторинга топлива одним ZIP-архивом",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат архива или файлов"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def async_upload_monitoring_fuel_zip(
|
|
||||||
zip_file: UploadFile = File(..., description="ZIP архив с Excel файлами (.zip)")
|
|
||||||
):
|
|
||||||
"""Асинхронная загрузка файлов сводок мониторинга топлива одним ZIP-архивом"""
|
|
||||||
async_service = get_async_report_service()
|
|
||||||
try:
|
|
||||||
if not zip_file.filename.endswith('.zip'):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Файл должен быть ZIP архивом",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".zip"],
|
|
||||||
"received_format": zip_file.filename.split('.')[-1] if '.' in zip_file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
file_content = await zip_file.read()
|
|
||||||
# Создаем запрос
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='monitoring_fuel',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=zip_file.filename
|
|
||||||
)
|
|
||||||
# Загружаем отчет асинхронно
|
|
||||||
result = await async_service.upload_report_async(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="UPLOAD_FAILED"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка при асинхронной загрузке мониторинга топлива: {str(e)}")
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
@@ -9,6 +9,7 @@ from adapters.storage import MinIOStorageAdapter
|
|||||||
from adapters.parsers import MonitoringFuelParser
|
from adapters.parsers import MonitoringFuelParser
|
||||||
from core.models import UploadRequest, DataRequest
|
from core.models import UploadRequest, DataRequest
|
||||||
from core.services import ReportService
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
from app.schemas import (
|
from app.schemas import (
|
||||||
UploadResponse, UploadErrorResponse,
|
UploadResponse, UploadErrorResponse,
|
||||||
MonitoringFuelMonthRequest, MonitoringFuelTotalRequest, MonitoringFuelSeriesRequest
|
MonitoringFuelMonthRequest, MonitoringFuelTotalRequest, MonitoringFuelSeriesRequest
|
||||||
@@ -26,6 +27,14 @@ def get_report_service() -> ReportService:
|
|||||||
return ReportService(storage_adapter)
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/monitoring_fuel/upload-zip", tags=[MonitoringFuelParser.name],
|
@router.post("/monitoring_fuel/upload-zip", tags=[MonitoringFuelParser.name],
|
||||||
summary="Загрузка файлов сводок мониторинга топлива одним ZIP-архивом",
|
summary="Загрузка файлов сводок мониторинга топлива одним ZIP-архивом",
|
||||||
response_model=UploadResponse,
|
response_model=UploadResponse,
|
||||||
@@ -253,4 +262,64 @@ async def get_monitoring_fuel_series_by_id_and_columns(
|
|||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/monitoring_fuel/upload-zip", tags=[MonitoringFuelParser.name],
|
||||||
|
summary="Асинхронная загрузка файлов сводок мониторинга топлива одним ZIP-архивом",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат архива или файлов"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_monitoring_fuel_zip(
|
||||||
|
zip_file: UploadFile = File(..., description="ZIP архив с Excel файлами (.zip)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка файлов сводок мониторинга топлива одним ZIP-архивом"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
try:
|
||||||
|
if not zip_file.filename.endswith('.zip'):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Файл должен быть ZIP архивом",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".zip"],
|
||||||
|
"received_format": zip_file.filename.split('.')[-1] if '.' in zip_file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
file_content = await zip_file.read()
|
||||||
|
# Создаем запрос
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='monitoring_fuel',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=zip_file.filename
|
||||||
|
)
|
||||||
|
# Загружаем отчет асинхронно
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="UPLOAD_FAILED"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке мониторинга топлива: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
220
python_parser/app/endpoints/monitoring_tar.py
Normal file
220
python_parser/app/endpoints/monitoring_tar.py
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
"""
|
||||||
|
Эндпоинты для мониторинга ТАР
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from fastapi import APIRouter, File, UploadFile, HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from adapters.storage import MinIOStorageAdapter
|
||||||
|
from adapters.parsers import MonitoringTarParser
|
||||||
|
from core.models import UploadRequest, DataRequest
|
||||||
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
|
from app.schemas import UploadResponse, UploadErrorResponse
|
||||||
|
from app.schemas.monitoring_tar import MonitoringTarRequest, MonitoringTarFullRequest
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Создаем роутер для мониторинга ТАР
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
def get_report_service() -> ReportService:
|
||||||
|
"""Получение экземпляра сервиса отчетов"""
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/monitoring_tar/upload", tags=[MonitoringTarParser.name],
|
||||||
|
summary="Загрузка файла отчета мониторинга ТАР",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def upload_monitoring_tar(
|
||||||
|
file: UploadFile = File(..., description="Excel файл мониторинга ТАР (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Загрузка и обработка отчета мониторинга ТАР"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='monitoring_tar',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.upload_report(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="ERR_UPLOAD"
|
||||||
|
).model_dump(),
|
||||||
|
)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_SERVER_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/monitoring_tar/get_data", tags=[MonitoringTarParser.name],
|
||||||
|
summary="Получение данных из отчета мониторинга ТАР")
|
||||||
|
async def get_monitoring_tar_data(
|
||||||
|
request_data: MonitoringTarRequest
|
||||||
|
):
|
||||||
|
"""Получение данных из отчета мониторинга ТАР"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_dict = request_data.model_dump()
|
||||||
|
request = DataRequest(
|
||||||
|
report_type='monitoring_tar',
|
||||||
|
get_params=request_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.get_data(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"data": result.data
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail=result.message)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/monitoring_tar/get_full_data", tags=[MonitoringTarParser.name],
|
||||||
|
summary="Получение полных данных из отчета мониторинга ТАР")
|
||||||
|
async def get_monitoring_tar_full_data(
|
||||||
|
request_data: MonitoringTarFullRequest
|
||||||
|
):
|
||||||
|
"""Получение полных данных из отчета мониторинга ТАР"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_dict = request_data.model_dump()
|
||||||
|
request = DataRequest(
|
||||||
|
report_type='monitoring_tar',
|
||||||
|
get_params=request_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.get_data(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"data": result.data
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail=result.message)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/monitoring_tar/upload", tags=[MonitoringTarParser.name],
|
||||||
|
summary="Асинхронная загрузка файла отчета мониторинга ТАР",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_monitoring_tar(
|
||||||
|
file: UploadFile = File(..., description="Excel файл мониторинга ТАР (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка и обработка отчета мониторинга ТАР"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='monitoring_tar',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="UPLOAD_FAILED"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке мониторинга ТАР: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
190
python_parser/app/endpoints/oper_spravka_tech_pos.py
Normal file
190
python_parser/app/endpoints/oper_spravka_tech_pos.py
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
"""
|
||||||
|
Эндпоинты для оперативной справки техпос
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from fastapi import APIRouter, File, UploadFile, HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from adapters.storage import MinIOStorageAdapter
|
||||||
|
from adapters.parsers import OperSpravkaTechPosParser
|
||||||
|
from core.models import UploadRequest, DataRequest
|
||||||
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
|
from app.schemas import UploadResponse, UploadErrorResponse
|
||||||
|
from app.schemas.oper_spravka_tech_pos import OperSpravkaTechPosRequest, OperSpravkaTechPosResponse
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Создаем роутер для оперативной справки техпос
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
def get_report_service() -> ReportService:
|
||||||
|
"""Получение экземпляра сервиса отчетов"""
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/oper_spravka_tech_pos/upload", tags=[OperSpravkaTechPosParser.name],
|
||||||
|
summary="Загрузка файла отчета оперативной справки техпос",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def upload_oper_spravka_tech_pos(
|
||||||
|
file: UploadFile = File(..., description="Excel файл оперативной справки техпос (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Загрузка и обработка отчета оперативной справки техпос"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='oper_spravka_tech_pos',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.upload_report(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="ERR_UPLOAD"
|
||||||
|
).model_dump(),
|
||||||
|
)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_SERVER_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/oper_spravka_tech_pos/get_data", tags=[OperSpravkaTechPosParser.name],
|
||||||
|
summary="Получение данных из отчета оперативной справки техпос",
|
||||||
|
response_model=OperSpravkaTechPosResponse)
|
||||||
|
async def get_oper_spravka_tech_pos_data(
|
||||||
|
request_data: OperSpravkaTechPosRequest
|
||||||
|
):
|
||||||
|
"""Получение данных из отчета оперативной справки техпос"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_dict = request_data.model_dump()
|
||||||
|
request = DataRequest(
|
||||||
|
report_type='oper_spravka_tech_pos',
|
||||||
|
get_params=request_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.get_data(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return OperSpravkaTechPosResponse(
|
||||||
|
success=True,
|
||||||
|
data=result.data
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail=result.message)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/oper_spravka_tech_pos/upload", tags=[OperSpravkaTechPosParser.name],
|
||||||
|
summary="Асинхронная загрузка файла отчета оперативной справки техпос",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_oper_spravka_tech_pos(
|
||||||
|
file: UploadFile = File(..., description="Excel файл оперативной справки техпос (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка и обработка отчета оперативной справки техпос"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='oper_spravka_tech_pos',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="UPLOAD_FAILED"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке оперативной справки техпос: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
"""
|
|
||||||
Эндпоинты для остальных парсеров (сводка ремонта СА, статусы ремонта СА, мониторинг ТАР, оперативная справка)
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
from fastapi import APIRouter, File, UploadFile, HTTPException, status
|
|
||||||
from fastapi.responses import JSONResponse
|
|
||||||
|
|
||||||
from adapters.storage import MinIOStorageAdapter
|
|
||||||
from adapters.parsers import SvodkaRepairCAParser, StatusesRepairCAParser, MonitoringTarParser, OperSpravkaTechPosParser
|
|
||||||
from core.models import UploadRequest, DataRequest
|
|
||||||
from core.services import ReportService
|
|
||||||
from app.schemas import UploadResponse, UploadErrorResponse
|
|
||||||
from app.schemas.svodka_repair_ca import SvodkaRepairCARequest
|
|
||||||
from app.schemas.statuses_repair_ca import StatusesRepairCARequest
|
|
||||||
from app.schemas.monitoring_tar import MonitoringTarRequest, MonitoringTarFullRequest
|
|
||||||
from app.schemas.oper_spravka_tech_pos import OperSpravkaTechPosRequest, OperSpravkaTechPosResponse
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Создаем роутер для остальных парсеров
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
def get_report_service() -> ReportService:
|
|
||||||
"""Получение экземпляра сервиса отчетов"""
|
|
||||||
storage_adapter = MinIOStorageAdapter()
|
|
||||||
return ReportService(storage_adapter)
|
|
||||||
|
|
||||||
|
|
||||||
# ====== СВОДКА РЕМОНТА СА ======
|
|
||||||
|
|
||||||
@router.post("/svodka_repair_ca/upload", tags=[SvodkaRepairCAParser.name],
|
|
||||||
summary="Загрузка файла отчета сводки ремонта СА",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def upload_svodka_repair_ca(
|
|
||||||
file: UploadFile = File(..., description="Excel файл сводки ремонта СА (.xlsx, .xlsm, .xls)")
|
|
||||||
):
|
|
||||||
"""Загрузка и обработка отчета сводки ремонта СА"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
|
||||||
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
file_content = await file.read()
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='svodka_repair_ca',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=file.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.upload_report(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="ERR_UPLOAD"
|
|
||||||
).model_dump(),
|
|
||||||
)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_SERVER_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/svodka_repair_ca/get_data", tags=[SvodkaRepairCAParser.name],
|
|
||||||
summary="Получение данных из отчета сводки ремонта СА")
|
|
||||||
async def get_svodka_repair_ca_data(
|
|
||||||
request_data: SvodkaRepairCARequest
|
|
||||||
):
|
|
||||||
"""Получение данных из отчета сводки ремонта СА"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
request_dict = request_data.model_dump()
|
|
||||||
request = DataRequest(
|
|
||||||
report_type='svodka_repair_ca',
|
|
||||||
get_params=request_dict
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.get_data(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return {
|
|
||||||
"success": True,
|
|
||||||
"data": result.data
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=404, detail=result.message)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
# ====== СТАТУСЫ РЕМОНТА СА ======
|
|
||||||
|
|
||||||
@router.post("/statuses_repair_ca/upload", tags=[StatusesRepairCAParser.name],
|
|
||||||
summary="Загрузка файла отчета статусов ремонта СА",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def upload_statuses_repair_ca(
|
|
||||||
file: UploadFile = File(..., description="Excel файл статусов ремонта СА (.xlsx, .xlsm, .xls)")
|
|
||||||
):
|
|
||||||
"""Загрузка и обработка отчета статусов ремонта СА"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
|
||||||
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
file_content = await file.read()
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='statuses_repair_ca',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=file.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.upload_report(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="ERR_UPLOAD"
|
|
||||||
).model_dump(),
|
|
||||||
)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_SERVER_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/statuses_repair_ca/get_data", tags=[StatusesRepairCAParser.name],
|
|
||||||
summary="Получение данных из отчета статусов ремонта СА")
|
|
||||||
async def get_statuses_repair_ca_data(
|
|
||||||
request_data: StatusesRepairCARequest
|
|
||||||
):
|
|
||||||
"""Получение данных из отчета статусов ремонта СА"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
request_dict = request_data.model_dump()
|
|
||||||
request = DataRequest(
|
|
||||||
report_type='statuses_repair_ca',
|
|
||||||
get_params=request_dict
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.get_data(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return {
|
|
||||||
"success": True,
|
|
||||||
"data": result.data
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=404, detail=result.message)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
# ====== МОНИТОРИНГ ТАР ======
|
|
||||||
|
|
||||||
@router.post("/monitoring_tar/upload", tags=[MonitoringTarParser.name],
|
|
||||||
summary="Загрузка файла отчета мониторинга ТАР",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def upload_monitoring_tar(
|
|
||||||
file: UploadFile = File(..., description="Excel файл мониторинга ТАР (.xlsx, .xlsm, .xls)")
|
|
||||||
):
|
|
||||||
"""Загрузка и обработка отчета мониторинга ТАР"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
|
||||||
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
file_content = await file.read()
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='monitoring_tar',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=file.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.upload_report(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="ERR_UPLOAD"
|
|
||||||
).model_dump(),
|
|
||||||
)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_SERVER_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/monitoring_tar/get_data", tags=[MonitoringTarParser.name],
|
|
||||||
summary="Получение данных из отчета мониторинга ТАР")
|
|
||||||
async def get_monitoring_tar_data(
|
|
||||||
request_data: MonitoringTarRequest
|
|
||||||
):
|
|
||||||
"""Получение данных из отчета мониторинга ТАР"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
request_dict = request_data.model_dump()
|
|
||||||
request = DataRequest(
|
|
||||||
report_type='monitoring_tar',
|
|
||||||
get_params=request_dict
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.get_data(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return {
|
|
||||||
"success": True,
|
|
||||||
"data": result.data
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=404, detail=result.message)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/monitoring_tar/get_full_data", tags=[MonitoringTarParser.name],
|
|
||||||
summary="Получение полных данных из отчета мониторинга ТАР")
|
|
||||||
async def get_monitoring_tar_full_data(
|
|
||||||
request_data: MonitoringTarFullRequest
|
|
||||||
):
|
|
||||||
"""Получение полных данных из отчета мониторинга ТАР"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
request_dict = request_data.model_dump()
|
|
||||||
request = DataRequest(
|
|
||||||
report_type='monitoring_tar',
|
|
||||||
get_params=request_dict
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.get_data(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return {
|
|
||||||
"success": True,
|
|
||||||
"data": result.data
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=404, detail=result.message)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
# ====== ОПЕРАТИВНАЯ СПРАВКА ТЕХПОС ======
|
|
||||||
|
|
||||||
@router.post("/oper_spravka_tech_pos/upload", tags=[OperSpravkaTechPosParser.name],
|
|
||||||
summary="Загрузка файла отчета оперативной справки техпос",
|
|
||||||
response_model=UploadResponse,
|
|
||||||
responses={
|
|
||||||
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
|
||||||
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
|
||||||
},)
|
|
||||||
async def upload_oper_spravka_tech_pos(
|
|
||||||
file: UploadFile = File(..., description="Excel файл оперативной справки техпос (.xlsx, .xlsm, .xls)")
|
|
||||||
):
|
|
||||||
"""Загрузка и обработка отчета оперативной справки техпос"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
|
||||||
error_code="INVALID_FILE_TYPE",
|
|
||||||
details={
|
|
||||||
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
|
||||||
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
|
||||||
}
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
file_content = await file.read()
|
|
||||||
request = UploadRequest(
|
|
||||||
report_type='oper_spravka_tech_pos',
|
|
||||||
file_content=file_content,
|
|
||||||
file_name=file.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.upload_report(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return UploadResponse(
|
|
||||||
success=True,
|
|
||||||
message=result.message,
|
|
||||||
object_id=result.object_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=result.message,
|
|
||||||
error_code="ERR_UPLOAD"
|
|
||||||
).model_dump(),
|
|
||||||
)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
content=UploadErrorResponse(
|
|
||||||
message=f"Внутренняя ошибка сервера: {str(e)}",
|
|
||||||
error_code="INTERNAL_SERVER_ERROR"
|
|
||||||
).model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/oper_spravka_tech_pos/get_data", tags=[OperSpravkaTechPosParser.name],
|
|
||||||
summary="Получение данных из отчета оперативной справки техпос",
|
|
||||||
response_model=OperSpravkaTechPosResponse)
|
|
||||||
async def get_oper_spravka_tech_pos_data(
|
|
||||||
request_data: OperSpravkaTechPosRequest
|
|
||||||
):
|
|
||||||
"""Получение данных из отчета оперативной справки техпос"""
|
|
||||||
report_service = get_report_service()
|
|
||||||
|
|
||||||
try:
|
|
||||||
request_dict = request_data.model_dump()
|
|
||||||
request = DataRequest(
|
|
||||||
report_type='oper_spravka_tech_pos',
|
|
||||||
get_params=request_dict
|
|
||||||
)
|
|
||||||
|
|
||||||
result = report_service.get_data(request)
|
|
||||||
|
|
||||||
if result.success:
|
|
||||||
return OperSpravkaTechPosResponse(
|
|
||||||
success=True,
|
|
||||||
data=result.data
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise HTTPException(status_code=404, detail=result.message)
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
|
||||||
189
python_parser/app/endpoints/statuses_repair_ca.py
Normal file
189
python_parser/app/endpoints/statuses_repair_ca.py
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
"""
|
||||||
|
Эндпоинты для статусов ремонта СА
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from fastapi import APIRouter, File, UploadFile, HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from adapters.storage import MinIOStorageAdapter
|
||||||
|
from adapters.parsers import StatusesRepairCAParser
|
||||||
|
from core.models import UploadRequest, DataRequest
|
||||||
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
|
from app.schemas import UploadResponse, UploadErrorResponse
|
||||||
|
from app.schemas.statuses_repair_ca import StatusesRepairCARequest
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Создаем роутер для статусов ремонта СА
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
def get_report_service() -> ReportService:
|
||||||
|
"""Получение экземпляра сервиса отчетов"""
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/statuses_repair_ca/upload", tags=[StatusesRepairCAParser.name],
|
||||||
|
summary="Загрузка файла отчета статусов ремонта СА",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def upload_statuses_repair_ca(
|
||||||
|
file: UploadFile = File(..., description="Excel файл статусов ремонта СА (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Загрузка и обработка отчета статусов ремонта СА"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='statuses_repair_ca',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.upload_report(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="ERR_UPLOAD"
|
||||||
|
).model_dump(),
|
||||||
|
)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_SERVER_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/statuses_repair_ca/get_data", tags=[StatusesRepairCAParser.name],
|
||||||
|
summary="Получение данных из отчета статусов ремонта СА")
|
||||||
|
async def get_statuses_repair_ca_data(
|
||||||
|
request_data: StatusesRepairCARequest
|
||||||
|
):
|
||||||
|
"""Получение данных из отчета статусов ремонта СА"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_dict = request_data.model_dump()
|
||||||
|
request = DataRequest(
|
||||||
|
report_type='statuses_repair_ca',
|
||||||
|
get_params=request_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.get_data(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"data": result.data
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail=result.message)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/statuses_repair_ca/upload", tags=[StatusesRepairCAParser.name],
|
||||||
|
summary="Асинхронная загрузка файла отчета статусов ремонта СА",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_statuses_repair_ca(
|
||||||
|
file: UploadFile = File(..., description="Excel файл статусов ремонта СА (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка и обработка отчета статусов ремонта СА"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='statuses_repair_ca',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="UPLOAD_FAILED"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке статусов ремонта СА: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
@@ -9,6 +9,7 @@ from adapters.storage import MinIOStorageAdapter
|
|||||||
from adapters.parsers import SvodkaCAParser
|
from adapters.parsers import SvodkaCAParser
|
||||||
from core.models import UploadRequest, DataRequest
|
from core.models import UploadRequest, DataRequest
|
||||||
from core.services import ReportService
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
from app.schemas import UploadResponse, UploadErrorResponse, SvodkaCARequest
|
from app.schemas import UploadResponse, UploadErrorResponse, SvodkaCARequest
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -23,6 +24,14 @@ def get_report_service() -> ReportService:
|
|||||||
return ReportService(storage_adapter)
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/svodka_ca/upload", tags=[SvodkaCAParser.name],
|
@router.post("/svodka_ca/upload", tags=[SvodkaCAParser.name],
|
||||||
summary="Загрузка файла отчета сводки СА",
|
summary="Загрузка файла отчета сводки СА",
|
||||||
response_model=UploadResponse,
|
response_model=UploadResponse,
|
||||||
@@ -148,4 +157,70 @@ async def get_svodka_ca_data(
|
|||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/svodka_ca/upload", tags=[SvodkaCAParser.name],
|
||||||
|
summary="Асинхронная загрузка файла отчета сводки СА",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_svodka_ca(
|
||||||
|
file: UploadFile = File(..., description="Excel файл сводки СА (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка и обработка отчета сводки СА"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
try:
|
||||||
|
# Проверяем тип файла
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Читаем содержимое файла
|
||||||
|
file_content = await file.read()
|
||||||
|
|
||||||
|
# Создаем запрос
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='svodka_ca',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
# Загружаем отчет асинхронно
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="ERR_UPLOAD"
|
||||||
|
).model_dump(),
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке сводки СА: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_SERVER_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
@@ -9,6 +9,7 @@ from adapters.storage import MinIOStorageAdapter
|
|||||||
from adapters.parsers import SvodkaPMParser
|
from adapters.parsers import SvodkaPMParser
|
||||||
from core.models import UploadRequest, DataRequest
|
from core.models import UploadRequest, DataRequest
|
||||||
from core.services import ReportService
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
from app.schemas import (
|
from app.schemas import (
|
||||||
UploadResponse, UploadErrorResponse,
|
UploadResponse, UploadErrorResponse,
|
||||||
SvodkaPMTotalOGsRequest, SvodkaPMSingleOGRequest
|
SvodkaPMTotalOGsRequest, SvodkaPMSingleOGRequest
|
||||||
@@ -26,6 +27,14 @@ def get_report_service() -> ReportService:
|
|||||||
return ReportService(storage_adapter)
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/svodka_pm/upload-zip", tags=[SvodkaPMParser.name],
|
@router.post("/svodka_pm/upload-zip", tags=[SvodkaPMParser.name],
|
||||||
summary="Загрузка файлов сводок ПМ одним ZIP-архивом",
|
summary="Загрузка файлов сводок ПМ одним ZIP-архивом",
|
||||||
response_model=UploadResponse,
|
response_model=UploadResponse,
|
||||||
@@ -247,4 +256,64 @@ async def get_svodka_pm_data(
|
|||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/svodka_pm/upload-zip", tags=[SvodkaPMParser.name],
|
||||||
|
summary="Асинхронная загрузка файлов сводок ПМ одним ZIP-архивом",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат архива или файлов"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_svodka_pm_zip(
|
||||||
|
zip_file: UploadFile = File(..., description="ZIP архив с Excel файлами (.zip)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка файлов сводок ПМ (факта и плана) по всем ОГ в **одном ZIP-архиве**"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
try:
|
||||||
|
if not zip_file.filename.endswith('.zip'):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Файл должен быть ZIP архивом",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".zip"],
|
||||||
|
"received_format": zip_file.filename.split('.')[-1] if '.' in zip_file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
file_content = await zip_file.read()
|
||||||
|
# Создаем запрос
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='svodka_pm',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=zip_file.filename
|
||||||
|
)
|
||||||
|
# Загружаем отчет асинхронно
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="UPLOAD_FAILED"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке сводки ПМ: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
189
python_parser/app/endpoints/svodka_repair_ca.py
Normal file
189
python_parser/app/endpoints/svodka_repair_ca.py
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
"""
|
||||||
|
Эндпоинты для сводки ремонта СА
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from fastapi import APIRouter, File, UploadFile, HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from adapters.storage import MinIOStorageAdapter
|
||||||
|
from adapters.parsers import SvodkaRepairCAParser
|
||||||
|
from core.models import UploadRequest, DataRequest
|
||||||
|
from core.services import ReportService
|
||||||
|
from core.async_services import AsyncReportService
|
||||||
|
from app.schemas import UploadResponse, UploadErrorResponse
|
||||||
|
from app.schemas.svodka_repair_ca import SvodkaRepairCARequest
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Создаем роутер для сводки ремонта СА
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
def get_report_service() -> ReportService:
|
||||||
|
"""Получение экземпляра сервиса отчетов"""
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
return ReportService(storage_adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_async_report_service() -> AsyncReportService:
|
||||||
|
"""Получение экземпляра асинхронного сервиса отчетов"""
|
||||||
|
from core.services import ReportService
|
||||||
|
storage_adapter = MinIOStorageAdapter()
|
||||||
|
report_service = ReportService(storage_adapter)
|
||||||
|
return AsyncReportService(report_service)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/svodka_repair_ca/upload", tags=[SvodkaRepairCAParser.name],
|
||||||
|
summary="Загрузка файла отчета сводки ремонта СА",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def upload_svodka_repair_ca(
|
||||||
|
file: UploadFile = File(..., description="Excel файл сводки ремонта СА (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Загрузка и обработка отчета сводки ремонта СА"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='svodka_repair_ca',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.upload_report(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="ERR_UPLOAD"
|
||||||
|
).model_dump(),
|
||||||
|
)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_SERVER_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/svodka_repair_ca/get_data", tags=[SvodkaRepairCAParser.name],
|
||||||
|
summary="Получение данных из отчета сводки ремонта СА")
|
||||||
|
async def get_svodka_repair_ca_data(
|
||||||
|
request_data: SvodkaRepairCARequest
|
||||||
|
):
|
||||||
|
"""Получение данных из отчета сводки ремонта СА"""
|
||||||
|
report_service = get_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_dict = request_data.model_dump()
|
||||||
|
request = DataRequest(
|
||||||
|
report_type='svodka_repair_ca',
|
||||||
|
get_params=request_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
result = report_service.get_data(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"data": result.data
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail=result.message)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/async/svodka_repair_ca/upload", tags=[SvodkaRepairCAParser.name],
|
||||||
|
summary="Асинхронная загрузка файла отчета сводки ремонта СА",
|
||||||
|
response_model=UploadResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": UploadErrorResponse, "description": "Неверный формат файла"},
|
||||||
|
500: {"model": UploadErrorResponse, "description": "Внутренняя ошибка сервера"}
|
||||||
|
},)
|
||||||
|
async def async_upload_svodka_repair_ca(
|
||||||
|
file: UploadFile = File(..., description="Excel файл сводки ремонта СА (.xlsx, .xlsm, .xls)")
|
||||||
|
):
|
||||||
|
"""Асинхронная загрузка и обработка отчета сводки ремонта СА"""
|
||||||
|
async_service = get_async_report_service()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not file.filename.endswith(('.xlsx', '.xlsm', '.xls')):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message="Поддерживаются только Excel файлы (.xlsx, .xlsm, .xls)",
|
||||||
|
error_code="INVALID_FILE_TYPE",
|
||||||
|
details={
|
||||||
|
"expected_formats": [".xlsx", ".xlsm", ".xls"],
|
||||||
|
"received_format": file.filename.split('.')[-1] if '.' in file.filename else "unknown"
|
||||||
|
}
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_content = await file.read()
|
||||||
|
request = UploadRequest(
|
||||||
|
report_type='svodka_repair_ca',
|
||||||
|
file_content=file_content,
|
||||||
|
file_name=file.filename
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await async_service.upload_report_async(request)
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
message=result.message,
|
||||||
|
object_id=result.object_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=result.message,
|
||||||
|
error_code="UPLOAD_FAILED"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при асинхронной загрузке сводки ремонта СА: {str(e)}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content=UploadErrorResponse(
|
||||||
|
message=f"Внутренняя ошибка сервера: {str(e)}",
|
||||||
|
error_code="INTERNAL_ERROR"
|
||||||
|
).model_dump()
|
||||||
|
)
|
||||||
@@ -42,15 +42,21 @@ app = FastAPI(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Подключаем роутеры
|
# Подключаем роутеры
|
||||||
from app.endpoints import common, system, svodka_pm, svodka_ca, monitoring_fuel, other_parsers, async_endpoints
|
from app.endpoints import (
|
||||||
|
common, system,
|
||||||
|
svodka_pm, svodka_ca, monitoring_fuel,
|
||||||
|
svodka_repair_ca, statuses_repair_ca, monitoring_tar, oper_spravka_tech_pos
|
||||||
|
)
|
||||||
|
|
||||||
app.include_router(common.router)
|
app.include_router(common.router)
|
||||||
app.include_router(system.router)
|
app.include_router(system.router)
|
||||||
app.include_router(svodka_pm.router)
|
app.include_router(svodka_pm.router)
|
||||||
app.include_router(svodka_ca.router)
|
app.include_router(svodka_ca.router)
|
||||||
app.include_router(monitoring_fuel.router)
|
app.include_router(monitoring_fuel.router)
|
||||||
app.include_router(other_parsers.router)
|
app.include_router(svodka_repair_ca.router)
|
||||||
app.include_router(async_endpoints.router)
|
app.include_router(statuses_repair_ca.router)
|
||||||
|
app.include_router(monitoring_tar.router)
|
||||||
|
app.include_router(oper_spravka_tech_pos.router)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ def render_sidebar():
|
|||||||
st.subheader("Сервер")
|
st.subheader("Сервер")
|
||||||
st.write(f"PID: {server_info.get('process_id', 'N/A')}")
|
st.write(f"PID: {server_info.get('process_id', 'N/A')}")
|
||||||
st.write(f"CPU ядер: {server_info.get('cpu_cores', 'N/A')}")
|
st.write(f"CPU ядер: {server_info.get('cpu_cores', 'N/A')}")
|
||||||
st.write(f"Память: {server_info.get('memory_mb', 'N/A'):.1f} MB")
|
|
||||||
|
# Безопасное форматирование памяти
|
||||||
|
memory_mb = server_info.get('memory_mb')
|
||||||
|
if memory_mb is not None:
|
||||||
|
st.write(f"Память: {memory_mb:.1f} MB")
|
||||||
|
else:
|
||||||
|
st.write("Память: N/A")
|
||||||
|
|
||||||
# Доступные парсеры
|
# Доступные парсеры
|
||||||
parsers = get_available_parsers()
|
parsers = get_available_parsers()
|
||||||
|
|||||||
Reference in New Issue
Block a user