pre-release

This commit is contained in:
2024-12-18 10:49:40 +09:00
parent 0bf2bb8dff
commit b8d3b953d2
5 changed files with 192 additions and 540 deletions

View File

@@ -24,94 +24,104 @@ class ReservationChecker:
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}")
""" Извлекает записи из UserActivityLog за период. """
user_logs = UserActivityLog.objects.filter(created__range=(self.start_time, self.end_time))
print(f"Found {user_logs.count()} logs for analysis.")
self.log_info(f"Найдено {user_logs.count()} логов активности для анализа.")
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 fetch_reservations(self):
""" Извлекает бронирования за период. """
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
def find_violations(self, user_logs, hotels):
def find_violations(self):
"""
Сопоставляет логи активности с бронированиями и фиксирует нарушения.
Сравнивает записи бронирований и логи активности для выявления нарушений:
- Сканирование QR без бронирования.
- Бронь со статусом "заселен" без сканирования QR.
- Раннее заселение.
"""
user_logs = self.fetch_user_logs()
reservations = self.fetch_reservations()
# Сопоставляем записи
log_lookup = {} # Словарь: (hotel_id, room_number) -> список логов
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)
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)
print(f"Processing log ID {log.id} with hotel ID {hotel_id} and room number {room_number}")
for reservation in reservations:
key = (reservation.hotel.hotel_id, reservation.room_number)
logs = log_lookup.get(key, [])
if not hotel_id or not room_number:
self.log_warning(f"Пропущена запись ID {log.id}: некорректные параметры URL.")
continue
# Бронь со статусом "заселен" без сканирования QR
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."
)
if hotel_id not in hotels:
self.log_warning(f"Пропущена запись ID {log.id}: отель с ID {hotel_id} не найден.")
continue
# Раннее заселение
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}."
)
hotel = hotels[hotel_id]
log_time = timezone.localtime(log.created)
# Сканирование QR без бронирования
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"не соответствует ни одному бронированию."
)
# Проверка существования бронирования
matching_reservations = Reservation.objects.filter(
def record_violation(self, hotel, room_number, violation_type, details):
"""
Записывает нарушение в список для последующего сохранения.
"""
if hotel:
self.violations.append(ViolationLog(
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}")
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.")
@@ -119,42 +129,19 @@ class ReservationChecker:
self.log_info("Нарушений не обнаружено.")
def run_check(self):
"""
Основной метод для запуска проверки.
"""
self.log_info(f"Запуск проверки бронирований с {self.start_time} по {self.end_time}.")
""" Основной метод для запуска проверки. """
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.find_violations()
self.save_violations()
except Exception as e:
self.log_error(f"Произошла ошибка при выполнении проверки: {e}")
self.log_error(f"Ошибка при выполнении проверки: {e}")
self.log_info("Проверка завершена.")
self.log_info("Проверка бронирований завершена.")
# Функция для запуска проверки из планировщика
# Функция для запуска из планировщика
def run_reservation_check():
"""
Функция для запуска проверки бронирований.
"""
checker = ReservationChecker()
checker.run_check()
checker.run_check()