260 lines
12 KiB
Python
260 lines
12 KiB
Python
# 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 завершена.")
|