Основа для логгера
This commit is contained in:
@@ -6,10 +6,14 @@ import json
|
|||||||
import zipfile
|
import zipfile
|
||||||
import tempfile
|
import tempfile
|
||||||
import shutil
|
import shutil
|
||||||
|
import logging
|
||||||
from typing import Dict, Any, List, Optional
|
from typing import Dict, Any, List, Optional
|
||||||
from core.ports import ParserPort
|
from core.ports import ParserPort
|
||||||
from adapters.pconfig import SINGLE_OGS, replace_id_in_path, find_header_row, data_to_json
|
from adapters.pconfig import SINGLE_OGS, replace_id_in_path, find_header_row, data_to_json
|
||||||
|
|
||||||
|
# Настройка логгера для модуля
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SvodkaPMParser(ParserPort):
|
class SvodkaPMParser(ParserPort):
|
||||||
"""Парсер для сводок ПМ (план и факт)"""
|
"""Парсер для сводок ПМ (план и факт)"""
|
||||||
@@ -51,17 +55,17 @@ class SvodkaPMParser(ParserPort):
|
|||||||
# Разархивируем файл
|
# Разархивируем файл
|
||||||
with zipfile.ZipFile(file_path, 'r') as zip_ref:
|
with zipfile.ZipFile(file_path, 'r') as zip_ref:
|
||||||
zip_ref.extractall(temp_dir)
|
zip_ref.extractall(temp_dir)
|
||||||
print(f"📦 Архив разархивирован в: {temp_dir}")
|
logger.info(f"📦 Архив разархивирован в: {temp_dir}")
|
||||||
|
|
||||||
# Посмотрим, что находится в архиве
|
# Посмотрим, что находится в архиве
|
||||||
print(f"🔍 Содержимое архива:")
|
logger.debug(f"🔍 Содержимое архива:")
|
||||||
for root, dirs, files in os.walk(temp_dir):
|
for root, dirs, files in os.walk(temp_dir):
|
||||||
level = root.replace(temp_dir, '').count(os.sep)
|
level = root.replace(temp_dir, '').count(os.sep)
|
||||||
indent = ' ' * 2 * level
|
indent = ' ' * 2 * level
|
||||||
print(f"{indent}{os.path.basename(root)}/")
|
logger.debug(f"{indent}{os.path.basename(root)}/")
|
||||||
subindent = ' ' * 2 * (level + 1)
|
subindent = ' ' * 2 * (level + 1)
|
||||||
for file in files:
|
for file in files:
|
||||||
print(f"{subindent}{file}")
|
logger.debug(f"{subindent}{file}")
|
||||||
|
|
||||||
# Создаем словари для хранения данных как в оригинале
|
# Создаем словари для хранения данных как в оригинале
|
||||||
df_pm_facts = {} # Словарь с данными факта, ключ - ID ОГ
|
df_pm_facts = {} # Словарь с данными факта, ключ - ID ОГ
|
||||||
@@ -80,8 +84,8 @@ class SvodkaPMParser(ParserPort):
|
|||||||
elif 'plan' in file.lower() or 'план' in file.lower():
|
elif 'plan' in file.lower() or 'план' in file.lower():
|
||||||
plan_files.append(full_path)
|
plan_files.append(full_path)
|
||||||
|
|
||||||
print(f"📊 Найдено файлов факта: {len(fact_files)}")
|
logger.info(f"📊 Найдено файлов факта: {len(fact_files)}")
|
||||||
print(f"📊 Найдено файлов плана: {len(plan_files)}")
|
logger.info(f"📊 Найдено файлов плана: {len(plan_files)}")
|
||||||
|
|
||||||
# Обрабатываем найденные файлы
|
# Обрабатываем найденные файлы
|
||||||
for fact_file in fact_files:
|
for fact_file in fact_files:
|
||||||
@@ -91,9 +95,9 @@ class SvodkaPMParser(ParserPort):
|
|||||||
if 'svodka_fact_pm_' in filename:
|
if 'svodka_fact_pm_' in filename:
|
||||||
og_id = filename.replace('svodka_fact_pm_', '').replace('.xlsx', '').replace('.xlsm', '')
|
og_id = filename.replace('svodka_fact_pm_', '').replace('.xlsx', '').replace('.xlsm', '')
|
||||||
if og_id in SINGLE_OGS:
|
if og_id in SINGLE_OGS:
|
||||||
print(f'📊 Загрузка факта: {fact_file} (ОГ: {og_id})')
|
logger.info(f'📊 Загрузка факта: {fact_file} (ОГ: {og_id})')
|
||||||
df_pm_facts[og_id] = self._parse_svodka_pm(fact_file, 'Сводка Нефтепереработка')
|
df_pm_facts[og_id] = self._parse_svodka_pm(fact_file, 'Сводка Нефтепереработка')
|
||||||
print(f"✅ Факт загружен для {og_id}")
|
logger.info(f"✅ Факт загружен для {og_id}")
|
||||||
|
|
||||||
for plan_file in plan_files:
|
for plan_file in plan_files:
|
||||||
# Извлекаем ID ОГ из имени файла
|
# Извлекаем ID ОГ из имени файла
|
||||||
@@ -102,9 +106,9 @@ class SvodkaPMParser(ParserPort):
|
|||||||
if 'svodka_plan_pm_' in filename:
|
if 'svodka_plan_pm_' in filename:
|
||||||
og_id = filename.replace('svodka_plan_pm_', '').replace('.xlsx', '').replace('.xlsm', '')
|
og_id = filename.replace('svodka_plan_pm_', '').replace('.xlsx', '').replace('.xlsm', '')
|
||||||
if og_id in SINGLE_OGS:
|
if og_id in SINGLE_OGS:
|
||||||
print(f'📊 Загрузка плана: {plan_file} (ОГ: {og_id})')
|
logger.info(f'📊 Загрузка плана: {plan_file} (ОГ: {og_id})')
|
||||||
df_pm_plans[og_id] = self._parse_svodka_pm(plan_file, 'Сводка Нефтепереработка')
|
df_pm_plans[og_id] = self._parse_svodka_pm(plan_file, 'Сводка Нефтепереработка')
|
||||||
print(f"✅ План загружен для {og_id}")
|
logger.info(f"✅ План загружен для {og_id}")
|
||||||
|
|
||||||
# Инициализируем None для ОГ, для которых файлы не найдены
|
# Инициализируем None для ОГ, для которых файлы не найдены
|
||||||
for og_id in SINGLE_OGS:
|
for og_id in SINGLE_OGS:
|
||||||
@@ -123,14 +127,14 @@ class SvodkaPMParser(ParserPort):
|
|||||||
'df_pm_plans': df_pm_plans
|
'df_pm_plans': df_pm_plans
|
||||||
}
|
}
|
||||||
|
|
||||||
print(f"🎯 Обработано ОГ: {len([k for k, v in df_pm_facts.items() if v is not None])} факт, {len([k for k, v in df_pm_plans.items() if v is not None])} план")
|
logger.info(f"🎯 Обработано ОГ: {len([k for k, v in df_pm_facts.items() if v is not None])} факт, {len([k for k, v in df_pm_plans.items() if v is not None])} план")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# Удаляем временную директорию
|
# Удаляем временную директорию
|
||||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||||
print(f"🗑️ Временная директория удалена: {temp_dir}")
|
logger.debug(f"🗑️ Временная директория удалена: {temp_dir}")
|
||||||
|
|
||||||
def _parse_svodka_pm(self, file_path: str, sheet_name: str, header_num: Optional[int] = None) -> pd.DataFrame:
|
def _parse_svodka_pm(self, file_path: str, sheet_name: str, header_num: Optional[int] = None) -> pd.DataFrame:
|
||||||
"""Парсинг отчетов одного ОГ для БП, ПП и факта"""
|
"""Парсинг отчетов одного ОГ для БП, ПП и факта"""
|
||||||
@@ -226,19 +230,19 @@ class SvodkaPMParser(ParserPort):
|
|||||||
|
|
||||||
def _get_svodka_value(self, df_svodka: pd.DataFrame, og_id: str, code: int, search_value: Optional[str] = None):
|
def _get_svodka_value(self, df_svodka: pd.DataFrame, og_id: str, code: int, search_value: Optional[str] = None):
|
||||||
"""Служебная функция для простой выборке по сводке"""
|
"""Служебная функция для простой выборке по сводке"""
|
||||||
print(f"🔍 DEBUG: Ищем код '{code}' для ОГ '{og_id}' в DataFrame с {len(df_svodka)} строками")
|
logger.debug(f"🔍 DEBUG: Ищем код '{code}' для ОГ '{og_id}' в DataFrame с {len(df_svodka)} строками")
|
||||||
print(f"🔍 DEBUG: Первая строка данных: {df_svodka.iloc[0].tolist()}")
|
logger.debug(f"🔍 DEBUG: Первая строка данных: {df_svodka.iloc[0].tolist()}")
|
||||||
print(f"🔍 DEBUG: Доступные индексы: {list(df_svodka.index)}")
|
logger.debug(f"🔍 DEBUG: Доступные индексы: {list(df_svodka.index)}")
|
||||||
print(f"🔍 DEBUG: Доступные столбцы: {list(df_svodka.columns)}")
|
logger.debug(f"🔍 DEBUG: Доступные столбцы: {list(df_svodka.columns)}")
|
||||||
|
|
||||||
# Проверяем, есть ли код в индексе
|
# Проверяем, есть ли код в индексе
|
||||||
if code not in df_svodka.index:
|
if code not in df_svodka.index:
|
||||||
print(f"⚠️ Код '{code}' не найден в индексе")
|
logger.warning(f"⚠️ Код '{code}' не найден в индексе")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Получаем позицию строки с кодом
|
# Получаем позицию строки с кодом
|
||||||
code_row_loc = df_svodka.index.get_loc(code)
|
code_row_loc = df_svodka.index.get_loc(code)
|
||||||
print(f"🔍 DEBUG: Код '{code}' в позиции {code_row_loc}")
|
logger.debug(f"🔍 DEBUG: Код '{code}' в позиции {code_row_loc}")
|
||||||
|
|
||||||
# Определяем позиции для поиска
|
# Определяем позиции для поиска
|
||||||
if search_value is None:
|
if search_value is None:
|
||||||
@@ -254,14 +258,14 @@ class SvodkaPMParser(ParserPort):
|
|||||||
if col_name == search_value:
|
if col_name == search_value:
|
||||||
target_positions.append(i)
|
target_positions.append(i)
|
||||||
|
|
||||||
print(f"🔍 DEBUG: Найдены позиции для '{search_value}': {target_positions[:5]}...")
|
logger.debug(f"🔍 DEBUG: Найдены позиции для '{search_value}': {target_positions[:5]}...")
|
||||||
print(f"🔍 DEBUG: Позиции в первой строке: {target_positions[:5]}...")
|
logger.debug(f"🔍 DEBUG: Позиции в первой строке: {target_positions[:5]}...")
|
||||||
|
|
||||||
print(f"🔍 DEBUG: Ищем столбцы с названием '{search_value}'")
|
logger.debug(f"🔍 DEBUG: Ищем столбцы с названием '{search_value}'")
|
||||||
print(f"🔍 DEBUG: Целевые позиции: {target_positions[:10]}...")
|
logger.debug(f"🔍 DEBUG: Целевые позиции: {target_positions[:10]}...")
|
||||||
|
|
||||||
if not target_positions:
|
if not target_positions:
|
||||||
print(f"⚠️ Позиции '{search_value}' не найдены")
|
logger.warning(f"⚠️ Позиции '{search_value}' не найдены")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Извлекаем значения из найденных позиций
|
# Извлекаем значения из найденных позиций
|
||||||
@@ -285,7 +289,7 @@ class SvodkaPMParser(ParserPort):
|
|||||||
|
|
||||||
# Преобразуем в числовой формат
|
# Преобразуем в числовой формат
|
||||||
numeric_values = pd.to_numeric(values, errors='coerce')
|
numeric_values = pd.to_numeric(values, errors='coerce')
|
||||||
print(f"🔍 DEBUG: Числовые значения (первые 5): {numeric_values.tolist()[:5]}")
|
logger.debug(f"🔍 DEBUG: Числовые значения (первые 5): {numeric_values.tolist()[:5]}")
|
||||||
|
|
||||||
# Попробуем альтернативное преобразование
|
# Попробуем альтернативное преобразование
|
||||||
try:
|
try:
|
||||||
@@ -301,10 +305,10 @@ class SvodkaPMParser(ParserPort):
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
manual_values.append(0)
|
manual_values.append(0)
|
||||||
|
|
||||||
print(f"🔍 DEBUG: Ручное преобразование (первые 5): {manual_values[:5]}")
|
logger.debug(f"🔍 DEBUG: Ручное преобразование (первые 5): {manual_values[:5]}")
|
||||||
numeric_values = pd.Series(manual_values)
|
numeric_values = pd.Series(manual_values)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"⚠️ Ошибка при ручном преобразовании: {e}")
|
logger.warning(f"⚠️ Ошибка при ручном преобразовании: {e}")
|
||||||
# Используем исходные значения
|
# Используем исходные значения
|
||||||
numeric_values = pd.Series([0 if pd.isna(v) or v is None else v for v in values])
|
numeric_values = pd.Series([0 if pd.isna(v) or v is None else v for v in values])
|
||||||
|
|
||||||
@@ -338,7 +342,7 @@ class SvodkaPMParser(ParserPort):
|
|||||||
|
|
||||||
# Получаем данные из сохраненных словарей (через self.df)
|
# Получаем данные из сохраненных словарей (через self.df)
|
||||||
if not hasattr(self, 'df') or self.df is None:
|
if not hasattr(self, 'df') or self.df is None:
|
||||||
print("❌ Данные не загружены. Сначала загрузите ZIP архив.")
|
logger.error("❌ Данные не загружены. Сначала загрузите ZIP архив.")
|
||||||
return {col: {str(code): None for code in codes} for col in columns}
|
return {col: {str(code): None for code in codes} for col in columns}
|
||||||
|
|
||||||
# Извлекаем словари из сохраненных данных
|
# Извлекаем словари из сохраненных данных
|
||||||
@@ -349,10 +353,10 @@ class SvodkaPMParser(ParserPort):
|
|||||||
fact_df = df_pm_facts.get(og_id)
|
fact_df = df_pm_facts.get(og_id)
|
||||||
plan_df = df_pm_plans.get(og_id)
|
plan_df = df_pm_plans.get(og_id)
|
||||||
|
|
||||||
print(f"🔍 ===== НАЧАЛО ОБРАБОТКИ ОГ {og_id} =====")
|
logger.debug(f"🔍 ===== НАЧАЛО ОБРАБОТКИ ОГ {og_id} =====")
|
||||||
print(f"🔍 Коды: {codes}")
|
logger.debug(f"🔍 Коды: {codes}")
|
||||||
print(f"🔍 Столбцы: {columns}")
|
logger.debug(f"🔍 Столбцы: {columns}")
|
||||||
print(f"🔍 Получены данные для {og_id}: факт={'✅' if fact_df is not None else '❌'}, план={'✅' if plan_df is not None else '❌'}")
|
logger.debug(f"🔍 Получены данные для {og_id}: факт={'✅' if fact_df is not None else '❌'}, план={'✅' if plan_df is not None else '❌'}")
|
||||||
|
|
||||||
# Определяем, какие столбцы из какого датафрейма брать
|
# Определяем, какие столбцы из какого датафрейма брать
|
||||||
for col in columns:
|
for col in columns:
|
||||||
@@ -360,24 +364,24 @@ class SvodkaPMParser(ParserPort):
|
|||||||
|
|
||||||
if col in ['ПП', 'БП']:
|
if col in ['ПП', 'БП']:
|
||||||
if plan_df is None:
|
if plan_df is None:
|
||||||
print(f"❌ Невозможно обработать '{col}': нет данных плана для {og_id}")
|
logger.warning(f"❌ Невозможно обработать '{col}': нет данных плана для {og_id}")
|
||||||
else:
|
else:
|
||||||
print(f"🔍 DEBUG: ===== ОБРАБАТЫВАЕМ '{col}' ИЗ ДАННЫХ ПЛАНА =====")
|
logger.debug(f"🔍 DEBUG: ===== ОБРАБАТЫВАЕМ '{col}' ИЗ ДАННЫХ ПЛАНА =====")
|
||||||
for code in codes:
|
for code in codes:
|
||||||
print(f"🔍 DEBUG: --- Код {code} для {col} ---")
|
logger.debug(f"🔍 DEBUG: --- Код {code} для {col} ---")
|
||||||
val = self._get_svodka_value(plan_df, og_id, code, col)
|
val = self._get_svodka_value(plan_df, og_id, code, col)
|
||||||
col_result[str(code)] = val
|
col_result[str(code)] = val
|
||||||
print(f"🔍 DEBUG: ===== ЗАВЕРШИЛИ ОБРАБОТКУ '{col}' =====")
|
logger.debug(f"🔍 DEBUG: ===== ЗАВЕРШИЛИ ОБРАБОТКУ '{col}' =====")
|
||||||
|
|
||||||
elif col in ['ТБ', 'СЭБ', 'НЭБ']:
|
elif col in ['ТБ', 'СЭБ', 'НЭБ']:
|
||||||
if fact_df is None:
|
if fact_df is None:
|
||||||
print(f"❌ Невозможно обработать '{col}': нет данных факта для {og_id}")
|
logger.warning(f"❌ Невозможно обработать '{col}': нет данных факта для {og_id}")
|
||||||
else:
|
else:
|
||||||
for code in codes:
|
for code in codes:
|
||||||
val = self._get_svodka_value(fact_df, og_id, code, col)
|
val = self._get_svodka_value(fact_df, og_id, code, col)
|
||||||
col_result[str(code)] = val
|
col_result[str(code)] = val
|
||||||
else:
|
else:
|
||||||
print(f"⚠️ Неизвестный столбец: '{col}'. Пропускаем.")
|
logger.warning(f"⚠️ Неизвестный столбец: '{col}'. Пропускаем.")
|
||||||
col_result = {str(code): None for code in codes}
|
col_result = {str(code): None for code in codes}
|
||||||
|
|
||||||
result[col] = col_result
|
result[col] = col_result
|
||||||
@@ -443,7 +447,7 @@ class SvodkaPMParser(ParserPort):
|
|||||||
data = self._get_svodka_og(og_id, codes, columns, search)
|
data = self._get_svodka_og(og_id, codes, columns, search)
|
||||||
total_result[og_id] = data
|
total_result[og_id] = data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Ошибка при обработке {og_id}: {e}")
|
logger.error(f"❌ Ошибка при обработке {og_id}: {e}")
|
||||||
total_result[og_id] = None
|
total_result[og_id] = None
|
||||||
|
|
||||||
json_result = data_to_json(total_result)
|
json_result = data_to_json(total_result)
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
import os
|
import os
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
import logging
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
from fastapi import FastAPI, File, UploadFile, HTTPException, status
|
from fastapi import FastAPI, File, UploadFile, HTTPException, status
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
# Настройка логирования
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(name)s - %(lineno)d - %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
|
)
|
||||||
|
|
||||||
from adapters.storage import MinIOStorageAdapter
|
from adapters.storage import MinIOStorageAdapter
|
||||||
from adapters.parsers import SvodkaPMParser, SvodkaCAParser, MonitoringFuelParser, MonitoringTarParser, SvodkaRepairCAParser, StatusesRepairCAParser, OperSpravkaTechPosParser
|
from adapters.parsers import SvodkaPMParser, SvodkaCAParser, MonitoringFuelParser, MonitoringTarParser, SvodkaRepairCAParser, StatusesRepairCAParser, OperSpravkaTechPosParser
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user