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, RoomDiscrepancy from touchh.utils.log import CustomLogger # Настройка логирования logger = CustomLogger(__name__).get_logger() class ReservationChecker: """ Класс для проверки несоответствий между бронированиями и логами заселения. """ def __init__(self): """ Инициализация времени проверки и списка нарушений. """ self.start_time = timezone.now() - timedelta(days=30) self.end_time = timezone.now() self.violations = [] self.checkin_diff_hours = 3 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): try: self.log_info("Начинается извлечение логов активности пользователей.") user_logs = UserActivityLog.objects.filter(created__range=(self.start_time, self.end_time)) self.log_info(f"Найдено {user_logs.count()} логов активности для анализа.") return user_logs except Exception as e: self.log_error(f"Ошибка при извлечении логов активности: {e}") return UserActivityLog.objects.none() def fetch_reservations(self): try: self.log_info("Начинается извлечение бронирований.") reservations = Reservation.objects.filter( Q(check_in__lte=self.end_time) & Q(check_out__gte=self.start_time) ) self.log_info(f"Найдено {reservations.count()} бронирований для анализа.") return reservations except Exception as e: self.log_error(f"Ошибка при извлечении бронирований: {e}") return Reservation.objects.none() def find_violations(self): self.log_info("Начинается анализ несоответствий.") user_logs = self.fetch_user_logs() reservations = self.fetch_reservations() log_lookup = {} for log in user_logs: params = parse_qs(log.url_parameters or "") hotel_id = params.get("utm_content", [None])[0] room_number = params.get("utm_term", [None])[0] if hotel_id and room_number: key = (hotel_id, room_number) log_lookup.setdefault(key, []).append(log) for reservation in reservations: key = (reservation.hotel.hotel_id, reservation.room_number) logs = log_lookup.get(key, []) if reservation.status == "заселен" and not logs: self.record_violation( hotel=reservation.hotel, room_number=reservation.room_number, violation_type="no_qr_scan", details=f"Бронирование для номера {reservation.room_number} в отеле '{reservation.hotel.name}' " f"не имеет записи сканирования QR." ) for log in logs: if log.created < reservation.check_in: self.record_violation( hotel=reservation.hotel, room_number=reservation.room_number, violation_type="early_check_in", details=f"Раннее заселение: сканирование QR {log.created} раньше времени заезда " f"{reservation.check_in} для номера {reservation.room_number}." ) for (hotel_id, room_number), logs in log_lookup.items(): matching_reservations = reservations.filter( hotel__hotel_id=hotel_id, room_number=room_number ) if not matching_reservations.exists(): for log in logs: self.record_violation( hotel=Hotel.objects.filter(hotel_id=hotel_id).first(), room_number=room_number, violation_type="no_reservation", details=f"Сканирование QR {log.created} для номера {room_number} в отеле с ID '{hotel_id}' " f"не соответствует ни одному бронированию." ) def record_violation(self, hotel, room_number, violation_type, details): if hotel: self.violations.append(ViolationLog( hotel=hotel, room_number=room_number, violation_type=violation_type, violation_details=details )) self.log_warning(f"Зафиксировано нарушение: {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: self.find_violations() self.save_violations() except Exception as e: self.log_error(f"Ошибка при выполнении проверки: {e}") self.log_info("Проверка завершена.") # Функция для запуска из планировщика def run_reservation_check(): logger.info("Планировщик вызывает run_reservation_check.") try: checker = ReservationChecker() checker.run_check() except Exception as e: logger.error(f"Ошибка при запуске проверки: {e}") logger.info("run_reservation_check завершена.")