Files
scud_ai/modules/web_api/routers/reports.py
T

128 lines
5.4 KiB
Python

"""
===============================================================================
FILE: modules/web_api/routers/reports.py
ROLE: REST API On-Demand генерации отчетов:
- Сводка: за СЕГОДНЯ (оперативный контроль, текущий срез).
- Детальный и Упрощенный отчет: строго за ВЧЕРА по финальному срезу Y.
===============================================================================
"""
import os
import logging
from datetime import datetime, timedelta
from typing import Optional
from pydantic import BaseModel
from fastapi import APIRouter, HTTPException
from config import DATE_TODAY, DATE_YESTERDAY
from services.scud_etl.svodka_generator import generate_svodka_service
from services.scud_etl.otchet_generator import generate_otchet_service
from services.reports.simplified_builder import generate_simplified_excel
from services.scud_etl.pipeline import load_best_snapshot_for_date, load_1c_files_for_date
from services.scud_etl.merger import merge_scud_and_1c
logger = logging.getLogger("REPORTS_API")
router = APIRouter(prefix="/api/v1/reports", tags=["Reports"])
def get_previous_workday(target_date_str: str) -> str:
"""Вычисляет дату предыдущей рабочей смены (в понедельник возвращает пятницу)."""
clean_date = target_date_str.replace('_', '.')
try:
dt = datetime.strptime(clean_date, "%d.%m.%Y")
days_back = 3 if dt.weekday() == 0 else 1
return (dt - timedelta(days=days_back)).strftime("%d.%m.%Y")
except Exception:
return DATE_YESTERDAY
class GenerateReportRequest(BaseModel):
date: Optional[str] = None # ДД.ММ.ГГГГ
time: Optional[str] = None # ЧЧ:ММ
report_type: str # 'SVODKA', 'DETAILED', 'SIMPLIFIED', 'ALL'
@router.post("/generate")
def api_generate_report(req: GenerateReportRequest):
"""
Генерирует выбранный отчет:
- SVODKA: на текущую дату (date).
- DETAILED / SIMPLIFIED: строго за вчерашний рабочий день по финальному срезу Y.
"""
target_date = (req.date or DATE_TODAY).replace('_', '.')
yesterday_date = get_previous_workday(target_date)
r_type = req.report_type.upper()
results = []
# 1. Ежедневная сводка (за СЕГОДНЯ)
if r_type in ["SVODKA", "ALL"]:
res_svodka = generate_svodka_service(
target_date=target_date,
target_time=req.time
)
if res_svodka.get("status") == "success":
results.append({
"type": "Сводка",
"filename": res_svodka.get("filename"),
"download_url": res_svodka.get("download_url"),
"status": "success"
})
else:
results.append({
"type": "Сводка",
"error": res_svodka.get("message"),
"status": "error"
})
# 2. Детальный отчет (строго за ВЧЕРА по финальному срезу Y)
if r_type in ["DETAILED", "ALL"]:
res_det = generate_otchet_service(target_date=yesterday_date)
if res_det.get("status") == "success":
results.append({
"type": "Детальный отчет",
"filename": res_det.get("filename"),
"download_url": res_det.get("download_url"),
"status": "success"
})
else:
results.append({
"type": "Детальный отчет",
"error": res_det.get("message"),
"status": "error"
})
# 3. Упрощенный отчет (строго за ВЧЕРА по финальному срезу Y)
if r_type in ["SIMPLIFIED", "ALL"]:
try:
df_scud_y = load_best_snapshot_for_date(yesterday_date, prefer_final_y=True)
if df_scud_y is not None and not df_scud_y.empty:
df_staff_y, df_abs_y = load_1c_files_for_date(yesterday_date)
df_merged_y = merge_scud_and_1c(df_scud_y, df_staff_y, df_abs_y)
out_path = generate_simplified_excel(df_merged_y, date_str=yesterday_date)
filename = os.path.basename(out_path)
results.append({
"type": "Упрощенный отчет",
"filename": filename,
"download_url": f"/api/v1/files/download/reports/{filename}",
"status": "success"
})
else:
results.append({
"type": "Упрощенный отчет",
"error": f"Финальный срез СКУД (Y) за {yesterday_date} не найден.",
"status": "error"
})
except Exception as e:
logger.exception(f"Ошибка формирования упрощенного отчета: {e}")
results.append({
"type": "Упрощенный отчет",
"error": str(e),
"status": "error"
})
return {
"date": target_date,
"yesterday_date": yesterday_date,
"requested_type": r_type,
"reports": results
}