import logging from datetime import datetime, timedelta import requests from asgiref.sync import sync_to_async from hotels.models import Hotel, Reservation from .base_plugin import BasePMSPlugin class EcviPMSPlugin(BasePMSPlugin): """ Плагин для интеграции с PMS Ecvi (интерфейс для получения данных об отеле). """ def __init__(self, pms_config): super().__init__(pms_config) # Инициализация логгера self.logger = logging.getLogger(self.__class__.__name__) # Логгер с именем класса handler_console = logging.StreamHandler() # Потоковый обработчик для вывода в консоль handler_file = logging.FileHandler('ecvi_pms_plugin.log') # Обработчик для записи в файл formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') handler_console.setFormatter(formatter) handler_file.setFormatter(formatter) # Добавляем оба обработчика к логгеру self.logger.addHandler(handler_console) self.logger.addHandler(handler_file) self.logger.setLevel(logging.DEBUG) # Уровень логирования # Инициализация параметров API self.api_url = pms_config.url self.token = pms_config.token self.username = pms_config.username self.password = pms_config.password self.pagination_count = 50 # Максимальное количество записей на страницу (если используется пагинация) def get_default_parser_settings(self): """ Возвращает настройки парсера по умолчанию. """ self.logger.debug(f"get_default_parser_settings. pms_config: {self.pms_config}") return { "field_mapping": { "check_in": "checkin", "check_out": "checkout", "room_number": "room_name", # Заменили на room_number "room_type_name": "room_type", "status": "occupancy", }, "date_format": "%Y-%m-%dT%H:%M:%S" } async def _fetch_data(self): """ Получает данные из PMS API, фильтрует и сохраняет в базу данных. """ now = datetime.now() current_date = now.strftime('%Y-%m-%d') yesterday_date = (now - timedelta(days=1)).strftime('%Y-%m-%d') headers = { "Content-Type": "application/json", } data = { "token": self.token, } try: # Запрос данных из PMS API response = await sync_to_async(requests.post)(self.api_url, headers=headers, json=data, auth=(self.username, self.password)) response.raise_for_status() # Если ошибка, выбросит исключение data = response.json() # Преобразуем ответ в JSON self.logger.debug(f"Получены данные с API: {data}") except requests.exceptions.RequestException as e: self.logger.error(f"Ошибка запроса: {e}") return [] self.logger.debug(f"\n\n\n\n\ndata: {data}\n\n\n\n\n") # Фильтрация данных filtered_data = [ { 'reservation_id': item.get('task_id'), 'room_number': item.get('room_number'), 'room_type': item.get('room_type'), 'checkin': datetime.strptime(item.get('checkin'), '%Y-%m-%d %H:%M:%S'), 'checkout': datetime.strptime(item.get('checkout'), '%Y-%m-%d %H:%M:%S'), 'status': item.get('occupancy') } for item in data if isinstance(item, dict) and item.get('occupancy') in ['проживание', 'под выезд', 'под заезд'] ] self.logger.debug(f"filtered_data: {filtered_data}") # Сохранение данных в базу данных for item in filtered_data: await self._save_to_db(item) self.logger.debug(f"Данные успешно сохранены.") return filtered_data async def _save_to_db(self, item): """ Сохраняет данные в БД (например, информацию о номере). """ try: # Получаем отель по настройкам PMS hotel = await sync_to_async(Hotel.objects.get)(pms=self.pms_config) self.logger.debug(f"Отель найден: {hotel.name}") # Проверяем, существует ли уже резервация с таким внешним ID reservation_id = item.get('reservation_id') self.logger.debug(f"-----\n\n\nITEM : {item}\n\n\n---") if not reservation_id: self.logger.error("Ошибка: 'reservation_id' отсутствует в данных.") return existing_reservation = await sync_to_async(Reservation.objects.filter)(reservation_id=reservation_id) # Теперь вызываем .first() после асинхронного вызова existing_reservation = await sync_to_async(existing_reservation.first)() if existing_reservation: self.logger.debug(f"Резервация {reservation_id} уже существует. Обновляем...") await sync_to_async(Reservation.objects.update_or_create)( reservation_id=reservation_id, defaults={ 'room_number': item.get('room_number'), 'room_type': item.get('room_type'), 'check_in': item.get('checkin'), 'check_out': item.get('checkout'), 'status': item.get('status'), 'hotel': hotel } ) self.logger.debug(f"Резервация обновлена.") else: self.logger.debug(f"Резервация не найдена, создаем новую...") reservation = await sync_to_async(Reservation.objects.create)( reservation_id=reservation_id, room_number=item.get('room_number'), room_type=item.get('room_type'), check_in=item.get('checkin'), check_out=item.get('checkout'), status=item.get('status'), hotel=hotel ) self.logger.debug(f"Новая резервация создана с ID: {reservation.reservation_id}") except Exception as e: self.logger.error(f"Ошибка сохранения данных: {e}") def validate_plugin(self): """ Проверка на соответствие требованиям. Можно проверить наличие методов или полей. """ # Проверяем наличие обязательных методов required_methods = ["fetch_data", "get_default_parser_settings", "_fetch_data"] for m in required_methods: if not hasattr(self, m): raise ValueError(f"Плагин {type(self).__name__} не реализует метод {m}.") self.logger.debug(f"Плагин {self.__class__.__name__} прошел валидацию.") return True