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

Туроператори стикаються з проблемою: ціни змінюються щодня, дати вильотів плавають, а зовнішні системи бронювання відповідають з різною швидкістю. Одна віддає JSON за 200 мс, інша — XML за 8 секунд. Якщо спроектувати каталог як статичний інфоблок з ручним оновленням, через місяць менеджери перестану
Послуги, які ми пропонуємо
Показано 1 з 1Усі 1626 послуг
Розробка сайту туроператора на 1С-Бітрікс
Складний
від 1 тижня до 3 місяців

Наші компетенції:

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1415
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    996
  • 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
    735
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    863
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    773
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    1134

Туроператори стикаються з проблемою: ціни змінюються щодня, дати вильотів плавають, а зовнішні системи бронювання відповідають з різною швидкістю. Одна віддає JSON за 200 мс, інша — XML за 8 секунд. Якщо спроектувати каталог як статичний інфоблок з ручним оновленням, через місяць менеджери перестануть оновлювати ціни, а клієнти бронюватимуть тури за застарілими даними. Ми — команда розробників з 10-річним досвідом в 1С-Бітрікс, спеціалізуємося на архітектурі, яка вирішує ці завдання. Наш підхід гарантує, що сайт працюватиме з реальними даними в реальному часі. За 10 років ми реалізували понад 50 проєктів для туроператорів — від невеликих вітрин до складних платформ з B2B-порталами.

Як побудувати каталог турів на інфоблоках?

Каталог будується на двох інфоблоках та одному Highload-блоці. Така архітектура забезпечує гнучкість та продуктивність навіть при тисячах турів.

Інфоблок «Напрямки» — розділи інфоблоку турів. Ієрархія: «Європа» → «Італія» → «Тоскана». Властивості розділів через UF_* поля: UF_COUNTRY_CODE (ISO 3166-1), UF_CLIMATE_INFO, UF_VISA_REQUIRED, UF_GALLERY. Розділи використовуються і для фільтрації, і для SEO-сторінок: /tours/italy/, /tours/italy/toscana/.

Інфоблок «Тури» (тип tours) — елементи всередині розділів-напрямків. Властивості включають тривалість, дати вильоту, тип туру, складність, розмір групи, включені послуги, базову ціну, зірковість готелю, зовнішній ідентифікатор системи бронювання, галерею та відео. Прив'язка до торгового каталогу (CCatalog::Add()) потрібна тільки якщо бронювання проходить через модуль sale. Якщо оплата йде на зовнішню систему (Samo.Tourvisor), каталог Бітрікс не підключається — інфоблок працює як вітрина.

Highload-блок «Цінові коефіцієнти» (PriceCoefficients) зберігає правила динамічного ціноутворення: поля TOUR_ID, DATE_FROM, DATE_TO, COEFFICIENT, RULE_TYPE (раннє бронювання, гарячий тур, сезонний, групова знижка), PRIORITY. Highload обрано тому, що записів будуть тисячі — кожен тур × кожен сезон × кожен тип правила. Вибірка через \Bitrix\Highloadblock\HighloadBlockTable::getList() з фільтром по TOUR_ID та поточній даті.

Чому фасетна фільтрація вимагає кастомного компонента?

Стандартний catalog.smart.filter не підходить для турів: дати вильоту — множинна властивість, ціна обчислюється динамічно, напрямок — ієрархія розділів. Ми розробляємо кастомний компонент project:tour.filter, який обробляє запити в 3 рази швидше стандартного на каталозі з 2000 турів.

Фільтрація за напрямком. Ієрархічний вибір: країна → регіон → курорт. При виборі країни фільтр підвантажує регіони AJAX-запитом на /api/tours/regions/?country=IT. В component.phpCIBlockSection::GetList() з кешуванням через CPHPCache з тегом iblock_id_N.

Фільтрація за датами вильоту. Клієнт обирає діапазон — наприклад, «з 1 по 30 червня». В БД дати зберігаються як множинні значення властивості. Проблема: стандартний CIBlockElement::GetList() з таким фільтром працює повільно на великих обсягах. Рішення — проміжна таблиця b_tour_departure_index, яка заповнюється агентом при оновленні туру. Фільтрація йде JOIN’ом на цю таблицю, результат — масив TOUR_ID.

Фільтрація за ціною. Ціна обчислюється в момент запиту: BASE_PRICE × коефіцієнт сезону × коефіцієнт раннього бронювання. Прямий фільтр неможливий. Є два варіанти:

  • Матеріалізована ціна — агент перераховує актуальну ціну кожного туру раз на годину і записує у властивість CURRENT_PRICE. Фільтрація по ньому стандартна. Мінус — затримка до години.
  • Двоетапна фільтрація — спочатку обираються тури за всіма іншими фільтрами, потім для кожного обчислюється ціна і відсікаються ті, що не потрапляють в діапазон. Працює точно, але при каталозі в 5000 турів другий етап може зайняти 200–500 мс. Вирішується кешуванням обчислених цін в Redis з TTL 15 хвилин.

На практиці обирають перший варіант — клієнт бачить ціну з похибкою до години, але фільтр працює миттєво. Точна ціна показується на детальній сторінці туру та при оформленні замовлення.

AJAX-фільтрація. Всі фільтри відправляються одним GET-запитом: /api/tours/search/?destination=IT&date_from=01.06&date_to=30.06&duration_min=7&duration_max=10&price_max=2000&type=excursion. Контролер в local/modules/project.tours/lib/controller/search.php наслідує \Bitrix\Main\Engine\Controller, валідує параметри, збирає фільтр CIBlockElement::GetList(), повертає JSON з масивом турів та метаданими фасетів (скільки турів по кожному типу при поточних фільтрах). Фасети — лічильники поруч з кожним значенням фільтра. Обчислюються окремими запитами COUNT(*), кешуються на 5 хвилин.

