full peresobral

This commit is contained in:
2025-07-21 16:59:26 +03:00
parent a6e21a7e59
commit c677e4f8af
11 changed files with 742 additions and 484 deletions

View File

@@ -0,0 +1,153 @@
# database.py
import sqlite3
import logging
# Настройка логирования для модуля БД
log = logging.getLogger(__name__)
class DatabaseManager:
"""
Класс для управления всеми операциями с базой данных SQLite.
Обеспечивает централизованное подключение и выполнение запросов.
"""
def __init__(self, db_path):
self.db_path = db_path
self.conn = None
def __enter__(self):
"""Открывает соединение с БД при входе в контекстный менеджер."""
try:
self.conn = sqlite3.connect(self.db_path)
# Устанавливаем row_factory для получения результатов в виде словарей
self.conn.row_factory = sqlite3.Row
log.info(f"Соединение с БД {self.db_path} установлено.")
return self
except sqlite3.Error as e:
log.error(f"Ошибка подключения к БД: {e}")
raise
def __exit__(self, exc_type, exc_val, exc_tb):
"""Закрывает соединение при выходе из контекстного менеджера."""
if self.conn:
self.conn.close()
log.info("Соединение с БД закрыто.")
def _execute_query(self, query, params=(), fetch=None):
"""
Приватный метод для выполнения SQL-запросов.
Использует параметризацию для предотвращения SQL-инъекций.
:param query: SQL-запрос.
:param params: Кортеж с параметрами для запроса.
:param fetch: 'one', 'all' или None для коммита.
"""
try:
cursor = self.conn.cursor()
cursor.execute(query, params)
if fetch == 'one':
return cursor.fetchone()
elif fetch == 'all':
return cursor.fetchall()
else:
self.conn.commit()
return cursor.lastrowid
except sqlite3.Error as e:
log.error(f"Ошибка выполнения запроса: {query} | {e}")
self.conn.rollback() # Откатываем транзакцию в случае ошибки
raise
def setup_tables(self):
"""Создает все необходимые таблицы, если они не существуют."""
log.info("Проверка и создание таблиц в БД...")
# Таблица для данных с FTP
self._execute_query("""
CREATE TABLE IF NOT EXISTS pos_fiscals (
serialNumber TEXT PRIMARY KEY,
modelName TEXT,
RNM TEXT,
organizationName TEXT,
fn_serial TEXT,
datetime_reg TEXT,
dateTime_end TEXT,
ofdName TEXT,
bootVersion TEXT,
ffdVersion TEXT,
fnExecution TEXT,
INN TEXT,
anydesk_id TEXT,
teamviewer_id TEXT,
lastModifiedDate TEXT
)""")
# Таблица для данных из ServiceDesk
self._execute_query("""
CREATE TABLE IF NOT EXISTS sd_fiscals (
UUID TEXT PRIMARY KEY,
serialNumber TEXT UNIQUE,
modelName TEXT,
RNM TEXT,
organizationName TEXT,
fn_serial TEXT,
datetime_reg TEXT,
dateTime_end TEXT,
ofdName TEXT,
bootVersion TEXT,
ffdVersion TEXT,
owner_uuid TEXT,
lastModifiedDate TEXT
)""")
# Новая таблица для рабочих станций
self._execute_query("""
CREATE TABLE IF NOT EXISTS workstations (
uuid TEXT PRIMARY KEY,
owner_uuid TEXT,
clean_anydesk_id TEXT,
clean_teamviewer_id TEXT
)""")
# Новая таблица для кэширования UUID справочников
self._execute_query("""
CREATE TABLE IF NOT EXISTS sd_lookups (
lookup_type TEXT, -- 'ModelKKT', 'FFD', etc.
title TEXT, -- 'АТОЛ 25Ф', '1.2', etc.
uuid TEXT,
PRIMARY KEY (lookup_type, title)
)""")
log.info("Все таблицы успешно созданы/проверены.")
def clear_tables(self, table_names: list):
"""Очищает указанные таблицы перед каждым циклом синхронизации."""
log.info(f"Очистка таблиц: {', '.join(table_names)}")
for table in table_names:
# Проверяем, что имя таблицы "безопасное"
if table.isalnum():
self._execute_query(f"DELETE FROM {table}")
else:
log.warning(f"Попытка очистить таблицу с некорректным именем: {table}")
def bulk_insert(self, table_name: str, columns: list, data: list):
"""
Выполняет массовую вставку данных в таблицу.
:param table_name: Имя таблицы.
:param columns: Список названий колонок.
:param data: Список кортежей с данными для вставки.
"""
if not data:
return
placeholders = ', '.join(['?'] * len(columns))
cols = ', '.join(columns)
query = f"INSERT OR REPLACE INTO {table_name} ({cols}) VALUES ({placeholders})"
try:
cursor = self.conn.cursor()
cursor.executemany(query, data)
self.conn.commit()
log.info(f"Вставлено {len(data)} записей в таблицу {table_name}.")
except sqlite3.Error as e:
log.error(f"Ошибка массовой вставки в {table_name}: {e}")
self.conn.rollback()
raise