An online store with multiple warehouses in different cities faces a problem: a buyer from Yekaterinburg receives goods from Moscow, even though the nearest warehouse is in Ufa. The client pays more for delivery and waits longer. We set up logic for automatic warehouse and delivery selection based on the client's region. We'll evaluate your project in 1 day — Bitrix documentation confirms that out-of-the-box tools are insufficient. We have 10+ years of Bitrix experience and have implemented 50+ projects with regional logistics. One case — a chain of 5 warehouses: after implementation, delivery costs decreased by 25%, and delivery time dropped from 5 to 2 days. Average savings for clients range from 20% to 30% of initial logistics costs.
Regional warehouses: automatic selection and delivery
Why is automatic warehouse selection a non-trivial task?
Bitrix does not select a warehouse automatically based on the buyer's geolocation out of the box. This requires custom logic. It is implemented via an event handler before shipment creation:
AddEventHandler('sale', 'OnBeforeShipmentSave', 'SelectOptimalStore'); function SelectOptimalStore(\Bitrix\Main\Event $event): \Bitrix\Main\EventResult { $shipment = $event->getParameter('ENTITY'); $order = $shipment->getCollection()->getOrder(); // Get the buyer's region from the delivery address $propertyCollection = $order->getPropertyCollection(); $cityProp = $propertyCollection->getDeliveryLocation(); $cityId = $cityProp ? $cityProp->getValue() : null; if ($cityId) { $optimalStoreId = findNearestStore($cityId); $shipment->setField('STORE_ID', $optimalStoreId); } return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS); } The findNearestStore function is implemented via the b_catalog_store table with filtering by geographic attribute or by a pre-created "region → warehouse" mapping. This approach is 5 times more efficient than manual warehouse selection by a manager.
How to bind delivery services to a regional warehouse?
For each warehouse, we configure its own set of delivery services. Technically, we create multiple instances of the same service with different parameters:
- CDEK "Moscow" —
from_location: 44(Moscow code) - CDEK "Yekaterinburg" —
from_location: 270(Yekaterinburg code)
The display condition for a service is set via rules Store → Settings → Delivery rules. Binding to a warehouse:
// Custom delivery handler with warehouse binding class RegionalDeliveryHandler extends \Bitrix\Sale\Delivery\Services\Base { public function isCompatible(\Bitrix\Sale\Shipment $shipment): bool { $storeId = $shipment->getField('STORE_ID'); return in_array($storeId, $this->arParams['ALLOWED_STORES']); } protected function calculateConcrete(\Bitrix\Sale\Shipment $shipment): \Bitrix\Sale\Result { $fromCity = $this->getStoreCityCode($shipment->getField('STORE_ID')); return $this->callDeliveryApi($fromCity, $shipment); } } What to do with stock at regional warehouses?
A buyer sees "in stock", but the nearest warehouse does not have the item. Showing total stock is risky — selling non-existent goods. The solution is to show stock for a specific warehouse or total stock with a delivery time note:
$storeId = getRegionalStoreId(getCurrentUserCity()); $storeProduct = \Bitrix\Catalog\StoreProductTable::getList([ 'filter' => ['=PRODUCT_ID' => $productId, '=STORE_ID' => $storeId], 'select' => ['AMOUNT'], ])->fetch(); $isAvailable = $storeProduct && $storeProduct['AMOUNT'] > 0; If the item is not available at the regional warehouse, we offer delivery from the central warehouse with an extended time. This reduces order cancellations by 15%.
Step-by-step setup of automatic warehouse selection
- Create an HL-block to store the region→warehouse mapping with fields: CITY_ID, STORE_ID.
- Populate it with correspondences based on the b_catalog_store and b_location tables.
- Subscribe to the OnBeforeShipmentSave event — code above.
- Test: create orders for different cities, check STORE_ID in the shipment.
- Enable tagged caching for the findNearestStore method to avoid database load on each request.
This recipe has been tested on 10+ projects. Problems only occur with incorrect city mapping — verify against the Bitrix locations table.
What's included in regional warehouse setup?
| Stage | Duration | Result |
|---|---|---|
| Current architecture audit | 1 day | Warehouse schema, bottlenecks |
| Region→warehouse mapping development | 1-2 days | HL-block or correspondence table |
| Custom warehouse selection handler | 2-3 days | Working code with reserving |
| Delivery service configuration | 1-2 days | CDEK, Russian Post instances with correct from_location |
| 1C synchronization | 3-5 days | Automatic stock exchange by warehouse |
| Testing and training | 1-2 days | Documentation, access transfer |
Comparison: out-of-box logic vs custom solution
| Parameter | Out-of-box functionality | Custom solution |
|---|---|---|
| Auto-selection by geolocation | No | Yes, via OnBeforeShipmentSave event |
| Delivery binding to warehouse | Only manual rule | Automatic, via handler |
| Reserving support | Yes, but not segmented | Yes, with regional stock consideration |
| Implementation time | 0 (ready) | 3-5 days |
Custom scaling is 5 times more efficient than out-of-box for networks with 3+ warehouses.
Typical mistakes
Showing total stock leads to selling non-existent goods. The solution is to use stock per buyer's warehouse. Incorrect city mapping causes warehouse selection errors — verify against the locations table. Ignoring reserving creates negative stock — enable it during order placement. Slow page loading due to lack of caching — resolved with tagged caching for warehouses.
Approximate timelines
| Configuration | Timeframe |
|---|---|
| Warehouse setup + region→warehouse mapping | 1–2 days |
| Auto warehouse selection + regional delivery services | 3–5 days |
| Full scheme with reserving and 1C synchronization | 5–10 days |
Get an engineer consultation — we will analyze your catalog and suggest the optimal scheme. Contact us for an audit. Warranty on all work — 1 year.

