Разработка сайта гостиницы на 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Разработка сайта гостиницы на 1С-Битрикс
Сложная
от 1 недели до 3 месяцев
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Разработка сайта гостиницы на 1С-Битрикс

Гостиничный сайт отличается от обычного каталога одним свойством: посетитель выбирает не товар, а временной слот. Номер сам по себе — набор характеристик (площадь, вместимость, вид из окна). Но номер без свободных дат — мёртвая карточка. Весь проект строится вокруг календаря доступности и механики бронирования, а не вокруг красивой вёрстки. Если движок бронирования работает, остальное — шаблоны и контент. Если не работает — никакие панорамы и отзывы не спасут конверсию.

Типы номеров: инфоблок и его свойства

Каждый тип номера — элемент инфоблока «Номерной фонд». Не путать с конкретным физическим номером: тип «Стандарт двухместный» может включать 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 позиций) и не требует отдельного управления. Значения списка: WIFI, AC, MINIBAR, SAFE, BALCONY, BATHTUB, HAIRDRYER, KETTLE, TV, IRON. На фронте каждое значение маппится на иконку через конфиг.

Фотогалерея и виртуальный тур. Множественное свойство типа «Файл» для галереи. Рендер — Swiper.js с lazy-загрузкой, превью через CFile::ResizeImageGet() на 600x400 с BX_RESIZE_IMAGE_PROPORTIONAL. Для 360-панорамы — Pannellum.js: библиотека принимает equirectangular-изображение и рендерит интерактивный обзор в <div>. Хранение — строковое свойство PANORAMA_URL с путём к изображению в /upload/panoramas/. 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-блоке, если нужна административная панель для их редактирования.

Движок бронирования и управление доступностью

Это ядро проекта. Всё остальное — обвес. Задача: пользователь выбирает даты заезда и выезда, система показывает доступные типы номеров с ценами, пользователь бронирует, номер блокируется.

Хранение доступности — 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-блок, а не обычная таблица? Highload-блоки в Битриксе — это ORM-обёртка над обычной таблицей с автоматической генерацией API. HighloadBlockTable::compileEntity() создаёт класс с методами getList, add, update, delete. При 100 номерах и горизонте 365 дней — 36 500 строк. При 500 номерах — 182 500 строк. Highload-блок справляется, но индексы обязательны: составной индекс на (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');

    // Все номера, которые НЕ заняты ни в одну ночь
    // + фильтр по вместимости через связь с инфоблоком
    // ...
}

Подвох: запрос «найти номера, свободные на ВСЕ ночи» — не тривиальный SQL. Простой WHERE UF_STATUS = 0 AND UF_DATE IN (...) вернёт номера, свободные хотя бы в одну ночь. Правильный подход — найти занятые номера и исключить их. Или использовать HAVING COUNT(*) = {$nights} для группировки по UF_ROOM_ID со статусом «свободен».

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

Этот запрос возвращает физические номера, свободные на все три ночи. Далее группируем по UF_ROOM_TYPE_ID и получаем типы номеров с количеством доступных единиц.

Календарь доступности на фронте. Два поля: дата заезда и дата выезда. Реализация — flatpickr в режиме range или кастомный React-компонент на базе react-day-picker. При открытии календаря — 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 в flatpickr). Минимальный тариф показывается при наведении. Запрос матрицы — тяжёлый: нужно агрегировать RoomInventory по датам. Кэширование обязательно: Bitrix\Main\Data\Cache с ключом availability_{month}_{year}, сброс при любом изменении в RoomInventory через обработчик OnAfterUpdate.

Сезонное ценообразование. Тариф за ночь зависит от сезона, дня недели, загруженности. Хранение — 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

При расчёте стоимости бронирования система перебирает каждую ночь, находит подходящий RatePlan (по дате и типу номера, с наибольшим приоритетом), определяет день недели и берёт UF_WEEKDAY_RATE или UF_WEEKEND_RATE. Итоговая сумма — сумма тарифов по всем ночам. При заполнении RoomInventory агент Битрикса предзаполняет поле UF_RATE для каждой строки — это кэш расчётной цены, чтобы не вычислять при каждом запросе доступности.

Интеграция с Channel Manager

Гостиница продаёт номера не только на своём сайте, но и через Booking.com, Expedia, Ostrovok. Без синхронизации — овербукинг. Channel manager — промежуточный слой, который синхронизирует доступность и тарифы между PMS, сайтом и OTA-каналами.

iCal-синхронизация — простейший вариант. Booking.com и Airbnb отдают и принимают .ics-файлы с заблокированными датами. Битрикс-агент раз в 15 минут:

  1. Забирает .ics по URL каждого канала (file_get_contents или cURL)
  2. Парсит VEVENT блоки — извлекает DTSTART, DTEND, SUMMARY
  3. Обновляет RoomInventory: проставляет UF_STATUS = 2 (заблокирован) для соответствующих дат и номеров
  4. Генерирует исходящий .ics с бронированиями сайта и кладёт в /upload/ical/room_{id}.ics

Ограничение iCal: нет передачи тарифов, нет подтверждения бронирования, задержка синхронизации до 15 минут. Для небольшой гостиницы (до 30 номеров) — приемлемо. Для 100+ номеров с высокой загрузкой — нужен API-коннектор.

XML Push / API-интеграция с OTA-площадками — через REST или SOAP. Booking.com Connectivity API: отправка обновлений доступности (OTA_HotelAvailNotifRQ), тарифов (OTA_HotelRatePlanNotifRQ), получение бронирований (OTA_HotelResNotifRS). Формат — XML по спецификации OTA (OpenTravel Alliance). Это enterprise-уровень, требует сертификации подключения.

Интеграция с PMS

