/
AIConnection
/
exel_diff
Обзор
Документация
Войти
/
AIConnection
/
exel_diff
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
app/main.py
150 строк
7 KB
19123130
init
23 мар 2026, 11:04
23 мар 2026, 11:04
b9f2169
Код
Авторство
О чём код?
import os import pandas as pd from datetime import datetime from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates import shutil from pathlib import Path app = FastAPI(title="Excel Diff Tool") # Создаем директории UPLOAD_DIR = Path("files") EXPORT_DIR = Path("export") UPLOAD_DIR.mkdir(exist_ok=True) EXPORT_DIR.mkdir(exist_ok=True) # Монтируем статические файлы и шаблоны app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") # Пути к файлам BD_LOAD_PATH = UPLOAD_DIR / "bd_load.txt" REESTR_PATH = UPLOAD_DIR / "reestr.xlsx" EXPORT_PATH = EXPORT_DIR / "result.xlsx" def load_bd_data(): """Загрузка данных из выгрузки БД""" # Загружаем данные из txt файла bd_df = pd.read_csv(BD_LOAD_PATH, sep='|') # Удаляем пустые колонки, которые могли появиться из-за лишних разделителей bd_df = bd_df.dropna(axis=1, how='all') # Убираем лишние пробелы из названий колонок bd_df.columns = bd_df.columns.str.strip() # Оставляем только нужные колонки bd_df = bd_df[['sequence_id', 'state', 'creation_date_time']] # Преобразуем дату, оставляя только дату без времени # Удаляем лишние строки с чертами bd_df = bd_df[bd_df['creation_date_time'].str.contains('------------------------') == False] # Преобразуем дату к строке в формате YYYY-MM-DD bd_df['creation_date'] = pd.to_datetime(bd_df['creation_date_time']).dt.strftime('%Y-%m-%d') # Переименовываем колонки для удобства сравнения bd_df = bd_df.rename(columns={'sequence_id': 'Исходящий номер документа', 'creation_date': 'Дата документа'}) return bd_df def load_reestr_data(): """Загрузка данных из реестра""" # Загружаем данные из xlsx файла reestr_df = pd.read_excel(REESTR_PATH) # Оставляем только нужные колонки reestr_df = reestr_df[['Исходящий номер документа', 'Дата документа']] # Преобразуем дату, если она в формате datetime if reestr_df['Дата документа'].dtype == 'datetime64[ns]': reestr_df['Дата документа'] = reestr_df['Дата документа'].dt.date # Приводим значения Исходящий номер документа к строковому типу и удаляем пробелы reestr_df['Исходящий номер документа'] = reestr_df['Исходящий номер документа'].astype("str").str.strip() return reestr_df def compare_data(bd_df, reestr_df): """Сравнение данных из БД и реестра""" # Создаем копию данных из БД для результата result_df = bd_df.copy() # Приводим значения Исходящий номер документа к строковому типу и удаляем пробелы # Удаляем ведущие нули из номера документа result_df['Исходящий номер документа'] = result_df['Исходящий номер документа'].astype("str").str.strip().str.lstrip('0') # Создаем множество пар (Исходящий номер документа, Дата документа) из реестра reestr_pairs = set() for _, row in reestr_df.iterrows(): doc_num = str(row['Исходящий номер документа']).strip() doc_date = row['Дата документа'] # Преобразуем дату к строке для сравнения if pd.notna(doc_date): doc_date = str(doc_date.date()) if hasattr(doc_date, 'date') else str(doc_date) # Удаляем ведущие нули из номера документа doc_num = doc_num.lstrip('0') reestr_pairs.add((doc_num, doc_date)) # Проверяем наличие каждой пары из БД в реестре result_df['В Реестре'] = result_df.apply( lambda row: 'Да' if (row['Исходящий номер документа'], row['Дата документа']) in reestr_pairs else 'Нет', axis=1 ) return result_df @app.get("/") async def get_form(): """Отображение формы для загрузки файлов""" return templates.TemplateResponse("form.html", {"request": {}}) @app.post("/compare/") async def compare_files( bd_file: UploadFile = File(..., description="Выгрузка из БД (TXT)"), reestr_file: UploadFile = File(..., description="Реестр (XLSX)") ): """Обработка загруженных файлов и сравнение данных""" # Проверка форматов файлов if not bd_file.filename.endswith('.txt'): raise HTTPException(status_code=400, detail="Файл выгрузки БД должен быть в формате TXT") if not reestr_file.filename.endswith('.xlsx'): raise HTTPException(status_code=400, detail="Файл реестра должен быть в формате XLSX") # Сохраняем загруженные файлы try: # Сохраняем выгрузку БД with open(BD_LOAD_PATH, "wb") as buffer: shutil.copyfileobj(bd_file.file, buffer) # Сохраняем реестр with open(REESTR_PATH, "wb") as buffer: shutil.copyfileobj(reestr_file.file, buffer) # Загружаем данные bd_data = load_bd_data() reestr_data = load_reestr_data() # Сравниваем данные result = compare_data(bd_data, reestr_data) # Сохраняем результат result.to_excel(EXPORT_PATH, index=False) # Возвращаем файл для скачивания return FileResponse( path=EXPORT_PATH, filename="result.xlsx", media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) except Exception as e: raise HTTPException(status_code=500, detail=f"Ошибка при обработке файлов: {str(e)}")