several FontAwesome icons changed.
This commit is contained in:
@@ -11,6 +11,10 @@ from datetime import datetime
|
||||
from django.utils.timezone import make_aware, is_aware, is_naive
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
from touchh.utils.log import CustomLogger
|
||||
|
||||
|
||||
|
||||
|
||||
async def statistics(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -61,106 +65,133 @@ async def stats_select_period(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||
|
||||
|
||||
def ensure_datetime(value):
|
||||
# print(f"statistics.py [DEBUG] ensure_datetime: Received value: {value} ({type(value)})")
|
||||
"""
|
||||
Ensure that the given value is a timezone-aware datetime object.
|
||||
|
||||
If the given value is a string, it is assumed to be in the format
|
||||
'%Y-%m-%d %H:%M:%S'. If the given value is a naive datetime object,
|
||||
it is converted to a timezone-aware datetime object using
|
||||
django.utils.timezone.make_aware.
|
||||
|
||||
:param value: The value to be converted
|
||||
:type value: str or datetime
|
||||
:return: A timezone-aware datetime object
|
||||
:rtype: datetime
|
||||
Преобразует значение в timezone-aware datetime объект, если это возможно.
|
||||
|
||||
:param value: Значение для преобразования
|
||||
:type value: str, datetime или другое
|
||||
:return: 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)
|
||||
# print(f"statistics.py [DEBUG] ensure_datetime: Returning value: {value} ({type(value)})")
|
||||
return value
|
||||
if isinstance(value, datetime):
|
||||
# Если это объект datetime, проверяем, наивен ли он
|
||||
return make_aware(value) if is_naive(value) else value
|
||||
elif isinstance(value, str):
|
||||
# Если это строка, пытаемся преобразовать в datetime
|
||||
try:
|
||||
return make_aware(datetime.strptime(value, '%Y-%m-%d %H:%M:%S'))
|
||||
except ValueError:
|
||||
# Если формат не соответствует, пробуем более общую обработку
|
||||
try:
|
||||
return make_aware(datetime.fromisoformat(value))
|
||||
except ValueError:
|
||||
# Если не получилось распознать формат
|
||||
logging.warning(f"Невозможно преобразовать строку в datetime: {value}")
|
||||
else:
|
||||
# Если тип неизвестен, просто возвращаем None
|
||||
logging.warning(f"Получено значение неизвестного типа для преобразования в datetime: {value}")
|
||||
return None
|
||||
|
||||
# async def generate_statistics(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
# """Генерация и отправка статистики."""
|
||||
# query = update.callback_query
|
||||
# await query.answer()
|
||||
|
||||
# try:
|
||||
# hotel_id = context.user_data.get("selected_hotel")
|
||||
# if not hotel_id:
|
||||
# raise ValueError(f"ID отеля не найден в user_data: {context.user_data}")
|
||||
|
||||
# period = query.data.split("_")[2]
|
||||
# now = ensure_datetime(datetime.utcnow())
|
||||
|
||||
# # Получаем диапазон дат
|
||||
# start_date, end_date = get_period_dates(period, now)
|
||||
|
||||
# reservations = await sync_to_async(list)(
|
||||
# Reservation.objects.filter(
|
||||
# hotel_id=hotel_id,
|
||||
# check_in__gte=start_date,
|
||||
# check_in__lte=end_date
|
||||
# ).select_related('hotel')
|
||||
# )
|
||||
|
||||
# if not reservations:
|
||||
# await query.edit_message_text("Нет данных для статистики за выбранный период.")
|
||||
# return
|
||||
|
||||
# hotel = await sync_to_async(Hotel.objects.get)(id=hotel_id)
|
||||
|
||||
# file_path = await generate_pdf_report(hotel.name, reservations, start_date, end_date)
|
||||
|
||||
# with open(file_path, "rb") as file:
|
||||
# await query.message.reply_document(document=file, filename=f"{hotel.name}_report.pdf")
|
||||
|
||||
# if os.path.exists(file_path):
|
||||
# os.remove(file_path)
|
||||
|
||||
# except Exception as e:
|
||||
# logging.error(f"Ошибка в generate_statistics: {str(e)}", exc_info=True)
|
||||
# logging.error(f'start_date_type: {type(start_date)}, \n end_date_type: {type(end_date)}\n')
|
||||
# await query.edit_message_text(f"Произошла ошибка: {str(e)}")
|
||||
|
||||
async def generate_statistics(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Генерация и отправка статистики."""
|
||||
|
||||
logger = CustomLogger(__name__).get_logger()
|
||||
query = update.callback_query
|
||||
await query.answer()
|
||||
|
||||
try:
|
||||
hotel_id = context.user_data.get("selected_hotel")
|
||||
|
||||
if not hotel_id:
|
||||
raise ValueError(f"ID отеля не найден в user_data: {context.user_data}")
|
||||
|
||||
period = query.data.split("_")[2]
|
||||
now = ensure_datetime(datetime.utcnow())
|
||||
|
||||
|
||||
now = datetime.utcnow().replace(tzinfo=timezone.utc)
|
||||
|
||||
print(type(now))
|
||||
|
||||
print(type(period))
|
||||
|
||||
# Получаем диапазон дат
|
||||
start_date, end_date = get_period_dates(period, now)
|
||||
|
||||
|
||||
try:
|
||||
# Получаем бронирования
|
||||
reservations = await sync_to_async(list)(
|
||||
Reservation.objects.filter(
|
||||
hotel_id=hotel_id,
|
||||
check_in__gte=start_date,
|
||||
check_in__lte=end_date
|
||||
).select_related('hotel')
|
||||
)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"statistics.py Ошибка при выборке бронирований: {e}") from e
|
||||
reservations = await sync_to_async(list)(
|
||||
Reservation.objects.filter(
|
||||
hotel_id=hotel_id,
|
||||
check_in__gte=start_date,
|
||||
check_in__lte=end_date
|
||||
).select_related('hotel')
|
||||
)
|
||||
|
||||
if not reservations:
|
||||
await query.edit_message_text("statistics.py Нет данных для статистики за выбранный период.")
|
||||
await query.edit_message_text("Нет данных для статистики за выбранный период.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Получаем данные об отеле
|
||||
hotel = await sync_to_async(Hotel.objects.get)(id=hotel_id)
|
||||
|
||||
except Hotel.DoesNotExist:
|
||||
raise RuntimeError(f"statistics.py Отель с ID {hotel_id} не найден")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"statistics.py Ошибка при выборке отеля: {e}") from e
|
||||
hotel = await sync_to_async(Hotel.objects.get)(id=hotel_id)
|
||||
|
||||
try:
|
||||
# Генерация отчета
|
||||
file_path = await generate_pdf_report(hotel.name, reservations, start_date, end_date)
|
||||
print(f"[DEBUG] start_date: {start_date}, type: {type(start_date)}")
|
||||
print(f"[DEBUG] end_date: {end_date}, type: {type(end_date)}")
|
||||
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"statistics.py [ERROR] Ошибка при генерации PDF-отчета: {e}") from e
|
||||
# Генерация PDF-отчета
|
||||
file_path = await generate_pdf_report(
|
||||
hotel.name,
|
||||
reservations,
|
||||
start_date=start_date.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
end_date=end_date.strftime('%Y-%m-%d %H:%M:%S')
|
||||
)
|
||||
|
||||
try:
|
||||
# Отправка файла через Telegram
|
||||
with open(file_path, "rb") as file:
|
||||
await query.message.reply_document(document=file, filename=f"{hotel.name}_report.pdf")
|
||||
# Отправка PDF-файла
|
||||
with open(file_path, "rb") as file:
|
||||
await query.message.reply_document(document=file, filename=f"{hotel.name}_report.pdf")
|
||||
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Ошибка при отправке PDF-файла: {e}") from e
|
||||
|
||||
# Удаляем временный файл
|
||||
# Удаление временного файла
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# Логируем стек вызовов для детального анализа
|
||||
error_trace = traceback.format_exc()
|
||||
|
||||
logger.error(f"Ошибка в generate_statistics: {str(e)}", exc_info=True)
|
||||
await query.edit_message_text(f"Произошла ошибка: {str(e)}")
|
||||
|
||||
|
||||
def get_period_dates(period, now):
|
||||
now = ensure_datetime(now)
|
||||
if period == "day":
|
||||
start_date = (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||
@@ -178,6 +209,7 @@ def get_period_dates(period, now):
|
||||
end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||
return start_date, end_date
|
||||
|
||||
|
||||
async def stats_back(update: Update, context):
|
||||
"""Возврат к выбору отеля."""
|
||||
query = update.callback_query
|
||||
|
||||
Reference in New Issue
Block a user