Гостиничный сайт отличается от обычного каталога тем, что посетитель выбирает не товар, а временной слот. Номер сам по себе — набор характеристик (площадь, вместимость, вид из окна). Но без свободных дат это мёртвая карточка. Весь проект строится вокруг календаря доступности и механики бронирования, а не вокруг красивой вёрстки. Проблема: посетитель видит красивые фото, но при попытке забронировать — календарь не обновлён или цена не соответствует сезону. Или интеграция с Booking.com отсутствует, и отель получает овербукинг. Мы решаем эти проблемы на уровне архитектуры: движок бронирования на Highload-блоках, сезонные тарифы, синхронизация с PMS.
Как работает система бронирования?
Ядро проекта — управление доступностью номеров. Задача: пользователь выбирает даты, система показывает доступные типы с ценами, бронирует и блокирует номер.
Хранение доступности — Highload-блок RoomInventory. Каждая строка — одна ночь для одного физического номера.
| Поле | Тип | Описание |
|---|---|---|
| UF_DATE | date | Дата ночи (например, 2025-07-15 — ночь с 15 на 16 июля) |
| UF_ROOM_ID | integer | ID физического номера |
| UF_ROOM_TYPE_ID | integer | ID типа номера |
| UF_STATUS | integer | 0 = свободен, 1 = забронирован, 2 = заблокирован, 3 = заселён |
| UF_BOOKING_ID | integer | ID заказа (из модуля sale) |
| UF_RATE | float | Тариф за эту ночь (с учётом сезона) |
Highload-блок — ORM-обёртка над таблицей с автоматическим API. При 100 номерах и горизонте 365 дней — 36 500 строк. Обязательные индексы: составной на (UF_DATE, UF_ROOM_TYPE_ID, UF_STATUS) и (UF_BOOKING_ID).
Алгоритм проверки доступности. Гость вводит check_in, check_out, guests. Система находит типы номеров с хотя бы одним физическим номером, свободным на все ночи.
public function getAvailableRoomTypes( \Bitrix\Main\Type\Date $checkIn, \Bitrix\Main\Type\Date $checkOut, int $guests ): array { $nights = $checkOut->getDiff($checkIn)->days; $dates = []; for ($i = 0; $i < $nights; $i++) { $d = clone $checkIn; $d->add(new \DateInterval("P{$i}D")); $dates[] = $d->format('Y-m-d'); } // Находим номера, занятые хотя бы в одну из ночей $busyRooms = RoomInventoryTable::getList([ 'select' => ['UF_ROOM_ID'], 'filter' => [ 'UF_DATE' => $dates, '!UF_STATUS' => 0, ], 'group' => ['UF_ROOM_ID'], ])->fetchAll(); $busyRoomIds = array_column($busyRooms, 'UF_ROOM_ID'); // Далее — исключаем занятые номера и фильтруем по вместимости } Подход через HAVING COUNT(*) = {$nights} корректнее:
SQL-запрос проверки доступности
SELECT UF_ROOM_ID, UF_ROOM_TYPE_ID FROM hl_room_inventory WHERE UF_DATE IN ('2025-07-15','2025-07-16','2025-07-17') AND UF_STATUS = 0 GROUP BY UF_ROOM_ID, UF_ROOM_TYPE_ID HAVING COUNT(*) = 3 Календарь доступности на фронте. Два поля — дата заезда и выезда. Реализация на flatpickr в режиме range. При открытии — AJAX-запрос за матрицей доступности: массив дат с признаком «есть свободные номера». Endpoint возвращает JSON:
{ "2025-07": { "15": {"available": true, "min_rate": 4500}, "16": {"available": true, "min_rate": 4500}, "17": {"available": false, "min_rate": null}, "18": {"available": true, "min_rate": 6200} } } Недоступные даты блокируются в календаре (disable). Минимальный тариф — при наведении. Запросы кэшируются через Bitrix\Main\Data\Cache с ключом availability_{month}_{year}.
Почему сезонное ценообразование увеличивает прибыль?
Highload-блок RatePlan:
| Поле | Тип |
|---|---|
| UF_ROOM_TYPE_ID | integer |
| UF_DATE_FROM | date |
| UF_DATE_TO | date |
| UF_WEEKDAY_RATE | float |
| UF_WEEKEND_RATE | float |
| UF_PRIORITY | integer |
При расчёте стоимости бронирования система перебирает каждую ночь, находит подходящий тарифный план и суммирует. Итоговая сумма — сумма по всем ночам.
Архитектура номерного фонда
Каждый тип номера — элемент инфоблока «Номерной фонд». Важно разделять тип (например, «Стандарт двухместный») и физические номера (20 комнат). Это ключевое архитектурное решение.
Структура инфоблока:
| Свойство | Тип | Назначение |
|---|---|---|
| CAPACITY | N (число) | Вместимость (основные места) |
| CAPACITY_EXTRA | N | Доп. места (раскладушка, детская кроватка) |
| AREA | N | Площадь, м² |
| AMENITIES | L (список, множественное) | Удобства: Wi-Fi, кондиционер, мини-бар, сейф |
| BED_TYPE | L (список) | Тип кровати: double, twin, king |
| VIEW | L (список) | Вид: море, город, сад, двор |
| FLOOR_RANGE | S (строка) | Этажи: «3-5» |
| GALLERY | F (файл, множественное) | Фотогалерея номера |
| PANORAMA_URL | S | Ссылка на 360-панораму |
| ROOM_COUNT | N | Количество физических номеров этого типа |
| MIN_STAY | N | Минимальное количество ночей |
| BASE_RATE | N | Базовый тариф за ночь (без сезонных наценок) |
Удобства (AMENITIES) — множественное свойство типа «Список». Не Highload-блок, потому что набор фиксирован (30-50 позиций). На фронте значения маппятся на иконки через конфиг.
Фотогалерея и виртуальный тур. Множественное свойство типа «Файл». Рендер — Swiper.js с lazy-загрузкой, превью через CFile::ResizeImageGet() на 600x400 с BX_RESIZE_IMAGE_PROPORTIONAL. Для 360-панорамы — Pannellum.js: библиотека принимает equirectangular-изображение и рендерит интерактивный обзор. Хранение — строковое свойство PANORAMA_URL. Pannellum инициализируется на клиенте:
pannellum.viewer('panorama-container', { type: 'equirectangular', panorama: roomData.panoramaUrl, autoLoad: true, compass: true, hotSpots: [ { pitch: -5, yaw: 120, type: 'info', text: 'Ванная комната' }, { pitch: 0, yaw: 240, type: 'info', text: 'Балкон с видом на море' } ] }); Hotspots задаются в JSON-свойстве инфоблока или в Highload-блоке, если нужна админ-панель.
Как iCal-синхронизация предотвращает овербукинг?
Гостиница продаёт номера на сайте и через OTA (Booking.com, Expedia). Без синхронизации — овербукинг. Channel Manager синхронизирует доступность и тарифы между PMS, сайтом и каналами.
iCal-синхронизация — простейший вариант. Booking.com и Airbnb отдают .ics-файлы. Битрикс-агент раз в 15 минут:
- Забирает
.icsпо URL (file_get_contentsили cURL) - Парсит
VEVENT— извлекаетDTSTART,DTEND,SUMMARY - Обновляет
RoomInventory:UF_STATUS = 2(заблокирован) - Генерирует исходящий
.icsс бронированиями сайта
Ограничение iCal: нет тарифов, задержка до 15 минут. Для 100+ номеров нужен API-коннектор. XML Push / API — через REST или SOAP (Booking.com Connectivity API). iCal-синхронизация в 10 раз проще API-интеграции, но менее гибкая.
PMS-интеграция. 1С:Отель — обмен через HTTP-сервис. Opera / Fidelio — SOAP с WSDL. Мы реализуем класс-обёртку над SoapClient с логированием.
Онлайн-оплата и предоплата. Бронирование через модуль sale. Заказ — одна позиция «Проживание в {тип}, {check_in} — {check_out}». Предоплата (20-30%) — кастомный обработчик OnSaleBeforeOrderAdd. Процент и первая ночь — типовые схемы.
Дополнительные модули
Личный кабинет гостя: авторизация (email + OAuth), мои бронирования, история поездок, программа лояльности. Баллы начисляются через обработчик OnSaleStatusOrderChange.
Мультиязычность: языковые версии (/en/, /de/), контент через свойства инфоблоков, hreflang. SEO и микроразметка: Schema.org Hotel + HotelRoom + Offer. Разметка генерируется автоматически.
Фотоцентричный дизайн: WebP с fallback, <picture> с srcset, lazy-load. Оригиналы до 3000px, превью 800x600.
Отзывы: Highload-блок Reviews с модерацией. Агрегированный рейтинг в свойстве инфоблока AVG_RATING.
Что входит в работу
- Аналитика и прототипирование (карта номерного фонда, логика бронирования)
- Дизайн (фотоцентричный UI, мобильная версия, календарь)
- Ядро бронирования (RoomInventory, проверка доступности, оформление заказа, оплата)
- Интеграции (PMS, Channel Manager, платёжные системы, REST API)
- Контент и SEO (микроразметка, мультиязычность, мета-шаблоны)
- Тестирование и запуск (нагрузочное, кроссбраузерное, деплой)
- Документация и обучение администраторов
- Постпроектное сопровождение и гарантия
Этапы и сроки
| Масштаб | Сроки |
|---|---|
| Мини-отель, 10-20 номеров, базовое бронирование | 4–8 недель |
| Гостиница, 50-100 номеров, Channel Manager, PMS | 10–16 недель |
| Сеть отелей, мультисайт, программа лояльности | 16–24 недели |
Сроки не включают фотосъёмку и создание 360-панорам — это параллельный процесс.
Прямое бронирование через сайт в 2-3 раза выгоднее для отеля, чем через OTA, за счёт отсутствия комиссии. Экономия составляет 15-25% от выручки. Система бронирования окупается в среднем за 6-12 месяцев за счёт роста прямых продаж.
Мы работаем в гостиничной разработке более 8 лет, выполнили более 50 проектов для гостиничного бизнеса. Наши инженеры — сертифицированные специалисты 1С-Битрикс. Закажите разработку сайта гостиницы — мы подберём архитектуру под ваш номерной фонд. Получите консультацию по архитектуре вашего сайта — оценим задачу и предложим решение.







