Перед тем, как исправлять выгрузку скуд с глупым Gemini-Lite
This commit is contained in:
+56
-69
@@ -2,92 +2,79 @@
|
||||
===============================================================================
|
||||
FILE: main_etl.py
|
||||
PROJECT: SCUD Orion AI (Unified Architecture)
|
||||
ROLE: Главная CLI-точка входа для запуска ежедневного контроллинга СКУД ⟷ 1С.
|
||||
|
||||
AI-CONTEXT-ANCHORS:
|
||||
- ANCHOR[MAIN_CLI_ENTRY]: Парсинг CLI-флагов и запуск конвейера.
|
||||
ROLE: Главная точка входа ETL-конвейера СКУД ⟷ 1С:ЗУП.
|
||||
===============================================================================
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
from core.database import init_db, get_latest_snapshot_time
|
||||
from services.share_copier import copy_1c_files_from_share
|
||||
from services.data_validator import check_file_freshness
|
||||
from services.scud_export import run_export
|
||||
from services.scud_etl.pipeline import run_controlling_pipeline
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
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, calculate_summary_metrics
|
||||
from services.scud_etl.anomaly_detector import detect_registry_anomalies
|
||||
from services.text_reporter.service import format_controlling_summary_markdown
|
||||
|
||||
# Корректные импорты из папки services/
|
||||
from services.scud_export import run_scud_export_today_and_yesterday
|
||||
from services.share_copier import sync_1c_files_from_share
|
||||
from services.excel_exporter import build_daily_summary_excel, build_detailed_yesterday_excel
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] %(message)s")
|
||||
|
||||
|
||||
# ANCHOR[MAIN_CLI_ENTRY]
|
||||
def main():
|
||||
help_text = """
|
||||
Система автоматизированного контроллинга СКУД ⟷ 1С:ЗУП (scud_orion_ai)
|
||||
|
||||
ПРИМЕРЫ ЗАПУСКА:
|
||||
python main_etl.py -- Обычный дневной запуск
|
||||
python main_etl.py --skip-export -- Расчет отчета по ПОСЛЕДНЕМУ имеющемуся снапшоту из SQLite
|
||||
python main_etl.py --snapshot 20260820-001 -- Расчет отчета строго по ID снапшота
|
||||
python main_etl.py -d -- Запуск в режиме расширенной отладки (DEBUG)
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=help_text, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument('-d', '--debug', action='store_true', help="Режим отладки (DEBUG)")
|
||||
parser.add_argument('--skip-export', action='store_true', help="Расчет отчета по последнему снапшоту из SQLite")
|
||||
parser.add_argument('--snapshot', type=str, default=None, help="ID конкретного снапшота")
|
||||
|
||||
args = parser.parse_args()
|
||||
print("=" * 60)
|
||||
print(f"ЗАПУСК СИСТЕМЫ МОДУЛЬНОГО КОНТРОЛЛИНГА СКУД ⟷ 1С {'[DEBUG MODE]' if args.debug else ''}")
|
||||
print("ЗАПУСК СИСТЕМЫ МОДУЛЬНОГО КОНТРОЛЛИНГА СКУД ⟷ 1С")
|
||||
print("=" * 60)
|
||||
|
||||
init_db()
|
||||
now = datetime.now()
|
||||
today_str = now.strftime("%d.%m.%Y")
|
||||
yesterday_str = (now - timedelta(days=1)).strftime("%d.%m.%Y")
|
||||
|
||||
# Определение режима работы и вывод статусов
|
||||
if args.snapshot:
|
||||
print(f"[📸] РЕЖИМ СНАПШОТА: Расчет отчета строго по срезу '{args.snapshot}'")
|
||||
elif args.skip_export:
|
||||
last_snap = get_latest_snapshot_time()
|
||||
print(f"[📸] РЕЖИМ --skip-export: Используем последний снапшот из SQLite ('{last_snap}')")
|
||||
else:
|
||||
current_snap = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
print(f"[📸] СФОРМИРОВАН НОВЫЙ СНАПШОТ: '{current_snap}'")
|
||||
# [Этап 0] Выгрузка свежих данных СКУД
|
||||
print(f"\n[0/5] Экспорт данных СКУД за {today_str} и {yesterday_str}...")
|
||||
run_scud_export_today_and_yesterday()
|
||||
|
||||
has_today_1c = True
|
||||
# [Этап 0.5] Синхронизация файлов с шары 1С
|
||||
print(f"\n[0.5/5] Проверка и копирование файлов 1С с шары...")
|
||||
sync_1c_files_from_share()
|
||||
|
||||
# Прямой экспорт и проверка сетевой шары (если не режим снапшотов)
|
||||
if not args.skip_export and not args.snapshot:
|
||||
try:
|
||||
run_export(save_xlsx=True, debug=args.debug)
|
||||
except Exception as e:
|
||||
print(f"[⚠️] Ошибка автоэкспорта из MS SQL: {e}. Переходим к записям SQLite.")
|
||||
# [Этап 1-2] Загрузка данных
|
||||
print(f"\n[1-2/5] Загрузка срезов: Сегодня = {today_str}, Накануне = {yesterday_str}...")
|
||||
df_scud_yesterday = load_best_snapshot_for_date(yesterday_str, prefer_final_y=True)
|
||||
df_scud_today = load_best_snapshot_for_date(today_str, prefer_final_y=False)
|
||||
|
||||
copy_1c_files_from_share()
|
||||
print("[1/5] Проверка актуальности и свежести входных данных...")
|
||||
is_valid, warnings, errors, has_today_1c = check_file_freshness()
|
||||
df_staff_yesterday, df_abs_yesterday = load_1c_files_for_date(yesterday_str)
|
||||
df_staff_today, df_abs_today = load_1c_files_for_date(today_str)
|
||||
|
||||
if warnings:
|
||||
print("\n--- ⚠️ ПРЕДУПРЕЖДЕНИЯ ОБ АКТУАЛЬНОСТИ ---")
|
||||
for w in warnings:
|
||||
print(f" • {w}")
|
||||
print("-" * 45)
|
||||
# [Этап 3] Детальный отчет за вчера (на базе финального Y-снапшота)
|
||||
print(f"\n[3/5] Обработка и построение детального отчета за ВЧЕРА ({yesterday_str})...")
|
||||
df_merged_yesterday = merge_scud_and_1c(df_scud_yesterday, df_staff_yesterday, df_abs_yesterday)
|
||||
build_detailed_yesterday_excel(df_merged_yesterday, yesterday_str)
|
||||
|
||||
if not is_valid:
|
||||
print("🛑 ОСТАНОВКА: Отсутствуют критически важные файлы за вчера!")
|
||||
for e in errors:
|
||||
print(f" {e}")
|
||||
sys.exit(1)
|
||||
print("[✓] Проверка доступности данных успешно пройдена!\n")
|
||||
else:
|
||||
print("[0/5] Пропуск прямого экспорта из MS SQL (чтение из базы SQLite)...")
|
||||
print("[1/5] Пропуск проверки сетевой шары (все данные читаются из SQLite)...")
|
||||
# [Этап 4] Сводка за сегодня
|
||||
print(f"\n[4/5] Обработка и построение Ежедневной сводки за {today_str}...")
|
||||
df_merged_today = merge_scud_and_1c(df_scud_today, df_staff_today, df_abs_today)
|
||||
metrics_today = calculate_summary_metrics(df_merged_today)
|
||||
anomalies_today = detect_registry_anomalies(df_merged_today)
|
||||
build_daily_summary_excel(df_merged_today, metrics_today, today_str)
|
||||
|
||||
# Запуск конвейера
|
||||
run_controlling_pipeline(
|
||||
snapshot_param=args.snapshot,
|
||||
skip_export=args.skip_export,
|
||||
debug=args.debug,
|
||||
has_today_1c=has_today_1c
|
||||
)
|
||||
# [Этап 5] Формирование текстового отчета и вывод в консоль
|
||||
print(f"\n[5/5] Формирование Markdown-сводки...")
|
||||
summary_md = format_controlling_summary_markdown(today_str, metrics_today, anomalies_today)
|
||||
|
||||
os.makedirs("output", exist_ok=True)
|
||||
md_file_path = f"output/Сводка_контроллинга_{today_str}.md"
|
||||
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||
f.write(summary_md)
|
||||
print(f"[✓] Текстовый отчет сохранен в: {md_file_path}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("ГОТОВАЯ ТЕКСТОВАЯ СВОДКА ИИ-АУДИТОРА:")
|
||||
print("=" * 60)
|
||||
print(summary_md)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user