Інтеграція 1С-Бітрікс із системою бронювання Travelline

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Інтеграція 1С-Бітрікс із системою бронювання Travelline
Середня
~1-2 тижні
Часті питання

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

Етапи розробки

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

  • 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С-Бітрікс з системою бронювання 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 — Вибір номера і тарифу. Картки номерів з фотографіями з інфоблоку 1С-Бітрікс + ціни та умови скасування з TL API. Дані об'єднуються за ROOM_TYPE_ID.

public function getRoomsWithPrices(string $arrival, string $departure, int $adults): array
{
    // Дані про номери з інфоблоку 1С-Бітрікс (опис, фото, зручності)
    $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);

    // Зберігаємо бронь у 1С-Бітрікс
    $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.

Зберігання броней у 1С-Бітрікс

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 кроки)
  • Об'єднання даних з інфоблоку 1С-Бітрікс і TL API
  • Webhook-обробник, оновлення статусів
  • Email-сповіщення гостю при підтвердженні та скасуванні
  • Інтеграція з платіжною системою для тарифів із передоплатою

Терміни: 5–8 тижнів — базова інтеграція. 8–14 тижнів — з передоплатою, особистим кабінетом гостя та історією броней.