Files
Touchh/bot/utils/pdf_report.py

145 lines
5.8 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.

from fpdf import FPDF
import os
from datetime import datetime
from asgiref.sync import sync_to_async
from django.utils.timezone import make_aware, is_naive, is_aware
import os
# Определение абсолютного пути к папке "reports"
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
REPORTS_DIR = os.path.join(BASE_DIR, "reports")
# Убедитесь, что директория существует
os.makedirs(REPORTS_DIR, exist_ok=True)
# Асинхронная функция для извлечения данных о бронировании
def ensure_datetime(value):
"""Преобразует строку или naive datetime в timezone-aware datetime."""
if isinstance(value, str):
value = datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
if isinstance(value, datetime) and is_naive(value):
value = make_aware(value)
return value
@sync_to_async
def get_reservation_data(res):
print(f"[DEBUG] Processing reservation {res.id}")
# Убедитесь, что даты являются timezone-aware
check_in = ensure_datetime(res.check_in)
check_out = ensure_datetime(res.check_out)
result = {
"hotel_name": res.hotel.name,
"pms": getattr(res.hotel, 'pms', 'N/A'),
"reservation_id": res.reservation_id,
"room_number": res.room_number if res.room_number else "Не указан",
"room_type": res.room_type,
"check_in": check_in,
"check_out": check_out,
"status": res.status,
}
# print(f"[DEBUG] Reservation data: {result}")
return result
class CustomPDF(FPDF):
def __init__(self, hotel_name, start_date, end_date, *args, **kwargs):
super().__init__(*args, **kwargs)
self.font_folder = "bot/fonts/"
self.add_font("DejaVuSans-Bold", "", os.path.join(self.font_folder, "DejaVuSans-Bold.ttf"), uni=True)
self.add_font("DejaVuSans", "", os.path.join(self.font_folder, "DejaVuSans.ttf"), uni=True)
self.creation_date = datetime.now().strftime("%d.%m.%Y %H:%M:%S")
# Переданные параметры
self.hotel_name = hotel_name
self.start_date = start_date
self.end_date = end_date
def header(self):
"""Добавление заголовка и заголовков таблицы на каждой странице."""
# Заголовок отчёта
if self.page == 1: # Заголовок отчёта только на первой странице
self.set_font("DejaVuSans-Bold", size=14)
self.cell(0, 10, f"Отчет о бронированиях отеля {self.hotel_name}", ln=1, align="C")
self.ln(5)
self.set_font("DejaVuSans", size=10)
self.cell(0, 10, f"за период {self.start_date.strftime('%Y-%m-%d %H:%M:%S')} - {self.end_date.strftime('%Y-%m-%d %H:%M:%S')}", ln=1, align="C")
self.ln(10)
# Заголовки таблицы
self.set_font("DejaVuSans-Bold", size=8)
headers = ["Отель", "№ бронирования", "№ комнаты", "Тип комнаты", "Заезд", "Выезд", "Статус"]
col_widths = [30, 30, 30, 60, 35, 35, 30]
row_height = 10
for col_width, header in zip(col_widths, headers):
self.cell(col_width, row_height, header, border=1, align="C")
self.ln()
def footer(self):
"""Добавление колонтитула внизу страницы."""
self.set_y(-15)
self.set_font("DejaVuSans", size=8)
self.cell(60, 10, f"Copyright (C) 2024 by Touchh", align="L")
self.cell(0, 10, f"Лист {self.page_no()} из {{nb}} / Дата генерации отчета: {self.creation_date}", align="C")
def trim_text_right(self, text, max_width):
"""Обрезка текста справа."""
while self.get_string_width(text) > max_width:
text = text[:-1]
return text + "..." if len(text) > 3 else text
async def generate_pdf_report(hotel_name, reservations, start_date, end_date):
# Создание экземпляра PDF с передачей параметров
pdf = CustomPDF(hotel_name=hotel_name, start_date=start_date, end_date=end_date, orientation="L", unit="mm", format="A4")
pdf.alias_nb_pages()
pdf.add_page() # Заголовок отчёта и таблица будут добавлены через методы header и footer
# Таблица
pdf.set_font("DejaVuSans", size=8)
col_widths = [30, 30, 30, 60, 35, 35, 30]
row_height = 10
for res in reservations:
try:
res_data = await get_reservation_data(res)
row_data = [
res_data["hotel_name"],
str(res_data["reservation_id"]),
res_data["room_number"],
res_data["room_type"],
res_data["check_in"].strftime('%Y-%m-%d %H:%M:%S'),
res_data["check_out"].strftime('%Y-%m-%d %H:%M:%S'),
res_data["status"],
]
for col_width, data in zip(col_widths, row_data):
pdf.cell(col_width, row_height, data, border=1, align="C")
pdf.ln()
except Exception as e:
print(f"pdf_report.py [ERROR] Error processing reservation {res.id}: {e}")
# Сохранение PDF
hotel_name_safe = hotel_name.replace(" ", "_").replace("/", "_")
start_date_str = start_date.strftime('%Y-%m-%d')
end_date_str = end_date.strftime('%Y-%m-%d')
pdf_output_path = os.path.join(REPORTS_DIR, f"{hotel_name_safe}_report_{start_date_str}-{end_date_str}.pdf")
pdf.output(pdf_output_path)
if not os.path.exists(pdf_output_path):
raise RuntimeError(f"PDF file was not created at: {pdf_output_path}")
return pdf_output_path