Розробка сайту готелю на 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Розробка сайту готелю на 1С-Бітрікс
Складна
від 1 тижня до 3 місяців
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • 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
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Розробка сайту готелю на 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) мапиться на іконку через конфіг на фронті.

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

Алгоритм перевірки доступності. Гість вводить дати заїзду й виїзду та кількість гостей. Система має повернути типи номерів, у яких є щонайменше один фізичний номер, вільний на всі ночі діапазону.

Наївний запит WHERE UF_STATUS = 0 AND UF_DATE IN (...) поверне номери, вільні хоча б в одну ніч — це не те саме. Правильний підхід — група з перевіркою повноти:

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": 2200},
    "16": {"available": true, "min_rate": 2200},
    "17": {"available": false, "min_rate": null},
    "18": {"available": true, "min_rate": 3100}
  }
}

Недоступні дати блокуються в календарі. Мінімальний тариф показується при наведенні. Запит матриці — важкий: потрібно агрегувати весь 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. Загальна сума — сума тарифів за всі ночі. Бітрікс-агент заздалегідь заповнює поле UF_RATE у RoomInventory — це кеш розрахованої ціни.

Перегони при бронюванні (race condition). Двоє гостей одночасно бачать вільний номер. Обидва натискають «Забронювати». Без захисту — овербукінг. Рішення: транзакційне блокування на момент підтвердження. Перед створенням замовлення код виконує SELECT ... FOR UPDATE на відповідних рядках RoomInventory, перевіряє статус, виставляє UF_STATUS = 1, потім фіксує транзакцію. Якщо статус вже змінено іншою транзакцією — бронювання відхиляється з повідомленням «номер вже зайнятий». Все це має відбуватися в межах однієї транзакції: $connection->startTransaction() / $connection->commitTransaction().

Інтеграція з Channel Manager

Готель продає номери не лише на власному сайті, а й через Booking.com, Expedia, Ostrovok. Без синхронізації — овербукінг. Channel manager — проміжний шар, що синхронізує доступність і тарифи.

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

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

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

API-інтеграція з OTA — Booking.com Connectivity API працює через XML-повідомлення OTA (OpenTravel Alliance): OTA_HotelAvailNotifRQ для оновлення доступності, OTA_HotelRatePlanNotifRQ для тарифів, OTA_HotelResNotifRS для отримання бронювань. Це 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 підтримує LiqPay, Portmone, Stripe. Налаштування через адмінпанель, без коду.

Особистий кабінет гостя

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

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

Мультимовність

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

hreflang у <head>:

<link rel="alternate" hreflang="uk" href="https://hotel.ua/rooms/standard/" />
<link rel="alternate" hreflang="en" href="https://hotel.ua/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-панорам — це паралельний процес, який краще починати на етапі дизайну.