Setting up unified warehouse accounting online and offline 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
    1212
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815
  • 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
    565
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    980

Configuring Unified Inventory Management Online and Offline 1С-Bitrix

Site shows "5 units in stock". Meanwhile, the last three units are being sold in the store. An hour later, an online customer orders 4 units — and the manager refuses them. This happens when online and offline work with different inventory databases.

Sources of truth about inventory

In a typical configuration: 1C is the master source of inventory, Bitrix is the consumer. 1C knows about all inventory movements: receipts, online sales, offline sales, inventory counts, write-offs. Bitrix receives current data through synchronization.

The problem is synchronization frequency. Standard CommerceML exchange works by schedule — every 15–60 minutes. During this time, several units may be sold in the offline store, while the site continues to show old inventory.

Real-time inventory update on offline sale

To minimize discrepancy — integrate the cashbox with Bitrix in real time. On each offline sale, immediate webhook to Bitrix:

// /local/ajax/pos-sale-callback.php
$data = json_decode(file_get_contents('php://input'), true);

foreach ($data['items'] as $item) {
    $product = \CCatalogProduct::GetByID($item['sku']);
    if (!$product) continue;

    // Decrease inventory on specific store
    \Bitrix\Catalog\StoreProductTable::update(
        ['PRODUCT_ID' => $item['product_id'], 'STORE_ID' => $data['store_id']],
        ['AMOUNT' => new \Bitrix\Main\DB\SqlExpression('AMOUNT - ?', $item['quantity'])]
    );

    // Recalculate total inventory in b_catalog_product
    \CCatalogProduct::RecalcQuantity($item['product_id']);
}

RecalcQuantity() recalculates b_catalog_product.QUANTITY as the sum across all stores in b_catalog_store_product. After this, the product cache should be invalidated — via BXClearCache(false, '/catalog/') or tagged cache.

Online inventory reservation

Common practice for multi-channel stores: allocate separate "online store" in b_catalog_store, whose inventory is intended only for the online store. Physically, goods may be on one store, but logically divided.

Offline sales decrease "physical store", while online orders are reserved from "online store". At night, 1C replenishes the online store from the physical one by a specified proportion.

Physical store: 100 units
Online quota: 30% = 30 units → stored in b_catalog_store_product (STORE_ID = online_store)
Offline quota: 70% = 70 units → not in Bitrix

This prevents overselling, but reduces available inventory for online sales.

Working with warehouse accounting documents

In Bitrix, the catalog module supports warehouse documents: \Bitrix\Catalog\Document\DocumentTable. Document types: A — receipt, S — sale, M — movement, R — return.

When conducting a document via \Bitrix\Catalog\Document\DocumentController::conduct(), inventory in b_catalog_store_product is automatically recalculated. This is the correct way to move inventory — via documents, not direct UPDATE.

For offline sales: when receiving webhook from cashbox, create document type S with sale items and conduct it. This ensures complete history of goods movement and correct warehouse accounting.

Inventory verification and reconciliation

Discrepancies between 1C and Bitrix are inevitable. It's important to find them. Once per day, run a reconciliation agent:

// Get inventory from 1C via REST API
$bx1cItems = get1cQuantities();

// Compare with b_catalog_store_product
foreach ($bx1cItems as $sku => $qty) {
    $bitrixQty = StoreProductTable::getList([
        'filter' => ['PRODUCT.XML_ID' => $sku],
        'select' => ['AMOUNT'],
    ])->fetch()['AMOUNT'] ?? 0;

    if (abs($bitrixQty - $qty) > 0) {
        logDiscrepancy($sku, $bitrixQty, $qty);
    }
}

The discrepancy log allows deciding: correct Bitrix per 1C (1C is master) or signal about integration issue.

What we configure

  • Webhook-endpoint to receive data about offline cashbox sales
  • Update b_catalog_store_product via sale type documents
  • Call RecalcQuantity() and cache invalidation after each movement
  • Inventory split scheme (online quota vs physical store) if needed
  • Nightly reconciliation agent with 1C and discrepancy logging