bnovo
This commit is contained in:
129
antifroud/migrations/0001_initial.py
Normal file
129
antifroud/migrations/0001_initial.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 04:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ExternalDBSettings',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(help_text='Имя подключения для идентификации.', max_length=255, unique=True)),
|
||||||
|
('host', models.CharField(help_text='Адрес сервера базы данных.', max_length=255)),
|
||||||
|
('port', models.PositiveIntegerField(default=3306, help_text='Порт сервера базы данных.')),
|
||||||
|
('user', models.CharField(help_text='Имя пользователя базы данных.', max_length=255)),
|
||||||
|
('password', models.CharField(help_text='Пароль для подключения.', max_length=255)),
|
||||||
|
('database', models.CharField(default='u1510415_wp832', help_text='Имя базы данных.', max_length=255)),
|
||||||
|
('table_name', models.CharField(blank=True, default='wpts_user_activity_log', help_text='Имя таблицы для загрузки данных.', max_length=255, null=True)),
|
||||||
|
('selected_fields', models.TextField(blank=True, help_text='Список полей для загрузки (через запятую).', null=True)),
|
||||||
|
('is_active', models.BooleanField(default=True, help_text='Флаг активности подключения.')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Настройка подключения к БД',
|
||||||
|
'verbose_name_plural': 'Настройки подключений к БД',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ImportedHotel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, 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(blank=True, max_length=255, null=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='Импортирован в основную базу')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Импортированный отель',
|
||||||
|
'verbose_name_plural': 'Импортированные отели',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RoomDiscrepancy',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('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(choices=[('early', 'Раннее заселение'), ('late', 'Позднее заселение'), ('missed', 'Неявка')], max_length=50, verbose_name='Тип несоответствия')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Несовпадение в заселении',
|
||||||
|
'verbose_name_plural': 'Несовпадения в заселении',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SyncLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||||
|
('recieved_records', models.IntegerField(default=0, verbose_name='Полученные записи')),
|
||||||
|
('processed_records', models.IntegerField(default=0, verbose_name='Обработанные записи')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Журнал синхронизации',
|
||||||
|
'verbose_name_plural': 'Журналы синхронизации',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserActivityLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('external_id', models.CharField(db_index=True, max_length=255, unique=True, verbose_name='Внешний ID')),
|
||||||
|
('user_id', models.BigIntegerField(blank=True, db_index=True, null=True, verbose_name='ID пользователя')),
|
||||||
|
('ip', models.GenericIPAddressField(blank=True, db_index=True, null=True, verbose_name='IP-адрес')),
|
||||||
|
('created', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Дата создания')),
|
||||||
|
('timestamp', models.BigIntegerField(blank=True, null=True, verbose_name='Метка времени')),
|
||||||
|
('date_time', models.DateTimeField(blank=True, null=True, verbose_name='Дата и время')),
|
||||||
|
('referred', models.TextField(blank=True, null=True, verbose_name='Реферальная ссылка')),
|
||||||
|
('agent', models.TextField(blank=True, null=True, verbose_name='Агент пользователя')),
|
||||||
|
('platform', models.CharField(blank=True, max_length=255, null=True, verbose_name='Платформа')),
|
||||||
|
('version', models.CharField(blank=True, max_length=255, null=True, verbose_name='Версия')),
|
||||||
|
('model', models.CharField(blank=True, max_length=255, null=True, verbose_name='Модель устройства')),
|
||||||
|
('device', models.CharField(blank=True, max_length=255, null=True, verbose_name='Тип устройства')),
|
||||||
|
('UAString', models.TextField(blank=True, null=True, verbose_name='User-Agent строка')),
|
||||||
|
('location', models.CharField(blank=True, max_length=255, null=True, verbose_name='Местоположение')),
|
||||||
|
('page_id', models.BigIntegerField(blank=True, db_index=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(blank=True, max_length=50, null=True, verbose_name='Тип')),
|
||||||
|
('last_counter', models.IntegerField(blank=True, null=True, verbose_name='Последний счетчик')),
|
||||||
|
('hits', models.IntegerField(blank=True, default='0', null=True, verbose_name='Количество обращений')),
|
||||||
|
('honeypot', models.BooleanField(blank=True, null=True, verbose_name='Метка honeypot')),
|
||||||
|
('reply', models.BooleanField(blank=True, null=True, verbose_name='Ответ пользователя')),
|
||||||
|
('page_url', models.URLField(blank=True, null=True, verbose_name='URL страницы')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Регистрация посетителей',
|
||||||
|
'verbose_name_plural': 'Регистрации посетителей',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ViolationLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('room_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='Номер комнаты')),
|
||||||
|
('violation_type', models.CharField(choices=[('missed', 'Неявка'), ('early', 'Раннее заселение'), ('late', 'Позднее заселение')], max_length=50, verbose_name='Тип нарушения')),
|
||||||
|
('violation_details', models.TextField(blank=True, null=True, verbose_name='Детали нарушения')),
|
||||||
|
('hits', models.IntegerField(verbose_name='Срабатывания')),
|
||||||
|
('detected_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата обнаружения')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Журнал нарушений',
|
||||||
|
'verbose_name_plural': 'Журналы нарушений',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
32
antifroud/migrations/0002_initial.py
Normal file
32
antifroud/migrations/0002_initial.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 04:55
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('antifroud', '0001_initial'),
|
||||||
|
('hotels', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='roomdiscrepancy',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='synclog',
|
||||||
|
name='hotel',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='violationlog',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
]
|
||||||
86
app_settings/migrations/0001_initial.py
Normal file
86
app_settings/migrations/0001_initial.py
Normal file
File diff suppressed because one or more lines are too long
138
hotels/migrations/0001_initial.py
Normal file
138
hotels/migrations/0001_initial.py
Normal file
File diff suppressed because one or more lines are too long
47
hotels/migrations/0002_initial.py
Normal file
47
hotels/migrations/0002_initial.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 04:55
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hotels', '0001_initial'),
|
||||||
|
('pms_integration', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='hotel',
|
||||||
|
name='pms',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pms_integration.pmsconfiguration', verbose_name='PMS система'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='fraudlog',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='frauds', to='hotels.hotel'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='reservation',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='guest',
|
||||||
|
name='reservation',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='guests', to='hotels.reservation', verbose_name='Бронирование'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='room',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userhotel',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='hotel_users', to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 05:10
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hotels', '0002_initial'),
|
||||||
|
('users', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='hotel',
|
||||||
|
old_name='external_id',
|
||||||
|
new_name='external_id_pms',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userhotel',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='user_hotels', to='users.user', verbose_name='Пользователь'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='apirequestlog',
|
||||||
|
index=models.Index(fields=['api'], name='hotels_apir_api_id_686bb0_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='apirequestlog',
|
||||||
|
index=models.Index(fields=['request_time'], name='hotels_apir_request_f65147_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='fraudlog',
|
||||||
|
index=models.Index(fields=['reservation_id'], name='hotels_frau_reserva_5a26b7_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='fraudlog',
|
||||||
|
index=models.Index(fields=['detected_at'], name='hotels_frau_detecte_07e626_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='reservation',
|
||||||
|
index=models.Index(fields=['hotel', 'check_in', 'check_out'], name='hotels_rese_hotel_i_6c527e_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='room',
|
||||||
|
index=models.Index(fields=['hotel', 'number'], name='hotels_room_hotel_i_a7c4fc_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='room',
|
||||||
|
constraint=models.UniqueConstraint(fields=('hotel', 'number'), name='unique_hotel_room'),
|
||||||
|
),
|
||||||
|
]
|
||||||
50
pms_integration/migrations/0001_initial.py
Normal file
50
pms_integration/migrations/0001_initial.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 04:55
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hotels', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PMSConfiguration',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='Название PMS')),
|
||||||
|
('url', models.URLField(verbose_name='URL API')),
|
||||||
|
('token', models.CharField(blank=True, max_length=255, null=True, verbose_name='Токен')),
|
||||||
|
('public_key', models.CharField(blank=True, max_length=255, null=True, verbose_name='Публичный ключ')),
|
||||||
|
('private_key', models.CharField(blank=True, max_length=255, null=True, verbose_name='Приватный ключ')),
|
||||||
|
('username', models.CharField(blank=True, max_length=255, null=True, verbose_name='Логин')),
|
||||||
|
('password', models.CharField(blank=True, max_length=255, null=True, verbose_name='Пароль')),
|
||||||
|
('plugin_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Плагин')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'PMS система',
|
||||||
|
'verbose_name_plural': 'PMS системы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PMSIntegrationLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('checked_at', models.DateTimeField(auto_now_add=True, verbose_name='Время проверки')),
|
||||||
|
('status', models.CharField(choices=[('success', 'Успех'), ('error', 'Ошибка')], max_length=50, verbose_name='Статус')),
|
||||||
|
('message', models.TextField(blank=True, null=True, verbose_name='Сообщение')),
|
||||||
|
('hotel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hotels.hotel', verbose_name='Отель')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Журнал интеграции PMS',
|
||||||
|
'verbose_name_plural': 'Журналы интеграции PMS',
|
||||||
|
'indexes': [models.Index(fields=['hotel'], name='pms_integra_hotel_i_ade4da_idx'), models.Index(fields=['checked_at'], name='pms_integra_checked_938acc_idx'), models.Index(fields=['status'], name='pms_integra_status_358b64_idx')],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
19
pms_integration/migrations/0002_pmsconfiguration_hotels.py
Normal file
19
pms_integration/migrations/0002_pmsconfiguration_hotels.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 06:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hotels', '0003_rename_external_id_hotel_external_id_pms_and_more'),
|
||||||
|
('pms_integration', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='pmsconfiguration',
|
||||||
|
name='hotels',
|
||||||
|
field=models.ManyToManyField(related_name='pms_configurations', to='hotels.hotel', verbose_name='Отели'),
|
||||||
|
),
|
||||||
|
]
|
||||||
116
pms_integration/plugins/travelline_pms.py
Normal file
116
pms_integration/plugins/travelline_pms.py
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
from datetime import datetime
|
||||||
|
from .base_plugin import BasePMSPlugin
|
||||||
|
|
||||||
|
class TravelLinePMSPlugin(BasePMSPlugin):
|
||||||
|
"""
|
||||||
|
Плагин для интеграции с PMS TravelLine.
|
||||||
|
"""
|
||||||
|
BASE_URL = "https://partner.tlintegration.com/api/webpms/v1"
|
||||||
|
|
||||||
|
def __init__(self, pms_config):
|
||||||
|
"""
|
||||||
|
Инициализация плагина с конфигурацией PMS.
|
||||||
|
|
||||||
|
:param pms_config: Конфигурация PMS (объект PMSConfiguration).
|
||||||
|
"""
|
||||||
|
super().__init__(pms_config)
|
||||||
|
self.api_key = pms_config.token
|
||||||
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def _get_headers(self):
|
||||||
|
"""
|
||||||
|
Возвращает заголовки для запросов.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
def _fetch_data(self):
|
||||||
|
"""
|
||||||
|
Получение данных из API TravelLine (поиск бронирований).
|
||||||
|
|
||||||
|
:return: Список номеров бронирований.
|
||||||
|
"""
|
||||||
|
url = f"{self.BASE_URL}/bookings"
|
||||||
|
params = {
|
||||||
|
"roomId": self.pms_config.room_id,
|
||||||
|
"modifiedFrom": self.pms_config.modified_from,
|
||||||
|
"modifiedTo": self.pms_config.modified_to,
|
||||||
|
"state": self.pms_config.state,
|
||||||
|
"affectsPeriodFrom": self.pms_config.affects_period_from,
|
||||||
|
"affectsPeriodTo": self.pms_config.affects_period_to,
|
||||||
|
}
|
||||||
|
params = {k: v for k, v in params.items() if v is not None}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url, headers=self._get_headers(), params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
self.logger.info("Данные успешно получены из API TravelLine.")
|
||||||
|
return response.json().get("bookingNumbers", [])
|
||||||
|
except requests.RequestException as e:
|
||||||
|
self.logger.error(f"Ошибка при запросе к API TravelLine: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def fetch_data(self):
|
||||||
|
"""
|
||||||
|
Обертка для получения данных из API TravelLine с дополнительной обработкой.
|
||||||
|
|
||||||
|
:return: Список номеров бронирований.
|
||||||
|
"""
|
||||||
|
return self._fetch_data()
|
||||||
|
|
||||||
|
def get_default_parser_settings(self):
|
||||||
|
"""
|
||||||
|
Возвращает настройки парсера по умолчанию.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"field_mapping": {
|
||||||
|
"reservation_id": "bookingNumber",
|
||||||
|
"check_in": "actualCheckInDateTime",
|
||||||
|
"check_out": "actualCheckOutDateTime",
|
||||||
|
"room_number": "roomId",
|
||||||
|
"status": "state",
|
||||||
|
},
|
||||||
|
"date_format": "%Y-%m-%dT%H:%M"
|
||||||
|
}
|
||||||
|
|
||||||
|
def process_data(self, booking_number, room_stay_id, action, actual_date_time):
|
||||||
|
"""
|
||||||
|
Обработка данных для заселения или выселения проживания.
|
||||||
|
|
||||||
|
:param booking_number: Номер бронирования.
|
||||||
|
:param room_stay_id: Идентификатор проживания.
|
||||||
|
:param action: Действие ("check-in" или "check-out").
|
||||||
|
:param actual_date_time: Фактические дата и время.
|
||||||
|
:return: Ответ API.
|
||||||
|
"""
|
||||||
|
if action not in ["check-in", "check-out"]:
|
||||||
|
raise ValueError("Invalid action. Must be 'check-in' or 'check-out'.")
|
||||||
|
|
||||||
|
url = f"{self.BASE_URL}/bookings/{booking_number}/room-stays/{room_stay_id}/{action}"
|
||||||
|
payload = {
|
||||||
|
f"actual{action.capitalize()}DateTime": actual_date_time
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, headers=self._get_headers(), json=payload)
|
||||||
|
response.raise_for_status()
|
||||||
|
self.logger.info(f"Успешно выполнено действие '{action}' для бронирования {booking_number}.")
|
||||||
|
return response.json()
|
||||||
|
except requests.RequestException as e:
|
||||||
|
self.logger.error(f"Ошибка при выполнении действия '{action}': {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def validate_plugin(self):
|
||||||
|
"""
|
||||||
|
Проверка плагина на соответствие требованиям.
|
||||||
|
"""
|
||||||
|
required_methods = ["fetch_data", "get_default_parser_settings", "_fetch_data"]
|
||||||
|
for method in required_methods:
|
||||||
|
if not hasattr(self, method):
|
||||||
|
raise ValueError(f"Плагин {type(self).__name__} не реализует метод {method}.")
|
||||||
|
self.logger.info(f"Плагин {self.__class__.__name__} успешно прошел валидацию.")
|
||||||
|
return True
|
||||||
30
scheduler/migrations/0001_initial.py
Normal file
30
scheduler/migrations/0001_initial.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 04:55
|
||||||
|
|
||||||
|
import scheduler.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ScheduledTask',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('task_name', models.CharField(max_length=255, verbose_name='Название задачи')),
|
||||||
|
('function_path', models.CharField(choices=scheduler.models.get_available_functions, max_length=500, verbose_name='Путь к функции (модуль.функция)')),
|
||||||
|
('minutes', models.CharField(default='*', max_length=255, verbose_name='Минуты')),
|
||||||
|
('hours', models.CharField(default='*', max_length=255, verbose_name='Часы')),
|
||||||
|
('days', models.CharField(default='*', max_length=255, verbose_name='Дни')),
|
||||||
|
('months', models.CharField(default='*', max_length=255, verbose_name='Месяцы')),
|
||||||
|
('weekdays', models.JSONField(default=list, verbose_name='Дни недели')),
|
||||||
|
('active', models.BooleanField(default=True, verbose_name='Активно')),
|
||||||
|
('last_run', models.DateTimeField(blank=True, null=True, verbose_name='Последний запуск')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
63
users/migrations/0001_initial.py
Normal file
63
users/migrations/0001_initial.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-25 04:55
|
||||||
|
|
||||||
|
import django.contrib.auth.models
|
||||||
|
import django.contrib.auth.validators
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0012_alter_user_first_name_max_length'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='User',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||||
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||||
|
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||||
|
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||||
|
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||||
|
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||||
|
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||||
|
('telegram_id', models.BigIntegerField(blank=True, null=True, unique=True, verbose_name='ID Телеграм')),
|
||||||
|
('chat_id', models.BigIntegerField(blank=True, null=True, unique=True, verbose_name='ID чата в телеграм')),
|
||||||
|
('role', models.CharField(choices=[('admin', 'Администратор системы'), ('hotel_user', 'Сотрудник отеля')], default='hotel_user', max_length=20, verbose_name='Роль')),
|
||||||
|
('confirmed', models.BooleanField(default=False, verbose_name='Подтвержден')),
|
||||||
|
('groups', models.ManyToManyField(blank=True, related_name='custom_user_set', to='auth.group')),
|
||||||
|
('user_permissions', models.ManyToManyField(blank=True, related_name='custom_user_set', to='auth.permission')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Пользователь',
|
||||||
|
'verbose_name_plural': 'Пользователи',
|
||||||
|
},
|
||||||
|
managers=[
|
||||||
|
('objects', django.contrib.auth.models.UserManager()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='NotificationSettings',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('telegram_enabled', models.BooleanField(default=True, verbose_name='Уведомления в Telegram')),
|
||||||
|
('email_enabled', models.BooleanField(default=False, verbose_name='Уведомления по Email')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Email для уведомлений')),
|
||||||
|
('notification_time', models.TimeField(default='09:00', verbose_name='Время отправки уведомлений')),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='users.user', verbose_name='Пользователь')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Способ оповещения',
|
||||||
|
'verbose_name_plural': 'Способы оповещений',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user