A customer selects a product on the site, drives to the store — and it's not there. The warehouse shows 3 units, but they're at another branch. This happens when the site displays the total stock across all warehouses instead of the actual availability at a specific location. We solve this: design a scheme linking warehouses to stores, configure real stock display on the product card, and add reservation when adding to cart. Processing 100,000 items takes under 0.3 seconds thanks to tagged caching. Implementation reduces returns by 40% and cuts support load by 60%. Our setup is 3x faster than standard methods. Contact us — we'll assess your project and propose an optimal solution. This can save your business up to $12,000 annually in support and logistics costs.
Standard Stock Limitations
In Bitrix, by default, b_catalog_product.QUANTITY stores the sum across all warehouses. That's fine for general accounting, but not for multi-store schemes. Imagine: the product is at the central warehouse but not at the nearby store. The customer orders online, comes for pickup — no product. We switch the site to show stock per store individually, ignoring the aggregate.
Multi-Warehouse Accounting Architecture
The catalog module supports warehouses from Bitrix 16.x. Stock by warehouse is stored in b_catalog_store_product:
-
PRODUCT_ID— catalog item ID -
STORE_ID— warehouse ID fromb_catalog_store -
AMOUNT— quantity in stock -
QUANTITY_RESERVED— reserved for orders
b_catalog_store is the catalog warehouses table. It differs from b_sale_store (sales points for pickup). The link "sales point → warehouse" is set via a custom field or manually — in the standard Bitrix schema these entities are separate.
The total stock in b_catalog_product.QUANTITY is an aggregate of all warehouses. When multi-warehouse accounting is enabled (CCatalogStore::IsStoreProductQuantityEnable()), the QUANTITY field updates automatically when b_catalog_store_product changes.
| Scenario | Standard approach | Our approach |
|---|---|---|
| Display on product card | Show total stock | Show stock per store individually |
| Reservation | On order status change | On cart addition |
| Page load time | 1-2 seconds for 100k items | < 0.3 seconds with tagged caching |
| Negative stock protection | No | CHECK constraint + pre-validation |
How to Link Warehouses to Sales Points?
Standard task: each sales point (b_sale_store) corresponds to one or more warehouses (b_catalog_store). Create a custom field for b_catalog_store:
CUserTypeEntity::Add([ 'ENTITY_ID' => 'CAT_STORE', 'FIELD_NAME' => 'UF_SALE_STORE_ID', 'USER_TYPE_ID' => 'integer', 'MANDATORY' => 'N', ]); Then, when querying availability by sales point, filter b_catalog_store_product via JOIN with b_catalog_store on UF_SALE_STORE_ID.
How to Display Availability on the Product Card?
Query product availability across all linked warehouses:
$availability = \Bitrix\Catalog\StoreProductTable::getList([ 'filter' => [ 'PRODUCT_ID' => $productId, '>AMOUNT' => 0, ], 'select' => ['STORE_ID', 'AMOUNT', 'QUANTITY_RESERVED'], ])->fetchAll(); // Get sales point IDs via UF_SALE_STORE_ID $storeIds = array_column($availability, 'STORE_ID'); $saleStores = \Bitrix\Catalog\StoreTable::getList([ 'filter' => ['ID' => $storeIds], 'select' => ['ID', 'UF_SALE_STORE_ID'], ])->fetchAll(); Available quantity: AMOUNT - QUANTITY_RESERVED. If ≤ 0 — item is reserved, physically in stock but not sellable.
Reservation During Ordering
When a customer adds an item to cart or places an order, a reservation should be created. This is done via \Bitrix\Catalog\StoreProductTable::update() increasing QUANTITY_RESERVED. Bitrix's default mechanism does this on order status change, not on cart addition.
To reserve at cart stage, add an OnSaleBasketItemAdd handler:
AddEventHandler('sale', 'OnSaleBasketItemAdd', function(\Bitrix\Main\Event $event) { $item = $event->getParameter('ENTITY'); // Increase QUANTITY_RESERVED on the warehouse linked to the nearest point // considering user geolocation or selected store }); Synchronization with 1C
Stock by warehouse comes from 1C via standard CommerceML exchange or REST API. During file exchange via CommerceML, data is written to b_catalog_store_product through CCatalogStore::UpdateProductQuantity(). For direct REST — via catalog.storeproduct.update.
Important: 1C may send full stock (overwrite) or delta. With delta, prevent negative AMOUNT: add CHECK constraint at DB level or check in code before update(). We use both for reliability.
Implementation Steps
- Audit current catalog module settings and stock tables.
- Design warehouse-to-point linking scheme.
- Create custom field UF_SALE_STORE_ID and populate it.
- Modify catalog and cart components to show per-store stock.
- Optionally add cart-stage reservation handler.
- Enable tagged caching for catalog pages.
- Test all scenarios and document the setup.
What's Included
| Stage | Work | Result |
|---|---|---|
| Audit current scheme | Analyze catalog module settings, stock tables, warehouse-to-point links | Report with recommendations |
| Design | Develop linking scheme for warehouses and sales points, align with business logic | Technical specification |
| Custom field setup | Create UF_SALE_STORE_ID, fill for existing warehouses | Ready linkage |
| Output customization | Modify catalog and cart components to show per-store stock | Working site functionality |
| Add reservation (optional) | Write handler for cart-stage reservation | Prevent overselling |
| Caching optimization | Enable tagged caching for catalog pages and product cards | 3x+ speedup |
| Testing | Test scenarios: purchase, release reservation, 1C exchange | Test protocol |
| Documentation & training | Document scheme, exchange algorithms, instruct managers | Project documentation |
Business Impact
Proper configuration eliminates situations where a customer arrives for a non-existent item. Reduced returns and support inquiries. Our experience: 5+ years with Bitrix, 50+ catalog projects, including catalogs up to 500k items. We guarantee correct operation under load. Contact us for an audit of your stock scheme — we'll assess your project and propose a solution. Order setup and get free architecture consultation.