Як інтегрувати Samo.Tourvisor та Sletat?

Туроператор рідко продає тільки власні тури. Сайт агрегує пропозиції з кількох джерел: власні тури (в інфоблоці), пакетні тури з Samo.Tourvisor та пропозиції з Sletat.ru.

Samo.Tourvisor API — RESTful JSON. Основні ендпоінти:

  • GET /api/search — пошук турів за параметрами (країна, курорт, дата, ночі, дорослі/діти). Відповідь — масив пропозицій з ціною, готелем, датою вильоту, оператором.
  • GET /api/hotel/{id} — деталі готелю: фото, опис, координати.
  • POST /api/order — створення заявки на бронювання.

Інтеграція реалізується через модуль local/modules/project.tourvisor/. Клас \Project\Tourvisor\Client обгортає HTTP-запити через \Bitrix\Main\Web\HttpClient. Критичний момент — час відповіді. Samo.Tourvisor відповідає за 2–8 секунд. Користувач не повинен чекати: перше завантаження показує результати з локального інфоблоку (власні тури) миттєво, паралельно фронтенд відправляє AJAX-запит на /api/tourvisor/search/, бекенд кешує результат в Redis з TTL 30 хвилин.

Sletat.ru API — XML/SOAP. Старий протокол, але величезна база турів. Основний метод — GetTours(). Час відповіді — 5–15 секунд. Особливість — RequestId: перший запит повертає RequestId, за яким потрібно опитувати GetSearchResult() кожні 2–3 секунди, поки статус не стане Completed. Це реалізується через polling на фронтенді.

Об'єднання результатів з різних джерел. На фронті — єдиний список з позначкою джерела. Кожен результат містить source (local / tourvisor / sletat), external_id, price, currency. Сортування за ціною вимагає конвертації валют через курс НБУ, що зберігається в Highload-блоці CurrencyRates і оновлюється агентом раз на день.

Як реалізувати динамічне ціноутворення?

Три рівні ціноутворення:

  1. Сезонні коефіцієнти — високий сезон ×1.3, низький ×0.8. Зберігаються в Highload-блоці PriceCoefficients з діапазоном дат.
  2. Раннє бронювання — знижка 10–20% при бронюванні за 60+ днів до вильоту. Правило: якщо DEPARTURE_DATE - TODAY > 60, застосувати коефіцієнт 0.85.
  3. Гарячі тури — знижка 15–40% за 3–7 днів до вильоту при незаповненій групі. Коефіцієнт залежить від відсотка заповнення: GROUP_FILLED < 50% → 0.6.

Розрахунок ціни в \Project\Tours\PriceCalculator::calculate($tourId, $departureDate):

$basePrice = $tour['BASE_PRICE']; $coefficients = HighloadBlockTable::getList([ 'filter' => [ 'TOUR_ID' => $tourId, '<=DATE_FROM' => $departureDate, '>=DATE_TO' => $departureDate, ], 'order' => ['PRIORITY' => 'ASC'], ])->fetchAll(); $finalPrice = $basePrice; foreach ($coefficients as $c) { $finalPrice *= $c['COEFFICIENT']; } 

Пріоритет визначає порядок застосування. Сезонний коефіцієнт (пріоритет 1) застосовується першим, потім раннє бронювання (пріоритет 2), потім гарячий (пріоритет 3). Правила не конфліктують: раннє бронювання та гарячий тур взаємовиключні за визначенням.

Як організувати бронювання та часткову оплату?

Потік оформлення замовлення через модуль sale: клієнт обирає тур, дату вильоту, кількість учасників. Формується замовлення \Bitrix\Sale\Order::create() з кошиком з одного товару (тур) та властивостями замовлення — дані пасажирів (ПІБ, паспортні дані, дата народження). Часткова оплата реалізується через два платежі в замовленні: перший — 30–50% від вартості, другий — за 30 днів до вильоту. Обробник OnSalePaymentEntitySaved перевіряє, чи обидва платежі оплачені. Агент за 30 днів до вильоту переводить другий платіж у статус «До оплати» та надсилає email з нагадуванням.

Що входить в роботу

  • Архітектурна документація (схема бази даних, структура модулів, опис API-інтеграцій)
  • Налаштування віддаленого доступу та передача вихідних кодів
  • Навчання менеджерів роботі з адмінкою та фільтрами
  • Пост-релізна підтримка протягом 3 місяців (виправлення помилок, консультації)

Типові помилки при реалізації:

  • Відсутність індексів на множинних властивостях призводить до гальмування фільтрації.
  • Ігнорування таймаутів зовнішніх API — користувач бачить нескінченне завантаження.
  • Синхронний виклик всіх джерел бронювання — сторінка завантажується 10+ секунд.
Масштаб проєкту Орієнтовні строки
Вітрина власних турів без онлайн-бронювання 3–5 тижнів
Каталог з фільтрацією, бронювання, одна інтеграція (Tourvisor) 6–10 тижнів
Повна платформа: кілька API, B2B-портал, динамічні ціни 10–14 тижнів
Джерело Тип API Типовий час відповіді Складність інтеграції
Локальний інфоблок < 50 мс Низька
Samo.Tourvisor REST JSON 2–8 сек Середня
Sletat.ru XML/SOAP 5–15 сек Висока (polling)

Зв'яжіться з нами для обговорення архітектури вашого каталогу. Отримайте консультацію щодо строк та вартості — ми розрахуємо індивідуальний план. Наші інженери з 10-річним досвідом допоможуть вам уникнути типових помилок та побудувати продуктивне рішення.