128 lines
5.4 KiB
Python
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
|
|
} |