Разработка сайта туроператора на 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
    Разработка веб-сайта для компании ФИКСПЕР
    995
  • 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
    734
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    863
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    772
  • 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-летним опытом помогут вам избежать типичных ошибок и построить производительное решение.