80 lines
3.6 KiB
Python
80 lines
3.6 KiB
Python
"""
|
|
===============================================================================
|
|
FILE: services/scud_etl/svodka_generator.py
|
|
ROLE: Генератор Ежедневной Сводки (оперативный контроль, текущий срез).
|
|
===============================================================================
|
|
"""
|
|
|
|
import os
|
|
import logging
|
|
from typing import Dict, Any, Optional
|
|
import pandas as pd
|
|
|
|
from config import DATE_TODAY
|
|
from core.database import load_scud_from_db_by_snapshot
|
|
from services.scud_etl.pipeline import load_1c_files_for_date
|
|
from services.scud_etl.merger import merge_scud_and_1c, calculate_summary_metrics
|
|
from services.scud_etl.anomaly_detector import detect_registry_anomalies
|
|
from services.snapshots.finder import find_or_create_snapshot_for_time
|
|
from services.excel_exporter import generate_summary_excel, get_dated_reports_dir, format_date_ru
|
|
|
|
logger = logging.getLogger("SVODKA_GENERATOR")
|
|
|
|
|
|
def generate_svodka_service(
|
|
target_date: Optional[str] = None,
|
|
target_time: Optional[str] = None,
|
|
snapshot_id: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Формирует оперативную сводку на указанную дату / время:
|
|
- target_date: дата сводки (по умолчанию сегодня).
|
|
- target_time: время среза (например '14:30').
|
|
- snapshot_id: точный ID среза.
|
|
"""
|
|
date_clean = str(target_date or DATE_TODAY).replace('_', '.')
|
|
applied_note = ""
|
|
|
|
# Если передано время, но не указан конкретный snapshot_id — ищем ближайший или запрашиваем экспорт
|
|
if target_time and not snapshot_id:
|
|
found_id, note = find_or_create_snapshot_for_time(date_clean, target_time, allow_ondemand_export=True)
|
|
snapshot_id = found_id
|
|
applied_note = note
|
|
if note:
|
|
logger.info(note)
|
|
|
|
df_scud = load_scud_from_db_by_snapshot(date_clean, snapshot_param=snapshot_id)
|
|
if df_scud is None or df_scud.empty:
|
|
return {
|
|
"status": "error",
|
|
"message": f"Срез СКУД за {date_clean} ({applied_note or snapshot_id or 'последний доступный'}) не найден в базе."
|
|
}
|
|
|
|
df_staff, df_abs = load_1c_files_for_date(date_clean)
|
|
|
|
df_merged = merge_scud_and_1c(df_scud, df_staff, df_abs)
|
|
metrics = calculate_summary_metrics(df_merged)
|
|
anomalies = detect_registry_anomalies(df_merged, df_raw_scud=df_scud)
|
|
|
|
# Добавляем суффикс времени в имя файла, если сводка строилась на точный срез
|
|
time_suffix = f" на {target_time.replace(':', '-')}" if target_time else ""
|
|
filename = f"{format_date_ru(date_clean)} сводка{time_suffix}.xlsx"
|
|
generate_summary_excel(df_merged, date_str=date_clean, filename=filename)
|
|
|
|
target_dir = get_dated_reports_dir(date_clean)
|
|
full_filepath = os.path.join(target_dir, filename)
|
|
|
|
return {
|
|
"status": "success",
|
|
"report_type": "SVODKA",
|
|
"date": date_clean,
|
|
"target_time": target_time,
|
|
"snapshot_id": snapshot_id or "AUTO_LATEST",
|
|
"filename": filename,
|
|
"filepath": full_filepath,
|
|
"download_url": f"/api/v1/files/download/reports/{os.path.basename(full_filepath)}",
|
|
"metrics": metrics,
|
|
"anomalies_count": len(anomalies),
|
|
"note": applied_note,
|
|
"message": f"Ежедневная сводка на {date_clean} {target_time or ''} успешно сформирована."
|
|
} |