plugins development
This commit is contained in:
@@ -75,35 +75,48 @@ async def delete_hotel(update: Update, context):
|
|||||||
await query.edit_message_text("Отель не найден.")
|
await query.edit_message_text("Отель не найден.")
|
||||||
|
|
||||||
|
|
||||||
from pms_integration.manager import PMSIntegrationManager
|
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
from hotels.models import Hotel
|
|
||||||
|
|
||||||
# async def check_pms(update, context):
|
# async def check_pms(update, context):
|
||||||
# query = update.callback_query
|
# query = update.callback_query
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# # Логирование callback_data
|
# # Получение hotel_id из callback_data
|
||||||
# hotel_id = query.data.split("_")[2]
|
# hotel_id = query.data.split("_")[2]
|
||||||
# print(f"Selected hotel id: {hotel_id}")
|
# print(f"Selected hotel id: {hotel_id}")
|
||||||
# context.user_data["selected_hotel"] = hotel_id
|
# context.user_data["selected_hotel"] = hotel_id
|
||||||
|
|
||||||
# # Инициализация менеджера PMS
|
# # Инициализация менеджера PMS
|
||||||
# pms_manager = PMSIntegrationManager(hotel_id=hotel_id)
|
# pms_manager = PMSIntegrationManager(hotel_id=hotel_id)
|
||||||
# print(f"Loaded hotel: {pms_manager.hotel}")
|
# print(f"Инициализация PMS менеджера для отеля ID: {hotel_id}")
|
||||||
# await pms_manager.load_hotel() # Асинхронная загрузка отеля
|
|
||||||
# pms_manager.load_plugin() # Загрузка плагина
|
|
||||||
|
|
||||||
# # Получение данных
|
# # Загрузка данных отеля
|
||||||
|
# await pms_manager.load_hotel()
|
||||||
|
# print(f"Данные отеля загружены: {pms_manager.hotel}")
|
||||||
|
|
||||||
|
# # Загрузка плагина
|
||||||
|
# pms_manager.load_plugin()
|
||||||
|
# print(f"Плагин загружен: {pms_manager.plugin}")
|
||||||
|
|
||||||
|
# # Получение данных из PMS
|
||||||
# data = pms_manager.fetch_data()
|
# data = pms_manager.fetch_data()
|
||||||
# print(f'PMS_managerПолучено записей: {len(data)}\n\n\n___')
|
# print(f"Данные получены из PMS: {len(data)} записей")
|
||||||
# print(f'Данные {data}\n\n\n')
|
# # print(f"Полные данные: {data}\n\n\n")
|
||||||
# # Логирование
|
|
||||||
|
# # Сохранение лога успешной интеграции
|
||||||
# await pms_manager.save_log("success", f"Успешная интеграция с PMS {pms_manager.pms_config.name}.")
|
# await pms_manager.save_log("success", f"Успешная интеграция с PMS {pms_manager.pms_config.name}.")
|
||||||
|
|
||||||
|
# # Ответ пользователю
|
||||||
# await query.edit_message_text(f"Интеграция успешна! Получено {len(data)} записей.")
|
# await query.edit_message_text(f"Интеграция успешна! Получено {len(data)} записей.")
|
||||||
|
|
||||||
|
# # Обработка данных и запись в БД
|
||||||
|
# await pms_manager.plugin._save_to_db(data, hotel_id=int(hotel_id))
|
||||||
|
# print(f"Данные успешно сохранены в базу данных.")
|
||||||
|
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# # Логирование ошибок
|
# # Логирование ошибки
|
||||||
|
# print(f"Ошибка при выполнении check_pms: {e}")
|
||||||
# if 'pms_manager' in locals() and pms_manager.hotel:
|
# if 'pms_manager' in locals() and pms_manager.hotel:
|
||||||
# await pms_manager.save_log("error", str(e))
|
# await pms_manager.save_log("error", str(e))
|
||||||
# await query.edit_message_text(f"❌ Ошибка: {e}")
|
# await query.edit_message_text(f"❌ Ошибка: {e}")
|
||||||
@@ -112,45 +125,45 @@ async def check_pms(update, context):
|
|||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Получение hotel_id из callback_data
|
# Получение ID отеля из callback_data
|
||||||
hotel_id = query.data.split("_")[2]
|
hotel_id = query.data.split("_")[2]
|
||||||
print(f"Selected hotel id: {hotel_id}")
|
|
||||||
context.user_data["selected_hotel"] = hotel_id
|
|
||||||
|
|
||||||
# Инициализация менеджера PMS
|
# Получение конфигурации отеля и PMS
|
||||||
|
hotel = await sync_to_async(Hotel.objects.select_related('pms').get)(id=hotel_id)
|
||||||
|
pms_config = hotel.pms
|
||||||
|
|
||||||
|
if not pms_config:
|
||||||
|
await query.edit_message_text("PMS конфигурация не найдена.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Создаем экземпляр PMSIntegrationManager
|
||||||
pms_manager = PMSIntegrationManager(hotel_id=hotel_id)
|
pms_manager = PMSIntegrationManager(hotel_id=hotel_id)
|
||||||
print(f"Инициализация PMS менеджера для отеля ID: {hotel_id}")
|
await sync_to_async(pms_manager.load_hotel)()
|
||||||
|
await sync_to_async(pms_manager.load_plugin)()
|
||||||
|
|
||||||
# Загрузка данных отеля
|
# Проверяем, какой способ интеграции использовать
|
||||||
await pms_manager.load_hotel()
|
if hasattr(pms_manager.plugin, 'fetch_data'):
|
||||||
print(f"Данные отеля загружены: {pms_manager.hotel}")
|
# Плагин поддерживает метод fetch_data
|
||||||
|
data = await sync_to_async(pms_manager.plugin.fetch_data)()
|
||||||
|
elif pms_config.api_url and pms_config.token:
|
||||||
|
# Используем прямой запрос к API
|
||||||
|
from pms_integration.api_client import APIClient
|
||||||
|
api_client = APIClient(base_url=pms_config.api_url, access_token=pms_config.token)
|
||||||
|
data = await sync_to_async(api_client.fetch_reservations)()
|
||||||
|
else:
|
||||||
|
# Если подходящий способ не найден
|
||||||
|
await query.edit_message_text("Подходящий способ интеграции с PMS не найден.")
|
||||||
|
return
|
||||||
|
|
||||||
# Загрузка плагина
|
# Сохраняем данные в базу
|
||||||
pms_manager.load_plugin()
|
from bot.utils.database import save_reservations
|
||||||
print(f"Плагин загружен: {pms_manager.plugin}")
|
await sync_to_async(save_reservations)(data)
|
||||||
|
|
||||||
# Получение данных из PMS
|
|
||||||
data = pms_manager.fetch_data()
|
|
||||||
print(f"Данные получены из PMS: {len(data)} записей")
|
|
||||||
# print(f"Полные данные: {data}\n\n\n")
|
|
||||||
|
|
||||||
# Сохранение лога успешной интеграции
|
|
||||||
await pms_manager.save_log("success", f"Успешная интеграция с PMS {pms_manager.pms_config.name}.")
|
|
||||||
|
|
||||||
# Ответ пользователю
|
|
||||||
await query.edit_message_text(f"Интеграция успешна! Получено {len(data)} записей.")
|
|
||||||
|
|
||||||
# Обработка данных и запись в БД
|
|
||||||
await pms_manager.plugin._save_to_db(data, hotel_id=int(hotel_id))
|
|
||||||
print(f"Данные успешно сохранены в базу данных.")
|
|
||||||
|
|
||||||
|
# Уведомляем об успешной интеграции
|
||||||
|
await query.edit_message_text(f"Интеграция PMS {pms_config.name} завершена успешно.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Логирование ошибки
|
# Обрабатываем и логируем ошибки
|
||||||
print(f"Ошибка при выполнении check_pms: {e}")
|
await query.edit_message_text(f"Ошибка: {str(e)}")
|
||||||
if 'pms_manager' in locals() and pms_manager.hotel:
|
|
||||||
await pms_manager.save_log("error", str(e))
|
|
||||||
await query.edit_message_text(f"❌ Ошибка: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
async def setup_rooms(update: Update, context):
|
async def setup_rooms(update: Update, context):
|
||||||
"""Настроить номера отеля."""
|
"""Настроить номера отеля."""
|
||||||
|
|||||||
@@ -35,3 +35,21 @@ async def get_reservations(hotel_id, start_date=None, end_date=None):
|
|||||||
if end_date:
|
if end_date:
|
||||||
query = query.filter(check_out__lte=end_date)
|
query = query.filter(check_out__lte=end_date)
|
||||||
return await sync_to_async(list)(query.prefetch_related('guests'))
|
return await sync_to_async(list)(query.prefetch_related('guests'))
|
||||||
|
|
||||||
|
def save_reservations(data):
|
||||||
|
"""
|
||||||
|
Сохранение данных бронирований в базу данных.
|
||||||
|
:param data: Список бронирований.
|
||||||
|
"""
|
||||||
|
for booking in data:
|
||||||
|
Reservation.objects.update_or_create(
|
||||||
|
external_id=booking['id'],
|
||||||
|
defaults={
|
||||||
|
'check_in': booking['begin_date'],
|
||||||
|
'check_out': booking['end_date'],
|
||||||
|
'amount': booking['amount'],
|
||||||
|
'notes': booking.get('notes', ''),
|
||||||
|
'guest_name': booking['client']['fio'],
|
||||||
|
'guest_phone': booking['client']['phone'],
|
||||||
|
},
|
||||||
|
)
|
||||||
116
hotels/migrations/0001_initial.py
Normal file
116
hotels/migrations/0001_initial.py
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-09 09:30
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='APIConfiguration',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='Название API')),
|
||||||
|
('url', models.URLField(verbose_name='URL API')),
|
||||||
|
('token', 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='Пароль')),
|
||||||
|
('last_updated', models.DateTimeField(auto_now=True, verbose_name='Дата последнего обновления')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Конфигурация API',
|
||||||
|
'verbose_name_plural': 'Конфигурации API',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FraudLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('reservation_id', models.BigIntegerField(unique=True, verbose_name='ID бронирования')),
|
||||||
|
('guest_name', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('check_in_date', models.DateField()),
|
||||||
|
('detected_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('message', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Журнал мошенничества',
|
||||||
|
'verbose_name_plural': 'Журналы мошенничества',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Guest',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='Имя гостя')),
|
||||||
|
('birthdate', models.DateField(blank=True, null=True, verbose_name='Дата рождения')),
|
||||||
|
('phone', models.CharField(blank=True, max_length=50, null=True, verbose_name='Телефон')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Email')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Гость',
|
||||||
|
'verbose_name_plural': 'Гости',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Reservation',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('reservation_id', models.BigIntegerField(unique=True, verbose_name='ID бронирования')),
|
||||||
|
('room_number', models.CharField(max_length=50, 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(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='Цена')),
|
||||||
|
('discount', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='Скидка')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Бронирование',
|
||||||
|
'verbose_name_plural': 'Бронирования',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserHotel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Пользователь отеля',
|
||||||
|
'verbose_name_plural': 'Пользователи отелей',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='APIRequestLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('request_time', models.DateTimeField(auto_now_add=True, verbose_name='Время запроса')),
|
||||||
|
('response_status', models.IntegerField(validators=[django.core.validators.MinValueValidator(100), django.core.validators.MaxValueValidator(599)], verbose_name='HTTP статус ответа')),
|
||||||
|
('response_data', models.JSONField(blank=True, null=True, verbose_name='Данные ответа')),
|
||||||
|
('api', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hotels.apiconfiguration', verbose_name='API')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Журнал запросов API',
|
||||||
|
'verbose_name_plural': 'Журналы запросов API',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Hotel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='Название отеля')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Создан')),
|
||||||
|
('api', models.OneToOneField(blank=True, help_text='API, связанный с этим отелем.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='hotels.apiconfiguration', verbose_name='API')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Отель',
|
||||||
|
'verbose_name_plural': 'Отели',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
42
hotels/migrations/0002_initial.py
Normal file
42
hotels/migrations/0002_initial.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-09 09:30
|
||||||
|
|
||||||
|
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='userhotel',
|
||||||
|
name='hotel',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='hotel_users', to='hotels.hotel', verbose_name='Отель'),
|
||||||
|
),
|
||||||
|
]
|
||||||
30
hotels/migrations/0003_initial.py
Normal file
30
hotels/migrations/0003_initial.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-09 09:30
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hotels', '0002_initial'),
|
||||||
|
('users', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userhotel',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_hotels', to='users.user', verbose_name='Пользователь'),
|
||||||
|
),
|
||||||
|
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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
hotels/migrations/__init__.py
Normal file
0
hotels/migrations/__init__.py
Normal file
@@ -118,9 +118,10 @@ class Guest(models.Model):
|
|||||||
verbose_name = "Гость"
|
verbose_name = "Гость"
|
||||||
verbose_name_plural = "Гости"
|
verbose_name_plural = "Гости"
|
||||||
|
|
||||||
|
|
||||||
class FraudLog(models.Model):
|
class FraudLog(models.Model):
|
||||||
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="frauds")
|
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="frauds")
|
||||||
reservation_id = models.CharField(max_length=255)
|
reservation_id = models.BigIntegerField(unique=True, verbose_name="ID бронирования")
|
||||||
guest_name = models.CharField(max_length=255, null=True, blank=True)
|
guest_name = models.CharField(max_length=255, null=True, blank=True)
|
||||||
check_in_date = models.DateField()
|
check_in_date = models.DateField()
|
||||||
detected_at = models.DateTimeField(auto_now_add=True)
|
detected_at = models.DateTimeField(auto_now_add=True)
|
||||||
@@ -128,3 +129,7 @@ class FraudLog(models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"FRAUD: {self.guest_name} ({self.check_in_date})"
|
return f"FRAUD: {self.guest_name} ({self.check_in_date})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Журнал мошенничества"
|
||||||
|
verbose_name_plural = "Журналы мошенничества"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2024-12-09 04:50
|
# Generated by Django 5.1.4 on 2024-12-09 09:30
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@@ -9,7 +9,7 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('hotels', '__first__'),
|
('hotels', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|||||||
78
pms_integration/plugins/realtycalendar_pms.py
Normal file
78
pms_integration/plugins/realtycalendar_pms.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import hashlib
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from hotels.models import Reservation
|
||||||
|
|
||||||
|
from pms_integration.plugins.base_plugin import BasePMSPlugin
|
||||||
|
|
||||||
|
|
||||||
|
class RealtyCalendarPlugin(BasePMSPlugin):
|
||||||
|
"""
|
||||||
|
Плагин для взаимодействия с RealtyCalendar.
|
||||||
|
"""
|
||||||
|
def __init__(self, config):
|
||||||
|
super().__init__(config)
|
||||||
|
self.public_key = config.token # Используем `token` как публичный ключ
|
||||||
|
self.private_key = config.password # Используем `password` как приватный ключ
|
||||||
|
self.base_url = config.url
|
||||||
|
|
||||||
|
def generate_sign(self, params):
|
||||||
|
"""
|
||||||
|
Генерация подписи запроса.
|
||||||
|
:param params: Параметры запроса.
|
||||||
|
:return: Подпись.
|
||||||
|
"""
|
||||||
|
sorted_keys = sorted(params.keys())
|
||||||
|
data_string = ''.join(f"{key}={params[key]}" for key in sorted_keys)
|
||||||
|
sign_string = f"{data_string}{self.private_key}"
|
||||||
|
return hashlib.md5(sign_string.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
|
def fetch_data(self, start_date=None, end_date=None):
|
||||||
|
"""
|
||||||
|
Получение данных из RealtyCalendar.
|
||||||
|
:param start_date: Начальная дата (формат YYYY-MM-DD).
|
||||||
|
:param end_date: Конечная дата (формат YYYY-MM-DD).
|
||||||
|
:return: Список данных бронирования.
|
||||||
|
"""
|
||||||
|
if not start_date:
|
||||||
|
start_date = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
if not end_date:
|
||||||
|
end_date = (datetime.now() + timedelta(days=1)).strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'begin_date': start_date,
|
||||||
|
'end_date': end_date,
|
||||||
|
}
|
||||||
|
params['sign'] = self.generate_sign(params)
|
||||||
|
|
||||||
|
url = f"{self.base_url}/bookings/{self.public_key}/"
|
||||||
|
headers = {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(url, json=params, headers=headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
return data.get('bookings', [])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_data(bookings):
|
||||||
|
"""
|
||||||
|
Сохранение данных бронирования в базу данных.
|
||||||
|
:param bookings: Список бронирований.
|
||||||
|
"""
|
||||||
|
for booking in bookings:
|
||||||
|
Reservation.objects.update_or_create(
|
||||||
|
external_id=booking['id'],
|
||||||
|
defaults={
|
||||||
|
'check_in': booking['begin_date'],
|
||||||
|
'check_out': booking['end_date'],
|
||||||
|
'amount': booking['amount'],
|
||||||
|
'notes': booking.get('notes', ''),
|
||||||
|
'guest_name': booking['client']['fio'],
|
||||||
|
'guest_phone': booking['client']['phone'],
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2024-12-09 04:50
|
# Generated by Django 5.1.4 on 2024-12-09 09:30
|
||||||
|
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
import django.contrib.auth.validators
|
import django.contrib.auth.validators
|
||||||
|
|||||||
Reference in New Issue
Block a user