Setting up scheduled balance updates from external 1C-Bitrix sources

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
    1189
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    813
  • 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
    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
    976

Setting up stock updates on schedule from external sources for 1С-Bitrix

Customer places an order, pays, waits for delivery — but the item isn't in stock. Stock levels on the site weren't updated for two days, and in that time the position was sold. Refund, negative review, lost customer. Automatic scheduled stock updates solve this problem — provided it's configured correctly.

How Bitrix stores stock

The catalog module stores availability data in several tables:

  • b_catalog_product — main product table. Field QUANTITY — total stock, QUANTITY_TRACE — is quantity tracking enabled, CAN_BUY_ZERO — can buy when zero.
  • b_catalog_store_product — stock by warehouse. Field AMOUNT — quantity in specific warehouse (STORE_ID).
  • b_catalog_store — warehouse reference.

If the site has one warehouse — update QUANTITY in b_catalog_product is sufficient. If warehouse tracking is enabled (multiple warehouses, address-based storage) — update b_catalog_store_product and Bitrix recalculates total automatically.

Update via API

Simple variant — one warehouse:

\Bitrix\Catalog\ProductTable::update($productId, [
    'QUANTITY' => $newQuantity,
]);

Warehouse tracking — multiple warehouses:

$existing = \Bitrix\Catalog\StoreProductTable::getList([
    'filter' => ['PRODUCT_ID' => $productId, 'STORE_ID' => $storeId],
])->fetch();

if ($existing) {
    \Bitrix\Catalog\StoreProductTable::update($existing['ID'], ['AMOUNT' => $newQuantity]);
} else {
    \Bitrix\Catalog\StoreProductTable::add([
        'PRODUCT_ID' => $productId,
        'STORE_ID'   => $storeId,
        'AMOUNT'     => $newQuantity,
    ]);
}

After updating warehouse stocks, call total quantity recalculation:

CCatalogProduct::QuantityTracer($productId);

Supplier data formats

Format Parsing Specifics
CSV fgetcsv() Simple but untyped — "10" and "10 pcs" need normalization
Excel (XLSX) PhpSpreadsheet Often multiple sheets, headers on line 2–3
XML (CommerceML) SimpleXMLElement 1С standard, structure known in advance
REST API curl / Guzzle JSON response, pagination, auth
FTP file ftp_get() File appears at specific time, needs retry

Product mapping

Key task — match supplier product identifier with Bitrix catalog element. Options:

  • By SKU — property PROPERTY_ARTICLE or PROPERTY_SUPPLIER_SKU. Most reliable if SKUs are unique.
  • By XML_ID — if catalog was initially imported from same source.
  • By barcodeb_catalog_product_barcode table. Reliable but not all products have barcodes.

For mapping, create indexed correspondence table:

CREATE TABLE parser_product_map (
    supplier_sku VARCHAR(100) NOT NULL,
    product_id   INT NOT NULL,
    store_id     INT DEFAULT 1,
    PRIMARY KEY (supplier_sku, store_id),
    INDEX idx_product (product_id)
);

Query through this table is 10–50 times faster than searching by info block properties for each product.

Handling zero stock

When product runs out, three behavior strategies:

  • Deactivation (ACTIVE = 'N') — product disappears from site. Bad for SEO: page stops indexing, positions lost.
  • Show with "Out of stock" labelQUANTITY = 0, CAN_BUY_ZERO = 'N'. "Buy" button replaced with "Notify me". Optimal option.
  • Pre-orderCAN_BUY_ZERO = 'Y'. Customer can place order, item comes with next shipment. Good for predictable restock items.

Strategy is set globally in catalog module settings and can be overridden per product.

Cron and schedule

Update frequency depends on product turnover:

Product type Update frequency Justification
Fast-moving (electronics, food) Every 15–30 min Quick turnover, high oversell risk
Medium (clothing, tools) Every 1–2 hours Balance between accuracy and load
Slow-moving (furniture, equipment) 2–4 times daily Low turnover
# Update stock every 30 minutes
*/30 * * * * /usr/bin/php /home/bitrix/scripts/update_stock.php >> /var/log/stock_update.log 2>&1

Performance

Updating 50,000+ positions element-by-element via API is too slow — 3–5 seconds per product due to event handlers and cache recalculation. Optimization:

  • Batch UPDATE — direct SQL query to update b_catalog_store_product in batches of 500–1000 rows.
  • Disable events\Bitrix\Catalog\ProductTable::disableEvents() during bulk update.
  • Deferred recalculation — update all stocks, then recalculate availability once and clear cache.

Monitoring

Stock update is a critical process. If the script crashes or supplier doesn't provide file — catalog shows stale data. Minimal monitoring:

  • Check time of last successful update. If more than two intervals passed — alert.
  • Log number of updated, skipped (not found in mapping), and errored positions.
  • Control anomalies: if 80% of catalog stock zeroed out — likely supplier file error, not real sell-out.