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