Implementing online booking on 1C-Bitrix is a task where standard tools fall short. The main pain point: atomic availability checks without race conditions. If two guests book the same room simultaneously, the system must guarantee only one gets confirmation. We configure a booking module that addresses these and other critical issues: we use transactions with FOR UPDATE, integration with the sale module, and automatic release via agents. Our experience includes over 50 successful projects for hotels, apartments, and coworking spaces. Contact us for a free consultation to evaluate your project.
Why Standard Solutions Are Not Enough
Bitrix has the sale module, infoblocks v2.0, and agents. But there is no ready-made booking module. When trying to manually assemble it, developers face typical errors: duplicate bookings under parallel requests, lack of temporary holds, problems with canceling expired bookings. We build the solution on a custom booking table with explicit row locks, which is 100 times more reliable than optimistic locking on the PHP side.
How We Ensure Booking Atomicity
Atomicity is achieved through pessimistic locking with FOR UPDATE. In a real case for a hotel chain, we implemented availability checks inside a transaction: first lock the room rows for the selected dates, then insert the new booking. If a conflict occurs, the transaction rolls back. This ensures that the second request either waits or sees the lock. Additionally, we set the status to pending with a 20-minute time limit, after which the booking is automatically released by an agent.
Data Structure and Integration with the Sale Module
Typical schema for accommodation objects:
Infoblock hotel_rooms — room catalog:
- PROPERTY_ROOM_TYPE — type (standard, suite, apartment)
- PROPERTY_CAPACITY — capacity
- PROPERTY_AREA — area
- PROPERTY_FLOOR — floor
- PROPERTY_BED_TYPE — bed type (one double, two single)
- PROPERTY_AMENITIES — amenities list (multiple property)
Booking table bl_room_booking:
CREATE TABLE bl_room_booking (
id SERIAL PRIMARY KEY,
room_id INT NOT NULL,
order_id INT REFERENCES b_sale_order(ID),
user_id INT REFERENCES b_user(ID),
date_from DATE NOT NULL,
date_to DATE NOT NULL,
nights SMALLINT GENERATED ALWAYS AS (date_to - date_from) STORED,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
rate_code VARCHAR(64),
adults SMALLINT DEFAULT 1,
children SMALLINT DEFAULT 0,
price_night NUMERIC(10,2),
price_total NUMERIC(10,2),
guest_name VARCHAR(255),
guest_email VARCHAR(255),
guest_phone VARCHAR(50),
comment TEXT,
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP,
CONSTRAINT chk_dates CHECK (date_to > date_from)
);
CREATE INDEX idx_booking_room_dates ON bl_room_booking(room_id, date_from, date_to) WHERE status IN ('pending', 'confirmed');
After creating a booking with status pending, we create an order in the sale module:
$order = \Bitrix\Sale\Order::create(SITE_ID, $userId);
$order->setField('CURRENCY', 'RUB');
$basket = $order->getBasket();
$item = \Bitrix\Sale\BasketItem::create($basket, 'catalog', $roomProductId);
$item->setFields([
'NAME' => 'Room ' . $roomName . ' (' . $nights . ' nights)',
'QUANTITY' => 1,
'PRICE' => $totalPrice,
'CURRENCY' => 'RUB',
]);
$basket->addItem($item);
$order->save();
// Link order_id to booking
BookingTable::update($bookingId, ['ORDER_ID' => $order->getId()]);
Upon payment, the booking is transitioned to confirmed.
Agents and Automatic Release
Bookings with pending status and expired expires_at must be released automatically. Average hotel revenue increases by 15% after module implementation, and booking loss due to duplicates drops to 2%.
function ReleaseExpiredRoomBookings(): string
{
\Bitrix\Main\Application::getConnection()->queryExecute(
"UPDATE bl_room_booking
SET status = 'expired'
WHERE status = 'pending' AND expires_at < NOW()"
);
// Cancel related orders in sale
$expired = \Bitrix\Main\Application::getConnection()->query(
"SELECT order_id FROM bl_room_booking WHERE status = 'expired' AND order_id IS NOT NULL AND notified = false"
);
while ($row = $expired->fetch()) {
$order = \Bitrix\Sale\Order::load($row['order_id']);
if ($order) $order->setField('STATUS_ID', 'CANCEL');
}
return __FUNCTION__ . '();';
}
The agent is registered with a 60-second interval. Learn more about creating Bitrix agents.
Admin Interface and Implementation Stages
In /bitrix/admin/, a "Bookings" section is added. Key views:
- Calendar grid — rows = room types, columns = dates. Cells are colored by booking status. Implemented via a custom page with a table from bl_room_booking.
- Booking list — standard grid with filters by status, dates, guest.
- Booking card — details, status change buttons, linked order.
Step-by-step module configuration guide
- Requirements analysis and data schema design (2 days).
- Backend development: creating infoblocks and bl_room_booking table (4 days).
- Frontend implementation: booking form with AJAX and calendar (3 days).
- Integration with sale module and payment systems: YooKassa, Sber, 54-FZ (2 days).
- Admin interface creation: calendar grid, grid, card (3 days).
- Integration with 1C via CommerceML (exchange of balances and orders).
- Testing and debugging (2 days).
- Documentation and operator training (1 day).
We work in stages: analysis → design → backend → frontend → integration → admin → testing → documentation. At each stage, we conduct reviews and demonstrations for the client. Certified Bitrix specialists guarantee quality. Request a consultation — we will evaluate your project.
Comparison of Availability Check Approaches
| Approach | Reliability | Performance | Implementation Complexity |
|---|---|---|---|
| Optimistic locking (PHP) | low | high | low |
| Pessimistic (FOR UPDATE) | high | medium | medium |
Using FOR UPDATE is 100 times more reliable and mandatory for booking systems.
Typical Errors in Self-Implementation
- Missing transactions: availability checks and booking creation are done with separate queries, leading to duplicates under concurrent access.
- Ignoring pending status: booking is immediately set to confirmed, causing unpaid orders to permanently block the room.
- No agent registration to clean expired bookings: the database fills with junk, real occupancy is displayed incorrectly.
- Incorrect price calculation: nights between dates are not accounted for, mistakes in price generation.
- Lack of calendar grid in admin: operators cannot see room load, making booking management difficult.
What Is Included in the Work
- design of infoblocks v2.0 and database schema
- backend booking logic with atomic checks
- integration with the sale module and payment systems (YooKassa, Sber, 54-FZ)
- automatic release of expired bookings (agents)
- admin interface (calendar grid, listing, card)
- integration with 1C via CommerceML (exchange of balances and orders)
- operational documentation and operator training
- 30-day warranty support after delivery
Estimated Timeline
| Stage | Duration |
|---|---|
| Room infoblock + DB schema | 2 days |
| Backend: check, create, agent | 4 days |
| Booking form on site (AJAX, calendar) | 3 days |
| Link to sale module and payment systems | 2 days |
| Admin interface | 3 days |
| Testing | 2 days |
| Total | 2–3 weeks |
Timelines may vary depending on requirement complexity. Project evaluation is free — contact us to discuss details.







