Setting up automatic supplier price updates for 1C-Bitrix dropshipping

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
    1175
  • 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
    747
  • 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 Automatic Vendor Price Updates for Dropshipping in 1C-Bitrix

Dropshipping on Bitrix isn't just "showing vendor products". It's daily price synchronization that must run seamlessly: prices updated, margins recalculated, zero-stock products marked unavailable. Without this, the store sells at outdated prices and faces losses or disputes with buyers.

Vendor Price Formats

Vendors provide prices in several formats: CSV, Excel (.xlsx), XML (including CommerceML), JSON via API. Each format requires its own parser. Bitrix has standard XML/CommerceML import through "1C → Exchange with 1C", but it's designed for manual runs and full imports, not incremental price updates.

For automation, a custom update component is needed. Structure:

/local/modules/vendor.priceimport/
├── lib/
│   ├── Parser/
│   │   ├── CsvParser.php
│   │   ├── XlsxParser.php
│   │   └── XmlParser.php
│   ├── PriceUpdater.php
│   └── StockUpdater.php
└── install/
    └── index.php

CSV Import: Parsing and Mapping

Vendor's CSV contains SKU, purchase price, stock. Mapping to Bitrix fields—through config file, so format changes don't require code rewrites:

// config/vendor_a.php
return [
    'delimiter'  => ';',
    'encoding'   => 'windows-1251',
    'skip_rows'  => 1, // Header
    'columns'    => [
        'sku'   => 0,  // SKU—first column
        'price' => 3,  // Price—fourth
        'stock' => 5,  // Stock—sixth
    ],
    'price_type' => 2, // Price type ID in b_catalog_price
    'markup'     => 1.25, // 25% markup
];

Parser:

class CsvParser {
    public function parse(string $filePath, array $config): \Generator {
        $file = new \SplFileObject($filePath);
        $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
        $file->setCsvControl($config['delimiter']);

        $row = 0;
        foreach ($file as $line) {
            if ($row++ < $config['skip_rows']) continue;
            yield [
                'sku'   => trim($line[$config['columns']['sku']]),
                'price' => (float)str_replace(',', '.', $line[$config['columns']['price']]),
                'stock' => (int)$line[$config['columns']['stock']],
            ];
        }
    }
}

Generator (yield) is mandatory for files over 50MB—allows processing without loading entire file to memory.

Price Updates in b_catalog_price Table

SKU to element mapping—through ARTICLE property or XML_ID:

class PriceUpdater {
    public function updateFromParsed(iterable $rows, array $config): array {
        $stats = ['updated' => 0, 'not_found' => 0];

        foreach ($rows as $row) {
            // Find element by SKU
            $el = \CIBlockElement::GetList(
                [], ['PROPERTY_ARTICLE' => $row['sku'], 'IBLOCK_ID' => CATALOG_IBLOCK_ID],
                false, ['nTopCount' => 1], ['ID']
            )->Fetch();

            if (!$el) { $stats['not_found']++; continue; }

            $newPrice = round($row['price'] * $config['markup'], 2);

            \CPrice::SetBasePrice($el['ID'], $newPrice, 'RUB', $config['price_type']);
            $stats['updated']++;
        }

        return $stats;
    }
}

CPrice::SetBasePrice() does INSERT or UPDATE in b_catalog_price—correct tool for single updates. For bulk updates (10,000+ items), direct SQL via temp table with subsequent UPDATE ... FROM is faster.

Scheduling through Bitrix Agents

Agent runs update every 4 hours:

\CAgent::AddAgent(
    'VendorPriceImport::run();',
    'vendor.priceimport',
    'N',  // Not one-time
    14400, // 4-hour interval
    '', 'Y',
    date(DATE_FORMAT, time() + 14400)
);

The run() method downloads price from vendor's FTP/HTTP, parses, updates prices and stock, logs to b_event_log. On error—sends email to admin via CEvent::Send().