Configuring Regional Warehouses and Delivery in 1C-Bitrix
When an online store operates multiple warehouses in different cities, the simple "one warehouse — one delivery" model breaks down. A customer in Yekaterinburg should receive shipment from the Ural warehouse, not wait for dispatch from Moscow. 1C-Bitrix provides the tools for this architecture, but correct configuration requires understanding the relationships between the sale, catalog modules, and delivery services.
Warehouses in 1C-Bitrix
Warehouses are managed through the trade catalog module: Trade Catalog → Warehouses. Each warehouse is a record in the b_catalog_store table with fields: address, GPS coordinates, active flag, and location link.
Stock levels per warehouse are stored in b_catalog_store_product:
SELECT cs.title, csp.amount, csp.quantity_reserved
FROM b_catalog_store_product csp
JOIN b_catalog_store cs ON cs.id = csp.store_id
WHERE csp.product_id = 12345;
Reservation on add-to-cart or order placement is configured under Trade Catalog → Settings → Reservation.
Warehouse Selection Logic for an Order
1C-Bitrix does not automatically select a warehouse based on the customer'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 customer'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 using the b_catalog_store table filtered by geographic criteria or a pre-defined "region → warehouse" mapping.
Regional Delivery Services
A separate set of delivery services is configured for each warehouse/region. Technically, this means creating multiple instances of the same service with different parameters:
- CDEK "Moscow" —
from_location: 44(Moscow code in CDEK) - CDEK "Yekaterinburg" —
from_location: 270(Yekaterinburg code)
The delivery service display condition is set through rules: Store → Settings → Delivery Rules. Warehouse binding:
// 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
{
// Calculate cost taking the source warehouse into account
$fromCity = $this->getStoreCityCode($shipment->getField('STORE_ID'));
return $this->callDeliveryApi($fromCity, $shipment);
}
}
Stock and Availability
An important consideration with regional warehouses: the customer sees "in stock," but the nearest warehouse has none — stock is only available at the central warehouse. The solution is to display stock for the specific warehouse or a combined total with an estimated delivery date:
$storeId = getRegionalStoreId(getCurrentUserCity());
$storeProduct = \Bitrix\Catalog\StoreProductTable::getList([
'filter' => ['=PRODUCT_ID' => $productId, '=STORE_ID' => $storeId],
'select' => ['AMOUNT'],
])->fetch();
$isAvailable = $storeProduct && $storeProduct['AMOUNT'] > 0;
Timeline
| Configuration | Timeline |
|---|---|
| Warehouse setup + region-to-warehouse mapping | 1–2 days |
| Automatic warehouse selection + regional delivery services | 3–5 days |
| Full setup with reservation and 1C synchronization | 5–10 days |







