import logging from datetime import timedelta from urllib.parse import parse_qs from django.utils import timezone from django.db.models import Q from hotels.models import Reservation, Hotel from .models import UserActivityLog, ViolationLog # Настройка логирования logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class ReservationChecker: """ Класс для проверки несоответствий между бронированиями и логами заселения. """ def __init__(self): """ Инициализация времени проверки и списка нарушений. """ self.start_time = timezone.now() - timedelta(days=30) self.end_time = timezone.now() self.violations = [] def log_info(self, message): """Логирование информационных сообщений.""" logger.info(message) def log_warning(self, message): """Логирование предупреждений.""" logger.warning(message) def log_error(self, message): """Логирование ошибок.""" logger.error(message) def fetch_user_logs(self): """ Извлекает записи из UserActivityLog за последние 12 часов. """ print(f"Fetching user logs from {self.start_time} to {self.end_time}") user_logs = UserActivityLog.objects.filter(created__range=(self.start_time, self.end_time)) print(f"Found {user_logs.count()} logs for analysis.") return user_logs def fetch_hotels(self, hotel_ids): """ Извлекает отели по hotel_id из логов. """ hotels = {hotel.hotel_id: hotel for hotel in Hotel.objects.filter(hotel_id__in=hotel_ids)} self.log_info(f"Найдено {len(hotels)} отелей для сверки.") return hotels def find_violations(self, user_logs, hotels): """ Сопоставляет логи активности с бронированиями и фиксирует нарушения. """ for log in user_logs: if not log.url_parameters: self.log_warning(f"Пропущена запись ID {log.id}: отсутствуют URL-параметры.") continue # Парсинг параметров URL params = parse_qs(log.url_parameters) hotel_id = params.get("utm_content", [None])[0] room_number = params.get("utm_term", [None])[0] print(f"Processing log ID {log.id} with hotel ID {hotel_id} and room number {room_number}") if not hotel_id or not room_number: self.log_warning(f"Пропущена запись ID {log.id}: некорректные параметры URL.") continue if hotel_id not in hotels: self.log_warning(f"Пропущена запись ID {log.id}: отель с ID {hotel_id} не найден.") continue hotel = hotels[hotel_id] log_time = timezone.localtime(log.created) # Проверка существования бронирования matching_reservations = Reservation.objects.filter( hotel=hotel, room_number=room_number, check_in__lte=log_time, check_out__gte=log_time ) print(f"Found {matching_reservations.count()} matching reservations") if not matching_reservations.exists(): violation_details = ( f"Не найдено бронирование для номера {room_number} в отеле '{hotel.name}' на {log_time}." ) # Добавляем нарушение, если его ещё нет в базе if not ViolationLog.objects.filter( hotel=hotel, room_number=room_number, violation_type="missed", violation_details=violation_details ).exists(): self.violations.append(ViolationLog( hotel=hotel, room_number=room_number, violation_type="missed", violation_details=violation_details )) self.log_warning(f"Зафиксировано нарушение: {violation_details}") def save_violations(self): """ Сохраняет найденные нарушения в базу данных. """ if self.violations: ViolationLog.objects.bulk_create(self.violations) self.log_info(f"Создано {len(self.violations)} записей в ViolationLog.") else: self.log_info("Нарушений не обнаружено.") def run_check(self): """ Основной метод для запуска проверки. """ self.log_info(f"Запуск проверки бронирований с {self.start_time} по {self.end_time}.") try: # Получаем логи пользователей user_logs = self.fetch_user_logs() # Извлекаем hotel_id из логов hotel_ids = set() for log in user_logs: if log.url_parameters: params = parse_qs(log.url_parameters) hotel_id = params.get("utm_content", [None])[0] if hotel_id: hotel_ids.add(hotel_id) # Предзагружаем отели hotels = self.fetch_hotels(hotel_ids) # Сравниваем логи с бронированиями self.find_violations(user_logs, hotels) # Сохраняем результаты self.save_violations() except Exception as e: self.log_error(f"Произошла ошибка при выполнении проверки: {e}") self.log_info("Проверка бронирований завершена.") # Функция для запуска проверки из планировщика def run_reservation_check(): """ Функция для запуска проверки бронирований. """ checker = ReservationChecker() checker.run_check()