from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator from django.core.exceptions import ValidationError import pytz class APIConfiguration(models.Model): name = models.CharField(max_length=255, verbose_name="Название API") url = models.URLField(verbose_name="URL API") token = models.CharField(max_length=255, blank=True, null=True, verbose_name="Токен") username = models.CharField(max_length=255, blank=True, null=True, verbose_name="Логин") password = models.CharField(max_length=255, blank=True, null=True, verbose_name="Пароль") last_updated = models.DateTimeField(auto_now=True, verbose_name="Дата последнего обновления") def __str__(self): return self.name class Meta: verbose_name = "Конфигурация API" verbose_name_plural = "Конфигурации API" class Hotel(models.Model): name = models.CharField(max_length=255, verbose_name="Название отеля") hotel_id = models.CharField(max_length=255, unique=True, null=True, blank=True, verbose_name="ID отеля") external_id_pms = models.CharField(max_length=100, unique=False, null=True, blank=True, verbose_name="Внешний PMS ID") created_at = models.DateTimeField(auto_now_add=True, verbose_name="Создан") phone = models.CharField( max_length=50, null=True, blank=True, verbose_name="Телефон", validators=[ RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Введите корректный номер телефона (до 15 цифр).") ], ) email = models.EmailField(null=True, blank=True, verbose_name="Email") address = models.CharField(max_length=255, null=True, blank=True, verbose_name="Адрес") city = models.CharField(max_length=255, null=True, blank=True, verbose_name="Город") timezone = models.CharField( max_length=63, choices=[(tz, tz) for tz in pytz.all_timezones], default='UTC', verbose_name="Часовой пояс", ) description = models.TextField(null=True, blank=True, verbose_name="Описание") pms = models.ForeignKey( 'pms_integration.PMSConfiguration', on_delete=models.SET_NULL, null=True, blank=True, verbose_name="PMS система" ) def __str__(self): return self.name class Meta: verbose_name = "Отель" verbose_name_plural = "Отели" class Room(models.Model): hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="rooms", verbose_name="Отель") number = models.CharField(max_length=50, unique=True, verbose_name="Номер комнаты") external_id = models.CharField(max_length=255, unique=True, verbose_name="Внешний ID комнаты") description = models.TextField(blank=True, null=True, verbose_name="Описание") created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") updated_at = models.DateTimeField(auto_now=True, verbose_name="Дата обновления") def __str__(self): return f"{self.hotel.name} - {self.number}" class Meta: verbose_name = "Номер" verbose_name_plural = "Номера" constraints = [ models.UniqueConstraint(fields=["hotel", "number"], name="unique_hotel_room") ] indexes = [ models.Index(fields=["hotel", "number"]), ] class UserHotel(models.Model): user = models.ForeignKey( 'users.User', on_delete=models.CASCADE, related_name="user_hotels", verbose_name="Пользователь" ) hotel = models.ForeignKey( Hotel, on_delete=models.CASCADE, related_name="hotel_users", verbose_name="Отель" ) def __str__(self): return f"{self.user.username} - {self.hotel.name}" class Meta: verbose_name = "Пользователь отеля" verbose_name_plural = "Пользователи отелей" class Reservation(models.Model): id = models.BigAutoField(primary_key=True, auto_created=True, verbose_name="ID") hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, verbose_name="Отель") reservation_id = models.BigIntegerField(unique=True, verbose_name="ID бронирования") room_number = models.CharField(max_length=255, null=True, blank=True, verbose_name="Номер комнаты") room_type = models.CharField(max_length=255, verbose_name="Тип комнаты") check_in = models.DateTimeField(verbose_name="Дата заезда") check_out = models.DateTimeField(verbose_name="Дата выезда") status = models.CharField(max_length=50, verbose_name="Статус") price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="Цена") discount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="Скидка") def clean(self): if self.check_out and self.check_in and self.check_out <= self.check_in: raise ValidationError("Дата выезда должна быть позже даты заезда.") def __str__(self): return f"Бронирование {self.reservation_id} - {self.hotel.name}" class Meta: verbose_name = "Бронирование" verbose_name_plural = "Бронирования" indexes = [ models.Index(fields=["hotel", "check_in", "check_out"]), ] class Guest(models.Model): reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, related_name="guests", verbose_name="Бронирование") name = models.CharField(max_length=255, verbose_name="Имя гостя") birthdate = models.DateField(null=True, blank=True, verbose_name="Дата рождения") phone = models.CharField( max_length=50, null=True, blank=True, verbose_name="Телефон", validators=[ RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Введите корректный номер телефона (до 15 цифр).") ], ) email = models.EmailField(null=True, blank=True, verbose_name="Email") def __str__(self): return f"{self.name} ({self.birthdate})" if self.birthdate else self.name class Meta: verbose_name = "Гость" verbose_name_plural = "Гости" class FraudLog(models.Model): hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="frauds") reservation_id = models.BigIntegerField(verbose_name="ID бронирования") guest_name = models.CharField(max_length=255, null=True, blank=True) check_in_date = models.DateField(verbose_name="Дата заезда") detected_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата обнаружения") message = models.TextField(verbose_name="Сообщение") def __str__(self): return f"FRAUD: {self.guest_name} ({self.check_in_date})" class Meta: verbose_name = "Журнал мошенничества" verbose_name_plural = "Журналы мошенничества" indexes = [ models.Index(fields=["reservation_id"]), models.Index(fields=["detected_at"]), ] class APIRequestLog(models.Model): api = models.ForeignKey(APIConfiguration, on_delete=models.CASCADE, verbose_name="API") request_time = models.DateTimeField(auto_now_add=True, verbose_name="Время запроса") response_status = models.IntegerField(verbose_name="HTTP статус ответа", validators=[MinValueValidator(100), MaxValueValidator(599)]) response_data = models.JSONField(verbose_name="Данные ответа", blank=True, null=True) def __str__(self): return f"{self.api.name} - {self.request_time}" class Meta: verbose_name = "Журнал запросов API" verbose_name_plural = "Журналы запросов API" indexes = [ models.Index(fields=["api"]), models.Index(fields=["request_time"]), ]