Setting up Click & Collect (order online - pick up in store) in 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1173
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    745
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Configuring Click & Collect (Order Online — Pick Up In Store) for 1C-Bitrix

Click & Collect is a scheme in which a customer places an order in an online store and picks it up at a physical location. In Bitrix this is implemented via a delivery module with the "pickup" type linked to specific warehouses/locations. The non-trivial part is showing real stock availability per location before checkout, reserving the product at a specific warehouse, and notifying the customer when the order is ready.

Data Structure: Pickup Locations and Warehouses

Bitrix stores pickup locations in the b_sale_location table (for the "Pickup" type). Warehouse logic is in b_catalog_store:

SELECT s.ID, s.TITLE, s.ADDRESS, sp.AMOUNT
FROM b_catalog_store s
JOIN b_catalog_store_product sp ON sp.STORE_ID = s.ID
WHERE sp.PRODUCT_ID = ? AND s.ACTIVE = 'Y' AND sp.AMOUNT > 0
ORDER BY s.SORT ASC;

Each pickup location in Bitrix can be linked to a warehouse. Configured in Catalog → Warehouses — each warehouse has an XML_ID field for mapping to a delivery location.

Pickup Delivery Service

In the admin panel: Store → Delivery → Add Delivery Service → Type: Pickup.

Creating programmatically:

\Bitrix\Main\Loader::includeModule('sale');

$deliveryService = \Bitrix\Sale\Delivery\Services\Manager::getList([
    'filter' => ['CODE' => 'self_pickup'],
])->fetch();

if (!$deliveryService) {
    // Register the pickup service
    \Bitrix\Sale\Delivery\Services\Manager::add([
        'NAME'       => 'In-store pickup',
        'CODE'       => 'self_pickup',
        'ACTIVE'     => 'Y',
        'CLASS_NAME' => '\Bitrix\Sale\Delivery\Services\Base',
        'CURRENCY'   => 'USD',
        'PRICE'      => 0,
    ]);
}

Pickup Location Selection in Cart

In the checkout component template (sale.order.ajax or sale.basket.order) — a dropdown or map with locations:

// Get active warehouses that have all cart items in stock
$basketItems = $order->getBasket();
$productIds = [];
foreach ($basketItems as $item) {
    $productIds[] = $item->getProductId();
}

// For each warehouse, check if all cart items are available
$storesResult = \Bitrix\Catalog\StoreTable::getList([
    'filter' => ['ACTIVE' => 'Y'],
    'select' => ['ID', 'TITLE', 'ADDRESS', 'GPS_N', 'GPS_S'],
    'order'  => ['SORT' => 'ASC'],
]);

$availableStores = [];
while ($store = $storesResult->fetch()) {
    $allAvailable = true;
    foreach ($productIds as $productId) {
        $stockResult = \Bitrix\Catalog\StoreProductTable::getList([
            'filter' => ['PRODUCT_ID' => $productId, 'STORE_ID' => $store['ID']],
            'select' => ['AMOUNT'],
        ])->fetch();

        if (!$stockResult || $stockResult['AMOUNT'] < $basketItems->getQuantityByProductId($productId)) {
            $allAvailable = false;
            break;
        }
    }

    if ($allAvailable) {
        $availableStores[] = $store;
    }
}

Reservation at a Specific Warehouse

After the pickup location is selected — reserve the products at that warehouse, not from the general pool:

// In the order save handler
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale', 'OnSaleOrderBeforeSaved',
    function (\Bitrix\Main\Event $event) {
        $order = $event->getParameter('ENTITY');

        // Read the selected pickup location from order properties
        $pickupStoreId = $order->getPropertyCollection()
            ->getItemByOrderPropertyCode('PICKUP_STORE_ID')
            ?->getValue();

        if (!$pickupStoreId) {
            return;
        }

        // Reserve at the specific warehouse
        foreach ($order->getBasket() as $basketItem) {
            \Bitrix\Catalog\StoreProductTable::reserveProduct(
                $basketItem->getProductId(),
                (int)$pickupStoreId,
                $basketItem->getQuantity(),
                $order->getId()
            );
        }
    }
);

The order property PICKUP_STORE_ID is created as a custom order field: Store → Settings → Order Properties.

Setup Timeline

Pickup delivery service, location selection with stock availability check, warehouse reservation, saving to order property — 2–4 business days depending on the complexity of the existing warehouse infrastructure.