проект теперь работает с использованием локальной базы данных SQLite. Все данные аккумулируются и хранятся в ней. Впереди - разработка веб интерфейса.

This commit is contained in:
2026-08-03 12:59:23 +03:00
parent d39618c891
commit 0efbe4ff99
14 changed files with 976 additions and 300 deletions
+29 -19
View File
@@ -1,5 +1,5 @@
"""
Модуль автоматического экспорта данных СКУД (Orion) из MS SQL Server в Excel.
Модуль автоматического экспорта данных СКУД (Orion) из MS SQL Server в SQLite и Excel.
Исправлена логика определения направления проходов (Mode = 2 -> OUT).
"""
@@ -14,7 +14,8 @@ import pandas as pd
import pyodbc
from openpyxl.utils import get_column_letter
from config import SCUD_DIR
from config import SCUD_DIR, clean_scud_fio_light, load_exceptions
from modules.database import save_scud_to_db
warnings.filterwarnings("ignore", message="pandas only supports SQLAlchemy connectable")
@@ -64,7 +65,6 @@ DECLARE @TargetDate DATE = @InputDate;
DECLARE @StartDate DATETIME = CAST(@TargetDate AS DATETIME);
DECLARE @EndDate DATETIME = DATEADD(SECOND, -1, DATEADD(DAY, 1, @StartDate));
-- 1. Фильтруем логи только за нужные 24 часа с ПРАВИЛЬНЫМ ПРИОРИТЕТОМ ВЫХОДА (Mode = 2)
WITH DailyLogs AS (
SELECT
log.HozOrgan AS EmployeeID,
@@ -83,7 +83,6 @@ WITH DailyLogs AS (
AND log.HozOrgan > 0
AND (log.Event IN (28, 29, 26, 27, 32, 33) OR log.Mode IN (1, 2))
),
-- 2. Агрегируем первичное время входа и последнее время выхода
Passages AS (
SELECT
EmployeeID,
@@ -195,7 +194,7 @@ def get_targets(input_date: str | None):
return targets
def run_export(input_date: str | None = None, debug: bool = False):
def run_export(input_date: str | None = None, save_xlsx: bool = True, debug: bool = False):
if debug:
logger.setLevel(logging.DEBUG)
log("=== ВКЛЮЧЕН РЕЖИМ ОТЛАДКИ (DEBUG MODE) ===", "WARNING")
@@ -223,15 +222,6 @@ def run_export(input_date: str | None = None, debug: bool = False):
log(f"--- Обработка периода: {period_label} ({processing_date_str}) ---")
file_name = f"Сотрудники_{processing_date_str}.xlsx"
file_path = os.path.join(SCUD_DIR, file_name)
if os.path.exists(file_path):
try:
os.remove(file_path)
except OSError as e:
log(f"ОШИБКА при удалении старого файла {file_name}: {e}", "ERROR")
sql_query = SQL_QUERY_TEMPLATE.format(target_date=processing_date.strftime("%Y-%m-%d"))
connection = None
@@ -242,9 +232,28 @@ def run_export(input_date: str | None = None, debug: bool = False):
log(f"База вернула {len(df)} строк за {processing_date_str}")
if len(df) > 0:
df.to_excel(file_path, sheet_name="Отчет", index=False, engine="openpyxl")
auto_fit_columns(file_path, sheet_name="Отчет")
log(f"[✓] Успешно экспортирован файл: data/scud/{file_name}", "SUCCESS")
# 1. Готовим колонки для локальной БД
df['fio_clean'] = df['Сотрудник'].apply(clean_scud_fio_light)
df['Пришел'] = df['Статус'].str.contains('Присутствовал', case=False, na=False)
# 2. ПРЯМОЕ СОХРАНЕНИЕ В SQLite (scud_orion_ai.db)
save_scud_to_db(df, processing_date_str)
log(f"[✓] Записи за {processing_date_str} успешно сохранены в SQLite!", "SUCCESS")
# 3. Сохранение в Excel (если включен флаг save_xlsx)
if save_xlsx:
file_name = f"Сотрудники_{processing_date_str}.xlsx"
file_path = os.path.join(SCUD_DIR, file_name)
if os.path.exists(file_path):
try:
os.remove(file_path)
except OSError as e:
log(f"ОШИБКА при удалении старого файла {file_name}: {e}", "ERROR")
df.to_excel(file_path, sheet_name="Отчет", index=False, engine="openpyxl")
auto_fit_columns(file_path, sheet_name="Отчет")
log(f"[✓] Успешно экспортирован файл: data/scud/{file_name}", "SUCCESS")
else:
log(f"Запрос за {processing_date_str} вернул 0 строк.", "WARNING")
@@ -260,9 +269,10 @@ def run_export(input_date: str | None = None, debug: bool = False):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Экспорт данных СКУД в Excel")
parser = argparse.ArgumentParser(description="Экспорт данных СКУД в SQLite и Excel")
parser.add_argument("--date", dest="input_date", default=None)
parser.add_argument("-d", "--debug", action="store_true")
parser.add_argument("--no-xlsx", dest="save_xlsx", action="store_false", default=True, help="Отключить сохранение в XLSX")
args = parser.parse_args()
run_export(args.input_date, debug=args.debug)
run_export(args.input_date, save_xlsx=args.save_xlsx, debug=args.debug)