Разработка системы бронирования на 1С-Битрикс
Бронирование — это не просто форма с датами. Под капотом: управление номерным фондом, проверка доступности на конкретные даты без пересечений, блокировка слота на время оплаты, автоматическое освобождение при таймауте и интеграция с менеджерами каналов (channel manager) или модулями онлайн-оплаты. Попытки построить это на стандартном модуле заказов sale без архитектурной проработки заканчиваются переполненными бронированиями и дублями.
Модель данных
Стандартный инфоблок для объектов размещения не подходит для календарного учёта доступности. Нужна отдельная схема.
Таблица объектов — хранится как инфоблок типа room (или пользовательский тип hotel.room):
- Тип номера, вместимость, базовая цена, свойства (
PROPERTY_ROOM_TYPE,PROPERTY_CAPACITY) - Связь с инфоблоком отеля через свойство-привязку
Таблица броней — пользовательская таблица bl_booking:
CREATE TABLE bl_booking (
id SERIAL PRIMARY KEY,
room_id INT NOT NULL, -- ID элемента инфоблока номера
user_id INT, -- b_user.ID
date_from DATE NOT NULL,
date_to DATE NOT NULL,
status VARCHAR(20) NOT NULL, -- pending, confirmed, cancelled, expired
order_id INT, -- b_sale_order.ID
price_total NUMERIC(12,2),
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP, -- для pending-броней
guest_name VARCHAR(255),
guest_phone VARCHAR(50),
guest_email VARCHAR(255)
);
CREATE INDEX idx_booking_room_dates ON bl_booking(room_id, date_from, date_to, status);
Проверка доступности
Ключевой запрос — проверить, нет ли пересечений для запрашиваемого периода:
SELECT COUNT(*) FROM bl_booking
WHERE room_id = :room_id
AND status IN ('pending', 'confirmed')
AND date_from < :date_to
AND date_to > :date_from;
Если COUNT > 0 — номер недоступен. Проверку оборачиваем в транзакцию с SELECT FOR UPDATE на запись номера, чтобы исключить race condition при параллельных запросах.
$connection = \Bitrix\Main\Application::getConnection();
$connection->startTransaction();
// SELECT FOR UPDATE
// INSERT в bl_booking со статусом pending
// COMMIT
Блокировка и таймаут
После создания брони в статусе pending запускается таймер. Если оплата не поступила за N минут (обычно 15–30), бронь переводится в expired и слот освобождается.
Реализация через агент Битрикс:
function ReleasExpiredBookings(): string
{
$expiredIds = BookingTable::getList([
'filter' => [
'STATUS' => 'pending',
'<=EXPIRES_AT' => new \Bitrix\Main\Type\DateTime(),
],
'select' => ['ID'],
])->fetchAll();
foreach ($expiredIds as $row) {
BookingTable::update($row['ID'], ['STATUS' => 'expired']);
}
return __FUNCTION__ . '();';
}
Агент регистрируется через CAgent::AddAgent() с интервалом 60 секунд.
Интерфейс выбора дат
Календарь доступности строится на основе AJAX-запроса: фронт запрашивает /bitrix/services/main/ajax.php?action=BookingModule:getAvailability, бэкенд возвращает массив занятых дат для конкретного номера. Для визуализации используем Flatpickr или Pikaday с разметкой недоступных дней.
На стороне бэкенда — AJAX-контроллер, наследник \Bitrix\Main\Engine\Controller:
class BookingController extends \Bitrix\Main\Engine\Controller
{
public function getAvailabilityAction(int $roomId, string $month): array
{
// возвращает занятые даты за месяц
}
}
Кейс: сеть апарт-отелей, 3 объекта, 47 номеров
Задача: заменить ручное бронирование через звонки, исключить овербукинг.
Что было: менеджеры вели Excel-таблицу, раз в неделю сверялись — периодически случались двойные брони, скандалы с гостями.
Что сделали:
- Инфоблок
roomsс 47 элементами, каждый с галереей и свойствами (FLOOR,VIEW,BED_TYPE) - Таблица
bl_bookingс индексом по диапазону дат - AJAX-контроллер проверки доступности (отвечает за 80–120 мс)
- Интеграция с эквайрингом через модуль
sale.payment: бронь переходит вconfirmedпо вебхуку от платёжного шлюза - Агент освобождения истёкших броней каждые 2 минуты
- Административный модуль с календарным представлением загрузки номеров
Результат: нулевые овербукинги за 14 месяцев работы, конверсия формы бронирования 4.2% (была 0% — всё шло через звонок).
| Этап | Срок |
|---|---|
| Проектирование схемы данных | 3 дня |
| Разработка бэкенда (таблица, агент, контроллер) | 5 дней |
| Фронтенд (календарь, форма, AJAX) | 4 дня |
| Интеграция с платёжным шлюзом | 2 дня |
| Административный интерфейс | 3 дня |
| Тестирование и запуск | 2 дня |
Что входит в разработку
- Проектирование модели данных с учётом типов номеров и сезонных цен
- Разработка механизма проверки доступности с защитой от race condition
- Интерфейс выбора дат с визуализацией занятости
- Агент автоматического освобождения истёкших броней
- Интеграция с модулем
saleдля выставления счёта и приёма оплаты - Административный раздел управления бронированиями