PMS (Property Management System) — система управления гостиницей: заселение, выселение, учёт, housekeeping. Распространённые: 1С:Отель, Fidelio, Opera PMS.

1С:Отель — обмен через COM-объект или HTTP-сервис на стороне 1С. Битрикс отправляет данные бронирования (гость, даты, номер, сумма), 1С создаёт документ «Бронь». Обратная синхронизация: 1С уведомляет сайт об изменении статуса (заселён, выселен, отменён) через webhook на endpoint Битрикса.

Opera / Fidelio — SOAP-интерфейс. WSDL-описание, вызов методов CreateReservation, ModifyReservation, CancelReservation. Аутентификация — WS-Security. Реализация на стороне Битрикса — класс-обёртка над SoapClient с логированием запросов.

Онлайн-оплата и предоплата

Бронирование через модуль sale. Заказ = одна товарная позиция «Проживание в {тип номера}, {check_in} — {check_out}». Цена — сумма тарифов по ночам. Свойства заказа: PROPERTY_CHECK_IN, PROPERTY_CHECK_OUT, PROPERTY_ROOM_TYPE_ID, PROPERTY_GUESTS.

Предоплата — не полная сумма, а процент (обычно 20-30%) или первая ночь. Реализация: кастомный обработчик OnSaleBeforeOrderAdd, который пересчитывает сумму к оплате. Полная сумма сохраняется в свойстве заказа PROPERTY_TOTAL_AMOUNT, к оплате — в поле PRICE корзины. Оставшаяся сумма — при заселении.

Платёжные системы: модуль sale поддерживает ЮKassa, CloudPayments, Stripe. Настройка — через административную панель, без кода.

Личный кабинет гостя

Авторизация — email + пароль, OAuth через Google, Apple. После входа:

  • Мои бронирования — список заказов из sale с фильтром по USER_ID. Статусы: ожидает оплаты, оплачен, подтверждён, заселён, завершён, отменён
  • История поездок — завершённые бронирования с возможностью оставить отзыв
  • Программа лояльности — баллы за бронирования. Highload-блок LoyaltyPoints: USER_ID, POINTS, OPERATION (начисление/списание), BOOKING_ID, DATE. Баллы начисляются обработчиком события OnSaleStatusOrderChange при переходе в статус «Завершён»

Мультиязычность

Для международных гостей — минимум 2-3 языка. Мультиязычность Битрикса через языковые версии сайта (/en/, /de/). Контент инфоблоков — через отдельные свойства (NAME_EN, DESCRIPTION_EN) или через модуль многосайтовости с привязкой инфоблоков к сайтам.

hreflang — в <head> каждой страницы:

<link rel="alternate" hreflang="ru" href="https://hotel.ru/rooms/standard/" />
<link rel="alternate" hreflang="en" href="https://hotel.ru/en/rooms/standard/" />

Переключатель валют — не конвертация в реальном времени, а фиксированные курсы в настройках модуля currency. Курсы обновляются агентом раз в сутки через API ЦБ или вручную.

SEO и микроразметка

Schema.org — тип Hotel + LodgingBusiness:

{
  "@context": "https://schema.org",
  "@type": "Hotel",
  "name": "Grand Hotel Riviera",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "ул. Набережная, 15",
    "addressLocality": "Сочи"
  },
  "starRating": {
    "@type": "Rating",
    "ratingValue": "4"
  },
  "amenityFeature": [
    {"@type": "LocationFeatureSpecification", "name": "Бассейн", "value": true},
    {"@type": "LocationFeatureSpecification", "name": "Парковка", "value": true}
  ]
}

Для каждого типа номера — разметка HotelRoom с occupancy, bed, amenityFeature. Для предложений — Offer с priceSpecification и availabilityStarts.

Фотоцентричный дизайн

Гостиничный сайт — это 60% фотографии. Требования к загрузке: WebP с fallback на JPEG, <picture> с srcset для retina, lazy-load через loading="lazy". Оригиналы до 3000px по длинной стороне, превью — 800x600 для карточек, 400x300 для списков. Модуль iblock автоматически генерирует ресайзы через CFile::ResizeImageGet(), но WebP-конвертация требует серверной поддержки (GD или Imagick с WebP) и кастомного обработчика.

Отзывы

Внутренняя система отзывов — Highload-блок Reviews: USER_ID, ROOM_TYPE_ID, RATING (1-5), TEXT, DATE, STATUS (на модерации / опубликован). Публикация — после ручной модерации или автоматически через 24 часа. Агрегированный рейтинг — пересчитывается триггером при добавлении нового отзыва, хранится в свойстве инфоблока AVG_RATING.

Интеграция внешних отзывов (TripAdvisor, Google Reviews) — через виджеты или API, без хранения в Битриксе.

Этапы и сроки

Масштаб Сроки
Мини-отель, 10-20 номеров, базовое бронирование 4-8 недель
Гостиница, 50-100 номеров, Channel Manager, PMS 10-16 недель
Сеть отелей, мультисайт, программа лояльности 16-24 недели
  1. Аналитика и прототипирование (1-2 недели) — карта номерного фонда, логика бронирования, прототипы
  2. Дизайн (2-3 недели) — фотоцентричный UI, мобильная версия, календарь
  3. Ядро бронирования (3-5 недель) — RoomInventory, проверка доступности, оформление заказа, оплата
  4. Интеграции (2-4 недели) — PMS, Channel Manager, платёжные системы
  5. Контент и SEO (1-2 недели) — микроразметка, мультиязычность, мета-шаблоны
  6. Тестирование и запуск (1-2 недели) — нагрузочное, кроссбраузерное, деплой

Сроки не включают фотосъёмку номеров и создание 360-панорам — это параллельный процесс, который лучше начинать на этапе дизайна.