Files
hotels/generate_excel_final_correct.py
Фёдор 0cf3297290 Проект аудита отелей: основные скрипты и документация
- Краулеры: smart_crawler.py, regional_crawler.py
- Аудит: audit_orel_to_excel.py, audit_chukotka_to_excel.py
- РКН проверка: check_rkn_registry.py, recheck_unclear_rkn.py
- Отчёты: create_orel_horizontal_report.py
- Обработка: process_all_hotels_embeddings.py
- Документация: README.md, DB_SCHEMA_REFERENCE.md
2025-10-16 10:52:09 +03:00

262 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
ФИНАЛЬНЫЙ Excel генератор с правильной обработкой критериев
"""
import psycopg2
import json
import openpyxl
from openpyxl.styles import Font, PatternFill, Border, Side, Alignment
from openpyxl.utils import get_column_letter
from datetime import datetime
from urllib.parse import unquote
# Конфигурация БД
DB_CONFIG = {
'host': '147.45.189.234',
'port': 5432,
'database': 'default_db',
'user': 'gen_user',
'password': unquote('2~~9_%5EkVsU%3F2%5CS')
}
def get_audit_results_from_db():
"""Получить результаты аудита из БД"""
try:
conn = psycopg2.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("""
SELECT
ar.hotel_id,
hm.full_name,
hm.website_address,
hm.rkn_registry_status,
hm.rkn_registry_number,
hm.rkn_registry_date,
ar.score_percentage,
ar.criteria_results,
hm.created_at
FROM hotel_audit_results ar
JOIN hotel_main hm ON ar.hotel_id = hm.id
WHERE hm.region_name = 'Чукотский автономный округ'
ORDER BY hm.created_at DESC
""")
results = []
for row in cursor.fetchall():
result = {
'hotel_id': row[0],
'full_name': row[1],
'website_address': row[2],
'rkn_registry_status': row[3],
'rkn_registry_number': row[4],
'rkn_registry_date': row[5],
'score_percentage': row[6],
'criteria_results': row[7],
'created_at': row[8]
}
results.append(result)
cursor.close()
conn.close()
return results
except Exception as e:
print(f"❌ Ошибка получения данных: {e}")
return []
def create_excel_report(results):
"""Создать Excel отчёт"""
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Аудит отелей"
# Стили
header_font = Font(size=12, bold=True, color="FFFFFF")
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
found_fill = PatternFill(start_color="C6EFCE", end_color="C6EFCE", fill_type="solid")
not_found_fill = PatternFill(start_color="FFC7CE", end_color="FFC7CE", fill_type="solid")
border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# Базовые заголовки
base_headers = [
'ID отеля', 'Название отеля', 'Сайт', 'Балл (%)', 'Дата аудита'
]
# Добавляем базовые заголовки
for i, header in enumerate(base_headers, 1):
cell = ws.cell(row=1, column=i, value=header)
cell.fill = header_fill
cell.font = header_font
cell.border = border
ws.column_dimensions[get_column_letter(i)].width = 20
col = len(base_headers) + 1
# Заголовки критериев (БЕЗ критерия 6 - РКН)
if results and results[0]['criteria_results']:
criteria_results = results[0]['criteria_results']
if isinstance(criteria_results, dict):
# Сортируем критерии по ключам
sorted_criteria = sorted(criteria_results.items())
for criterion_key, criterion_data in sorted_criteria:
criterion_num = criterion_key.split('_')[1] # извлекаем номер
criterion_id = int(criterion_num)
# Пропускаем критерий 6 (РКН) - он будет отдельно
if criterion_id == 6:
continue
criterion_name = f"{criterion_id}. {criterion_data.get('name', f'Критерий {criterion_id}')}"
# 3 колонки на критерий: Статус, URL, Комментарий
headers = [f"{criterion_name} Статус", f"{criterion_name} URL", f"{criterion_name} Комментарий"]
for header in headers:
cell = ws.cell(row=1, column=col, value=header)
cell.fill = header_fill
cell.font = header_font
cell.border = border
ws.column_dimensions[get_column_letter(col)].width = 30
col += 1
# Добавляем РКН колонки после критерия 5
rkn_headers = ['6. РКН Реестр', '6. РКН Номер/Дата', '6. РКН Ссылка']
for header in rkn_headers:
cell = ws.cell(row=1, column=col, value=header)
cell.fill = header_fill
cell.font = header_font
cell.border = border
ws.column_dimensions[get_column_letter(col)].width = 30
col += 1
print(f"✅ Заголовки созданы, всего колонок: {col-1}")
# Добавляем данные
for row_idx, result in enumerate(results, 2):
col = 1
# Базовые данные
ws.cell(row=row_idx, column=col, value=result['hotel_id']).border = border
col += 1
ws.cell(row=row_idx, column=col, value=result['full_name']).border = border
col += 1
ws.cell(row=row_idx, column=col, value=result['website_address'] or '-').border = border
col += 1
ws.cell(row=row_idx, column=col, value=result['score_percentage']).border = border
col += 1
ws.cell(row=row_idx, column=col, value=str(result['created_at'])[:10]).border = border
col += 1
# Данные критериев
criteria_results = result['criteria_results']
if isinstance(criteria_results, dict):
# Сортируем критерии по ключам
sorted_criteria = sorted(criteria_results.items())
for criterion_key, criterion_data in sorted_criteria:
criterion_num = criterion_key.split('_')[1]
criterion_id = int(criterion_num)
# Пропускаем критерий 6 (РКН) - он будет отдельно
if criterion_id == 6:
continue
# Статус
verdict = criterion_data.get('verdict', 'НЕТ')
status_cell = ws.cell(row=row_idx, column=col, value=verdict)
status_cell.border = border
status_cell.alignment = Alignment(horizontal='center', vertical='center')
if verdict == 'ДА':
status_cell.fill = found_fill
else:
status_cell.fill = not_found_fill
col += 1
# URL
urls = criterion_data.get('approval_urls', [])
url = urls[0] if urls else '-'
ws.cell(row=row_idx, column=col, value=url).border = border
col += 1
# Комментарий
quote = criterion_data.get('quote', '') or ''
comment = quote[:200] + '...' if len(quote) > 200 else quote if quote else "Не найдено"
ws.cell(row=row_idx, column=col, value=comment).border = border
col += 1
# РКН данные из hotel_main
rkn_status = result.get('rkn_registry_status', '')
rkn_in_registry = "ДА" if rkn_status and rkn_status.lower() == 'found' else "НЕТ"
rkn_status_cell = ws.cell(row=row_idx, column=col, value=rkn_in_registry)
rkn_status_cell.border = border
rkn_status_cell.alignment = Alignment(horizontal='center', vertical='center')
if rkn_in_registry == "ДА":
rkn_status_cell.fill = found_fill
else:
rkn_status_cell.fill = not_found_fill
col += 1
rkn_number = result.get('rkn_registry_number', '')
rkn_date = result.get('rkn_registry_date', '')
rkn_info_text = f"{rkn_number}\n{rkn_date}" if rkn_number or rkn_date else "-"
cell = ws.cell(row=row_idx, column=col, value=rkn_info_text)
cell.border = border
cell.alignment = Alignment(vertical='top', wrap_text=True)
col += 1
rkn_url = f"https://rkn.gov.ru/mass-communications/reestr/search/?q={rkn_number}" if rkn_number else "-"
cell = ws.cell(row=row_idx, column=col, value=rkn_url)
cell.border = border
cell.alignment = Alignment(vertical='top')
col += 1
# Высота строки
ws.row_dimensions[row_idx].height = 50
print(f"✅ Данные добавлены, всего строк: {len(results)}")
# Сохраняем файл
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"audit_final_{timestamp}.xlsx"
wb.save(filename)
return filename
def main():
"""Основная функция"""
print("🚀 ГЕНЕРАЦИЯ ФИНАЛЬНОГО EXCEL")
print("=" * 40)
try:
results = get_audit_results_from_db()
if not results:
print("❌ Нет данных для отчёта")
return
print(f"✅ Получено результатов: {len(results)}")
filename = create_excel_report(results)
print(f"✅ Excel отчёт сохранён: {filename}")
print(f"📊 Обработано отелей: {len(results)}")
if results:
avg_score = sum(r['score_percentage'] for r in results) / len(results)
print(f"📈 Средний % соответствия: {avg_score:.1f}%")
except Exception as e:
print(f"❌ Ошибка: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()