Интеграция 1С-Битрикс с системой бронирования Travelline

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Интеграция 1С-Битрикс с системой бронирования Travelline
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1173
  • 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С Предприятие для компании МИРСАНБЕЛ
    745
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Интеграция 1С-Битрикс с системой бронирования Travelline

Travelline — система управления отелем (PMS) и модуль бронирования, широко используемая в российской гостиничной индустрии. Сайт отеля на 1С-Битрикс должен показывать актуальную доступность номеров, принимать бронирования и передавать их в Travelline. Без прямой интеграции отель либо работает через iframe виджета Travelline (негибкий UX), либо вручную переносит брони из сайта в PMS.

Архитектура интеграции

Travelline предоставляет два API:

TL API v2 (JSON REST) — для получения тарифов, доступности и создания броней. Основной API для сайтовой интеграции.

TL Distributor API — для крупных OTA и агрегаторов, требует отдельного соглашения.

Для сайта отеля используем TL API v2. Endpoint: https://api.travelline.ru/api/v2/. Авторизация через API-ключ в заголовке X-Api-Key.

Клиент Travelline API

class TravellineApiClient
{
    private string $apiKey;
    private string $hotelId;  // ID объекта в TL
    private string $baseUrl = 'https://api.travelline.ru/api/v2';

    public function __construct(string $apiKey, string $hotelId)
    {
        $this->apiKey  = $apiKey;
        $this->hotelId = $hotelId;
    }

    /**
     * Доступность номеров
     */
    public function getAvailability(string $arrivalDate, string $departureDate, int $adults = 2, int $children = 0): array
    {
        return $this->request('GET', '/availability', [
            'hotelId'       => $this->hotelId,
            'arrivalDate'   => $arrivalDate,   // Y-m-d
            'departureDate' => $departureDate,
            'adults'        => $adults,
            'children'      => $children,
        ]);
    }

    /**
     * Тарифы и цены
     */
    public function getRatePlans(string $arrivalDate, string $departureDate): array
    {
        return $this->request('GET', '/rateplans', [
            'hotelId'       => $this->hotelId,
            'arrivalDate'   => $arrivalDate,
            'departureDate' => $departureDate,
            'currency'      => 'RUB',
        ]);
    }

    /**
     * Создание брони
     */
    public function createBooking(array $bookingData): array
    {
        return $this->request('POST', '/bookings', array_merge(
            $bookingData,
            ['hotelId' => $this->hotelId]
        ));
    }

    /**
     * Отмена брони
     */
    public function cancelBooking(string $bookingId, string $reason = ''): array
    {
        return $this->request('POST', "/bookings/{$bookingId}/cancel", [
            'reason' => $reason,
        ]);
    }

    /**
     * Получение брони
     */
    public function getBooking(string $bookingId): array
    {
        return $this->request('GET', "/bookings/{$bookingId}");
    }

    private function request(string $method, string $path, array $data = []): array
    {
        $url = $this->baseUrl . $path;

        if ($method === 'GET' && $data) {
            $url .= '?' . http_build_query($data);
        }

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST  => $method,
            CURLOPT_HTTPHEADER     => [
                "X-Api-Key: {$this->apiKey}",
                'Content-Type: application/json',
                'Accept: application/json',
            ],
            CURLOPT_POSTFIELDS => in_array($method, ['POST', 'PUT', 'PATCH'])
                ? json_encode($data) : null,
            CURLOPT_TIMEOUT => 15,
        ]);

        $json     = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode >= 400) {
            $errorData = json_decode($json, true) ?? [];
            throw new \RuntimeException(
                "Travelline API {$httpCode}: " . ($errorData['message'] ?? $json)
            );
        }

        return json_decode($json, true) ?? [];
    }
}

Кеширование доступности

Запрашивать доступность номеров из Travelline при каждом показе страницы недопустимо — это медленно (200–500 мс) и нагружает TL API. Кешируем:

class RoomAvailabilityService
{
    private TravellineApiClient $tl;

    public function getAvailability(string $arrival, string $departure, int $adults): array
    {
        $cacheKey  = "tl_avail_{$arrival}_{$departure}_{$adults}";
        $cacheTtl  = 300; // 5 минут

        $cache = \Bitrix\Main\Data\Cache::createInstance();
        if ($cache->initCache($cacheTtl, $cacheKey, '/travelline/')) {
            return $cache->getVars()['data'];
        }

        $data = $this->tl->getAvailability($arrival, $departure, $adults);

        $cache->startDataCache();
        $cache->endDataCache(['data' => $data]);

        return $data;
    }
}

При изменении данных (получение брони через webhook) — инвалидация кеша через \Bitrix\Main\Data\Cache::clearByTag().

Компонент поиска и бронирования

/local/components/local/hotel.booking/ — многошаговый компонент:

Шаг 1 — Поиск. Форма с датами заезда/выезда, числом гостей. После отправки — список доступных номеров с ценами из TL API.

Шаг 2 — Выбор номера и тарифа. Карточки номеров с фотографиями из инфоблока Битрикс + цены и условия отмены из TL API. Данные объединяются по ROOM_TYPE_ID.

