# import json # from datetime import timedelta # from django.utils import timezone # from django.db.models import Q # from hotels.models import Reservation, Hotel # from .models import UserActivityLog, RoomDiscrepancy # from touchh.utils.log import CustomLogger # # Настройка логирования # logger = CustomLogger(__name__).get_logger() # class ReservationChecker: # """ # Класс для проверки несоответствий между бронированиями и логами заселения. # """ # def __init__(self): # 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 run_check(self): # """Запуск проверки фродовых событий.""" # self.log_info("Запуск проверки фродовых данных.") # try: # check_in_diff = timedelta(hours=self.checkin_diff_hours) # # Кэшируем отели в словарь для быстрого доступа # hotels_map = {hotel.hotel_id: hotel for hotel in Hotel.objects.all()} # # Загружаем бронирования и активности пользователей # user_logs = UserActivityLog.objects.filter(fraud_checked=False) # reservations = Reservation.objects.filter(fraud_checked=False).select_related('hotel') # # Преобразуем бронирования в словарь для быстрого поиска # reservations_map = { # (res.hotel.hotel_id, res.room_number): res for res in reservations # } # violations = [] # missing_reservations = set(reservations) # Сет для поиска пропавших бронирований # for user_log in user_logs: # try: # params = json.loads(user_log.url_parameters.replace("'", '"')) if user_log.url_parameters else {} # hotel_id = params.get('utm_content') # room = params.get('utm_term') # if not hotel_id or not room: # continue # Пропускаем записи без нужных параметров # key = (hotel_id, room) # reserv = reservations_map.get(key) # discrepancy_type = None # if reserv: # if reserv in missing_reservations: # missing_reservations.remove(reserv) # if user_log.date_time < reserv.check_in: # discrepancy_type = 'early' # elif user_log.date_time > reserv.check_in + check_in_diff: # discrepancy_type = 'late' # else: # discrepancy_type = 'no_booking' # if discrepancy_type: # violations.append(RoomDiscrepancy( # hotel=hotels_map.get(hotel_id), # room_number=room, # discrepancy_type=discrepancy_type, # booking_id=reserv.reservation_id if reserv else None, # check_in_date_expected=reserv.check_in if reserv else None, # check_in_date_actual=user_log.date_time, # )) # user_log.fraud_checked = True # Отмечаем логи как проверенные # except json.JSONDecodeError: # self.log_error(f"Ошибка декодирования JSON в URL-параметрах: {user_log.url_parameters}") # except Exception as e: # self.log_error(f"Ошибка при обработке логов: {e}") # # Добавляем пропущенные бронирования # for miss_reserv in missing_reservations: # violations.append(RoomDiscrepancy( # hotel=miss_reserv.hotel, # room_number=miss_reserv.room_number, # discrepancy_type='missed', # booking_id=miss_reserv.reservation_id, # check_in_date_expected=miss_reserv.check_in, # )) # # Массово сохраняем нарушения # if violations: # RoomDiscrepancy.objects.bulk_create(violations) # self.log_info(f"Записано {len(violations)} новых несоответствий.") # # Обновляем флаги fraud_checked # UserActivityLog.objects.filter(id__in=[log.id for log in user_logs]).update(fraud_checked=True) # Reservation.objects.filter(id__in=[res.id for res in reservations]).update(fraud_checked=True) # 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 завершена.") import json from datetime import timedelta from django.utils import timezone from django.db.models import Q from hotels.models import Reservation, Hotel from .models import UserActivityLog, RoomDiscrepancy from touchh.utils.log import CustomLogger # Настройка логирования logger = CustomLogger(__name__).get_logger() class ReservationChecker: """ Класс для проверки несоответствий между бронированиями и логами заселения. """ def __init__(self): 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 run_check(self): """Запуск проверки фродовых событий.""" self.log_info("🔍 Запуск проверки фродовых данных.") try: check_in_diff = timedelta(hours=self.checkin_diff_hours) # Кэшируем отели в словарь для быстрого доступа hotels_map = {hotel.hotel_id: hotel for hotel in Hotel.objects.all()} # Загружаем бронирования и активности пользователей user_logs = UserActivityLog.objects.filter(fraud_checked=False) reservations = Reservation.objects.filter(fraud_checked=False).select_related('hotel') # Преобразуем бронирования в словарь для быстрого поиска reservations_map = { (res.hotel.hotel_id, res.room_number): res for res in reservations } violations = [] checked_reservations = set() # Сет для бронирований, которые были проверены self.log_info(f"✅ Загружено {len(user_logs)} логов активности и {len(reservations)} бронирований.") for user_log in user_logs: try: params = json.loads(user_log.url_parameters.replace("'", '"')) if user_log.url_parameters else {} hotel_id = params.get('utm_content') room = params.get('utm_term') if not hotel_id or not room: self.log_warning(f"🚫 Пропущен лог без hotel_id или room_number: {user_log.url_parameters}") continue # Пропускаем записи без нужных параметров key = (hotel_id, room) reserv = reservations_map.get(key) discrepancy_type = "match" # По умолчанию считаем, что всё соответствует if reserv: checked_reservations.add(reserv) if user_log.date_time < reserv.check_in: discrepancy_type = 'early' self.log_warning(f"⚠️ Обнаружено раннее заселение: {user_log.date_time} < {reserv.check_in}") elif user_log.date_time > reserv.check_in + check_in_diff: discrepancy_type = 'late' self.log_warning(f"⚠️ Обнаружено позднее заселение: {user_log.date_time} > {reserv.check_in + check_in_diff}") else: discrepancy_type = 'no_booking' self.log_warning(f"🚨 Заселение без бронирования: {user_log.date_time} (Отель {hotel_id}, Комната {room})") violations.append(RoomDiscrepancy( hotel=hotels_map.get(hotel_id), room_number=room, discrepancy_type=discrepancy_type, booking_id=reserv.reservation_id if reserv else None, check_in_date_expected=reserv.check_in if reserv else None, check_in_date_actual=user_log.date_time, )) user_log.fraud_checked = True # Отмечаем логи как проверенные except json.JSONDecodeError: self.log_error(f"❌ Ошибка декодирования JSON в URL-параметрах: {user_log.url_parameters}") except Exception as e: self.log_error(f"❌ Ошибка при обработке логов: {e}") # Добавляем пропущенные бронирования (неявки) for reserv in reservations: if reserv not in checked_reservations: violations.append(RoomDiscrepancy( hotel=reserv.hotel, room_number=reserv.room_number, discrepancy_type='missed', booking_id=reserv.reservation_id, check_in_date_expected=reserv.check_in, )) self.log_warning(f"⚠️ Обнаружена неявка (missed) | Отель: {reserv.hotel.hotel_id}, Номер: {reserv.room_number}, Ожидаемая дата заезда: {reserv.check_in}") # Массово сохраняем все записи, включая корректные совпадения if violations: RoomDiscrepancy.objects.bulk_create(violations) self.log_info(f"✅ Записано {len(violations)} новых записей в RoomDiscrepancy.") # Обновляем флаги fraud_checked UserActivityLog.objects.filter(id__in=[log.id for log in user_logs]).update(fraud_checked=True) Reservation.objects.filter(id__in=[res.id for res in reservations]).update(fraud_checked=True) 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 завершена.")