from django.db import models from hotels.models import Hotel from hotels.models import Reservation class UserActivityLog(models.Model): external_id = models.CharField(max_length=255, null=True, blank=True) user_id = models.BigIntegerField(verbose_name="ID пользователя") ip = models.GenericIPAddressField(verbose_name="IP-адрес") created = models.DateTimeField(verbose_name="Дата создания") timestamp = models.BigIntegerField(verbose_name="Метка времени") date_time = models.DateTimeField(verbose_name="Дата и время") referred = models.TextField(blank=True, null=True, verbose_name="Реферальная ссылка") agent = models.TextField(verbose_name="Агент пользователя") platform = models.CharField(max_length=255, blank=True, null=True, verbose_name="Платформа") version = models.CharField(max_length=255, blank=True, null=True, verbose_name="Версия") model = models.CharField(max_length=255, blank=True, null=True, verbose_name="Модель устройства") device = models.CharField(max_length=255, blank=True, null=True, verbose_name="Тип устройства") UAString = models.TextField(verbose_name="User-Agent строка") location = models.CharField(max_length=255, blank=True, null=True, verbose_name="Местоположение") page_id = models.BigIntegerField(blank=True, null=True, verbose_name="ID страницы") url_parameters = models.TextField(blank=True, null=True, verbose_name="Параметры URL") page_title = models.TextField(blank=True, null=True, verbose_name="Заголовок страницы") type = models.CharField(max_length=50, verbose_name="Тип") last_counter = models.IntegerField(verbose_name="Последний счетчик") hits = models.IntegerField(verbose_name="Количество обращений") honeypot = models.BooleanField(verbose_name="Метка honeypot") reply = models.BooleanField(verbose_name="Ответ пользователя") page_url = models.URLField(blank=True, null=True, verbose_name="URL страницы") def __str__(self): return f"UserActivityLog {self.id}: {self.page_title}" class Meta: verbose_name = "Регистрация посетителей" verbose_name_plural = "Регистрации посетителей" class ExternalDBSettings(models.Model): name = models.CharField(max_length=255, unique=True, help_text="Имя подключения для идентификации.") host = models.CharField(max_length=255, help_text="Адрес сервера базы данных.") port = models.PositiveIntegerField(default=3306, help_text="Порт сервера базы данных.") user = models.CharField(max_length=255, help_text="Имя пользователя базы данных.") password = models.CharField(max_length=255, help_text="Пароль для подключения.") database = models.CharField(max_length=255, default="u1510415_wp832", help_text="Имя базы данных.") table_name = models.CharField(max_length=255, blank=True, default="wpts_user_activity_log", null=True, help_text="Имя таблицы для загрузки данных.") selected_fields = models.TextField(blank=True, null=True, help_text="Список полей для загрузки (через запятую).") is_active = models.BooleanField(default=True, help_text="Флаг активности подключения.") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.name} ({self.host}:{self.port})" class Meta: verbose_name = "Настройка подключения к БД" verbose_name_plural = "Настройки подключений к БД" class RoomDiscrepancy(models.Model): hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, verbose_name="Отель") room_number = models.CharField(max_length=50, verbose_name="Номер комнаты") booking_id = models.CharField(max_length=255, verbose_name="ID бронирования") check_in_date_expected = models.DateField(verbose_name="Ожидаемая дата заселения") check_in_date_actual = models.DateField(verbose_name="Фактическая дата заселения") discrepancy_type = models.CharField( max_length=50, choices=[("early", "Раннее заселение"), ("late", "Позднее заселение"), ("missed", "Неявка")], verbose_name="Тип несоответствия" ) created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") def __str__(self): return f"{self.hotel.name} - Room {self.room_number}: {self.discrepancy_type}" class Meta: verbose_name = "Несовпадение в заселении" verbose_name_plural = "Несовпадения в заселении" @staticmethod def detect_discrepancies(expected_bookings, actual_check_ins): """ Сравнение ожидаемых и фактических данных о заселении. """ discrepancies = [] # Преобразуем фактические заселения в словарь для быстрого доступа actual_dict = { (entry.hotel_id, entry.room_number): entry.check_in_date for entry in actual_check_ins } for booking in expected_bookings: key = (booking.hotel_id, booking.room_number) actual_date = actual_dict.get(key) if actual_date is None: discrepancies.append(RoomDiscrepancy( hotel=booking.hotel, room_number=booking.room_number, booking_id=booking.booking_id, check_in_date_expected=booking.check_in_date, discrepancy_type="missed" )) elif actual_date < booking.check_in_date: discrepancies.append(RoomDiscrepancy( hotel=booking.hotel, room_number=booking.room_number, booking_id=booking.booking_id, check_in_date_expected=booking.check_in_date, check_in_date_actual=actual_date, discrepancy_type="early" )) elif actual_date > booking.check_in_date: discrepancies.append(RoomDiscrepancy( hotel=booking.hotel, room_number=booking.room_number, booking_id=booking.booking_id, check_in_date_expected=booking.check_in_date, check_in_date_actual=actual_date, discrepancy_type="late" )) RoomDiscrepancy.objects.bulk_create(discrepancies) from urllib.parse import unquote from html import unescape class ImportedHotel(models.Model): id = models.BigAutoField(primary_key=True, auto_created=True, verbose_name="ID") external_id = models.CharField(max_length=255, verbose_name="Внешний ID отеля") name = models.CharField(max_length=255, verbose_name="Имя отеля") display_name = models.CharField(max_length=255, null=True, blank=True, verbose_name="Отображаемое имя") created = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") updated = models.DateTimeField(auto_now=True, verbose_name="Дата обновления") imported = models.BooleanField(default=False, verbose_name="Импортирован в основную базу") def __str__(self): return f"{self.display_name or self.name} ({self.external_id})" class Meta: verbose_name = "Импортированный отель" verbose_name_plural = "Импортированные отели" def set_display_name_from_page_title(self, page_title): """ Декодирует HTML-сущности, URL-кодировку и устанавливает display_name. """ if page_title: decoded = unquote(unescape(page_title)) self.display_name = decoded else: self.display_name = self.name self.save() class SyncLog(models.Model): """ Журнал синхронизации. """ id = models.BigIntegerField(primary_key=True, unique=True, verbose_name="ID") hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, verbose_name="Отель") reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, verbose_name="Бронирование") created = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") recieved_records = models.IntegerField(verbose_name="Полученные записи") processed_records = models.IntegerField(verbose_name="Обработанные записи") class Meta: verbose_name = "Журнал синхронизации" verbose_name_plural = "Журналы синхронизации" class ViolationLog(models.Model): hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, verbose_name="Отель") room_number = models.CharField(max_length=50, verbose_name="Номер комнаты", null=True, blank=True) violation_type = models.CharField( max_length=50, choices=[("missed", "Неявка"), ("early", "Раннее заселение"), ("late", "Позднее заселение")], verbose_name="Тип нарушения" ) violation_details = models.TextField(verbose_name="Детали нарушения", blank=True, null=True) detected_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата обнаружения") created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") def __str__(self): return f"{self.hotel.name} - {self.room_number or 'N/A'}: {self.violation_type}" class Meta: verbose_name = "Журнал нарушений" verbose_name_plural = "Журналы нарушений"