Development of Rental Functionality in 1C-Bitrix
The standard sale module in Bitrix is designed for sales: item → cart → payment → delivery. Rental is a different model: an item has time slots, price depends on duration, the same SKU can be "sold" to multiple customers on different dates, and after return is available again. Out-of-the-box Bitrix can't do this — development is needed on top of existing catalog and order architecture.
Data Architecture: What to Store and Where
Main complexity — availability model. For sales, a "balance" field in b_catalog_store_product is enough. For rental you need a booking calendar: specific dates when a unit is occupied.
Option 1 — highload-block of bookings. Create HL-block RentalBooking with fields:
-
UF_PRODUCT_ID— binding to SKU (element of infobux trading offers) -
UF_UNIT_ID— identifier of specific unit (if one item has 5 units, each tracked separately) -
UF_DATE_FROM,UF_DATE_TO— booking period -
UF_ORDER_ID— connection to orderb_sale_order -
UF_STATUS— confirmed / awaiting payment / returned
Option 2 — separate table via module. For high-load projects (equipment rental, tens of thousands of bookings) HL-block becomes slow due to EAV storage. Create your own table:
CREATE TABLE b_rental_booking (
ID INT AUTO_INCREMENT PRIMARY KEY,
PRODUCT_ID INT NOT NULL,
UNIT_ID INT NOT NULL,
DATE_FROM DATE NOT NULL,
DATE_TO DATE NOT NULL,
ORDER_ID INT,
STATUS ENUM('pending','confirmed','returned','cancelled'),
INDEX idx_product_dates (PRODUCT_ID, DATE_FROM, DATE_TO)
);
Index on (PRODUCT_ID, DATE_FROM, DATE_TO) is mandatory because date intersection check is the main query of the system.
Availability Check and Blocking
Main engineering challenge — race condition. Two clients simultaneously book one unit on same dates. Standard CIBlockElement::GetList doesn't protect against this.
Solution — SELECT ... FOR UPDATE on booking creation. Wrapped in transaction:
-
BEGIN -
SELECT * FROM b_rental_booking WHERE PRODUCT_ID = ? AND UNIT_ID = ? AND STATUS IN ('pending','confirmed') AND DATE_FROM < ? AND DATE_TO > ? FOR UPDATE - If no rows found —
INSERTnew booking -
COMMIT
In Bitrix this is implemented via $DB->StartTransaction() / $DB->Commit(). D7 ORM (Bitrix\Main\ORM) supports transactions via Application::getConnection()->startTransaction().
Pricing
Rental implies price per unit of time: day, hour, week. Standard price type in b_catalog_group stores fixed value. For rental you need recalculation logic.
Infobux properties for pricing:
-
PRICE_PER_DAY— base rate per day -
MIN_RENTAL_DAYS— minimum duration -
DISCOUNT_WEEK— discount for 7+ days rental (percent) -
DISCOUNT_MONTH— discount for 30+ days
Price calculation executed by custom handler of event OnSaleBasketItemRefreshData. On basket recalculation Bitrix calls this handler, and we inject price based on rental dates stored in basket item properties (BasketPropertyCollection).
Calendar on Frontend
Date selection component on product page. Minimal implementation:
- AJAX request to custom controller (
ajax.phpof module or REST-endpoint) - Controller returns array of occupied dates for specific item
- On frontend — datepicker with blocked dates (flatpickr, react-datepicker or similar)
- On date range selection — repeat AJAX for price calculation and availability check
Occupied dates cached in b_cache_tag with tag by item ID. Invalidation — on booking creation, cancellation or completion.
Booking Lifecycle
| Stage | Bitrix Event | Action |
|---|---|---|
| Add to cart | OnSaleBasketItemAdd |
Create preliminary booking (status=pending), TTL 30 minutes |
| Order payment | OnSalePayOrder |
Confirm booking (status=confirmed) |
| Order cancellation | OnSaleCancelOrder |
Release dates (status=cancelled) |
| Item return | Custom handler | status=returned, unit available again |
| TTL expiration | Agent CAgent |
Delete pending-bookings older than 30 minutes |
Agent for cleanup of stuck bookings is critical. Without it, abandoned carts will block items forever. Agent registration via CAgent::AddAgent() with 300-second interval.
Integration with sale Module
Cart properties (BasketPropertyCollection) store rental dates:
-
RENTAL_DATE_FROM -
RENTAL_DATE_TO -
RENTAL_UNIT_ID
These properties added on $basket->addItem() call and used on price calculation, print document formation and display in personal account.
For display in admin order override template sale.admin.order.edit — add columns with rental dates to order composition table.
Implementation Timeframes
| Project Scale | Work Volume | Timeframe |
|---|---|---|
| Simple rental (10–50 items, daily rental) | HL-block + event handlers + datepicker | 1 week |
| Medium (100+ items, hourly rental, per-unit accounting) | Own table + transactions + agents + account integration | 1.5–2 weeks |
| Complex (multi-warehouse, deposits, late penalties) | Full module with admin, API and notification system | 2–3 weeks |
Key limitation of out-of-the-box Bitrix — no temporal dimension in product balance. Everything else (cart, payment, notifications) works as-is if you correctly implement booking layer on top of standard mechanisms.