public function getRoomsWithPrices(string $arrival, string $departure, int $adults): array
{
    // Данные о номерах из инфоблока Битрикс (описание, фото, удобства)
    $rooms = $this->getRoomsFromIblock();

    // Доступность и цены из Travelline
    $availability = $this->availabilityService->getAvailability($arrival, $departure, $adults);

    // Объединяем по TL roomTypeId
    $tlRooms = array_column($availability['roomTypes'] ?? [], null, 'id');

    foreach ($rooms as &$room) {
        $tlRoomId = $room['PROPERTY_TL_ROOM_TYPE_ID_VALUE'] ?? null;

        if ($tlRoomId && isset($tlRooms[$tlRoomId])) {
            $room['TL_DATA']  = $tlRooms[$tlRoomId];
            $room['AVAILABLE'] = ($tlRooms[$tlRoomId]['availableRooms'] ?? 0) > 0;
            $room['MIN_PRICE'] = $this->getMinPrice($tlRooms[$tlRoomId]['ratePlans'] ?? []);
        } else {
            $room['AVAILABLE'] = false;
        }
    }

    return array_filter($rooms, fn($r) => $r['AVAILABLE']);
}

Шаг 3 — Данные гостя. Форма: имя, фамилия, email, телефон, комментарий. Авторизованным — подставляем из профиля.

Шаг 4 — Создание брони.

public function createBooking(array $formData, string $ratePlanId, string $roomTypeId): array
{
    $arrival   = $_SESSION['booking']['arrival'];
    $departure = $_SESSION['booking']['departure'];

    $bookingPayload = [
        'arrivalDate'   => $arrival,
        'departureDate' => $departure,
        'roomTypeId'    => $roomTypeId,
        'ratePlanId'    => $ratePlanId,
        'adults'        => (int)$_SESSION['booking']['adults'],
        'children'      => (int)($_SESSION['booking']['children'] ?? 0),
        'guest'         => [
            'firstName'   => $formData['first_name'],
            'lastName'    => $formData['last_name'],
            'email'       => $formData['email'],
            'phone'       => $formData['phone'],
            'countryCode' => 'RU',
        ],
        'comment'       => $formData['comment'] ?? '',
        'currency'      => 'RUB',
        'source'        => 'website',
    ];

    $booking = $this->tl->createBooking($bookingPayload);

    // Сохраняем бронь в Битрикс
    $this->saveBookingLocally($booking, $formData);

    // Отправляем подтверждение гостю
    \CEvent::Send('HOTEL_BOOKING_CONFIRMED', SITE_ID, [
        'EMAIL'          => $formData['email'],
        'GUEST_NAME'     => $formData['first_name'],
        'BOOKING_ID'     => $booking['bookingId'],
        'ARRIVAL_DATE'   => date('d.m.Y', strtotime($arrival)),
        'DEPARTURE_DATE' => date('d.m.Y', strtotime($departure)),
        'ROOM_NAME'      => $booking['roomType']['name'] ?? '',
        'TOTAL_PRICE'    => $booking['totalPrice'],
    ]);

    return $booking;
}

Webhooks от Travelline

Travelline отправляет уведомления при изменении статуса брони (подтверждение, отмена, изменение):

// /local/api/travelline/webhook.php
$rawBody  = file_get_contents('php://input');
$signature = hash_hmac('sha256', $rawBody, TL_WEBHOOK_SECRET);

if ($signature !== ($_SERVER['HTTP_X_TL_SIGNATURE'] ?? '')) {
    http_response_code(403);
    exit;
}

$event = json_decode($rawBody, true);

switch ($event['type']) {
    case 'booking.confirmed':
        TravellineBookingTable::updateByTlId($event['bookingId'], ['STATUS' => 'confirmed']);
        break;

    case 'booking.cancelled':
        TravellineBookingTable::updateByTlId($event['bookingId'], ['STATUS' => 'cancelled']);
        // Уведомить гостя об отмене
        break;

    case 'booking.modified':
        // Обновить данные брони
        break;
}

http_response_code(200);
echo json_encode(['received' => true]);

Оплата на сайте

Если тариф предусматривает предоплату — интегрируем платёжную систему (ЮКасса, Тинькофф). Сумма предоплаты берётся из $booking['prepaymentAmount']. После успешной оплаты — подтверждение брони через TL API POST /bookings/{id}/confirm.

Хранение броней в Битрикс

class TravellineBookingTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getTableName(): string { return 'local_tl_bookings'; }

    public static function getMap(): array
    {
        return [
            new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
            new \Bitrix\Main\ORM\Fields\StringField('TL_BOOKING_ID', ['required' => true]),
            new \Bitrix\Main\ORM\Fields\IntegerField('USER_ID'),
            new \Bitrix\Main\ORM\Fields\StringField('GUEST_EMAIL'),
            new \Bitrix\Main\ORM\Fields\StringField('GUEST_PHONE'),
            new \Bitrix\Main\ORM\Fields\DateField('ARRIVAL_DATE'),
            new \Bitrix\Main\ORM\Fields\DateField('DEPARTURE_DATE'),
            new \Bitrix\Main\ORM\Fields\StringField('ROOM_TYPE_ID'),
            new \Bitrix\Main\ORM\Fields\FloatField('TOTAL_PRICE'),
            new \Bitrix\Main\ORM\Fields\StringField('CURRENCY'),
            new \Bitrix\Main\ORM\Fields\StringField('STATUS'),
            new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
        ];
    }
}

Состав работ

  • PHP-клиент Travelline API v2
  • Кеширование доступности, инвалидация по webhook
  • Компонент поиска и бронирования (4 шага)
  • Объединение данных из инфоблока Битрикс и TL API
  • Webhook-обработчик, обновление статусов
  • Email-уведомления гостю при подтверждении и отмене
  • Интеграция с платёжной системой для тарифов с предоплатой

Сроки: 5–8 недель базовая интеграция. 8–14 недель с предоплатой, личным кабинетом гостя и историей броней.