Стандартный обмен через CommerceML покрывает типовые задачи с 1С: каталог, заказы, остатки. Но когда данные приходят в нестандартном формате — XML от поставщика, JSON из CRM, XLSX‑отчёты — производительность падает, а маппинг превращается в квест. Кастомный модуль импорта/экспорта решает эту проблему: он работает напрямую с любым источником, использует потоковую обработку для больших объёмов и поддерживает двустороннюю синхронизацию с контролем коллизий. Мы разрабатываем такие модули под ключ: от анализа схем до деплоя и обучения администраторов. Наша команда занимается кастомной разработкой более 8 лет и успешно внедрила 50+ интеграций для ритейла, логистики и производства. Оценим проект за один день — свяжитесь с нами для консультации.
Типичный сценарий: у вас есть внешний склад или ERP‑система, которая отдаёт данные в формате CommerceML. Но CommerceML — это тяжёлый XML, который при объёмах более 10 000 товаров за одну загрузку обрабатывается часами. Кастомный модуль парсит данные собственным парсером, используя XMLReader для потокового чтения, и может обрабатывать до 1 000 элементов в секунду. Разница — в 3–5 раз быстрее стандартного обмена. Кроме того, мы реализуем пакетную обработку с агентами Битрикс, что исключает тайм-ауты веб-запросов.
Когда CommerceML не справляется?
CommerceML — универсальный протокол, но он не всегда гибок. Если ваш источник данных — JSON API стороннего сервиса, бинарный XLSX с тысячами строк или требуется сложное преобразование полей (объединение, удаление дублей, связь со справочниками), стандартный обмен неэффективен. Кастомный модуль позволяет обрабатывать произвольные форматы: XML (любая схема), CSV, XLSX, JSON, а также забирать файлы по FTP/SFTP. При объёмах от 100 000 записей обязательна чанковая загрузка — мы встраиваем её в ядро модуля.
Как работает двусторонняя синхронизация?
Самое сложное — избежать коллизий при одновременных изменениях в обеих системах. Мы используем timestamp-based sync с полем sync_hash. При экспорте записываем хеш состояния записи. При следующем импорте: если хеш изменился в источнике — обновляем в Битрикс; если изменился в Битрикс (пользователь отредактировал) — отправляем изменения обратно в источник. Если оба изменились — конфликт, логируем для ручного разбора.
SQL для добавления поля sync_hash
ALTER TABLE b_iblock_element ADD COLUMN sync_hash VARCHAR(32);
ALTER TABLE b_iblock_element ADD COLUMN synced_at DATETIME;
Архитектура кастомного модуля
Модуль Битрикс — это директория в /local/modules/{vendor}.{modulename}/, зарегистрированная через RegisterModule. Стандартная структура:
local/modules/company.import/
├── install/
│ ├── index.php # InstallDB(), UnInstallDB(), DoInstall()
│ └── db/mysql/install.sql
├── lib/
│ ├── Importer.php # основная логика
│ ├── Parser/
│ │ ├── XmlParser.php
│ │ └── CsvParser.php
│ └── Queue/
│ └── ImportQueue.php
├── admin/
│ └── import_settings.php # административный интерфейс
├── include.php
└── .settings.php
Импорт из произвольного XML-источника
Пример реализации парсера для кастомной схемы:
namespace Company\Import;
use Bitrix\Main\Loader;
use Bitrix\Catalog\ProductTable;
class Importer {
private \SimpleXMLElement $xml;
public function __construct(string $filePath) {
Loader::includeModule('iblock');
Loader::includeModule('catalog');
$this->xml = simplexml_load_file($filePath);
}
public function run(): array {
$stats = ['created' => 0, 'updated' => 0, 'errors' => 0];
foreach ($this->xml->products->product as $product) {
try {
$this->processProduct($product, $stats);
} catch (\Throwable $e) {
\Bitrix\Main\Diag\Debug::writeToFile($e->getMessage(), 'IMPORT ERROR', '/bitrix/modules/company.import/error.log');
$stats['errors']++;
}
}
return $stats;
}
private function processProduct(\SimpleXMLElement $p, array &$stats): void {
$externalId = (string)$p->id;
$existing = $this->findByExternalId($externalId);
$fields = [
'IBLOCK_ID' => IMPORT_IBLOCK_ID,
'NAME' => (string)$p->name,
'CODE' => \CUtil::translit((string)$p->name, 'ru'),
'ACTIVE' => (string)$p->is_active === '1' ? 'Y' : 'N',
'PROPERTY_VALUES' => [
'EXTERNAL_ID' => $externalId,
'VENDOR_CODE' => (string)$p->sku,
'DESCRIPTION' => (string)$p->description,
],
];
if ($existing) {
\CIBlockElement::Update($existing, $fields);
$stats['updated']++;
} else {
$el = new \CIBlockElement();
$newId = $el->Add($fields);
if (!$newId) throw new \RuntimeException($el->LAST_ERROR);
$stats['created']++;
}
// Обновляем цену и остаток
\CPrice::SetBasePrice($newId ?? $existing, (float)$p->price, 'RUB');
\CCatalogProduct::Update($newId ?? $existing, ['QUANTITY' => (int)$p->stock]);
}
}
Пакетная обработка и агенты
При 100 000+ записях прямой веб-запрос невозможен — timeout. Используем агент Битрикс с сохранением прогресса в БД. Агент вызывается каждую минуту и обрабатывает следующий чанк:
class ImportQueue {
public static function processChunk(int $jobId, int $offset, int $limit = 500): array {
$job = ImportJobTable::getById($jobId)->fetch();
// ... читаем $limit строк начиная с $offset
// ... обрабатываем
// ... обновляем прогресс в БД
return ['processed' => $count, 'total' => $job['total_rows']];
}
}
function ImportAgent(): string {
$activeJob = getActiveImportJob();
if (!$activeJob) return '';
$result = ImportQueue::processChunk($activeJob['id'], $activeJob['offset']);
if ($activeJob['offset'] + $result['processed'] >= $result['total']) {
markJobComplete($activeJob['id']);
return '';
}
return 'ImportAgent();';
}
Экспорт данных
Экспорт в произвольный формат для внешней системы:
class Exporter {
public function exportOrders(\DateTime $from, \DateTime $to): string {
$orders = \Bitrix\Sale\OrderTable::getList([
'filter' => [
'>=DATE_INSERT' => $from->format('d.m.Y H:i:s'),
'<=DATE_INSERT' => $to->format('d.m.Y H:i:s'),
'CANCELED' => 'N',
],
'select' => ['ID', 'ACCOUNT_NUMBER', 'PRICE', 'CURRENCY', 'DATE_INSERT', 'USER_ID'],
])->fetchAll();
$xml = new \XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('orders');
foreach ($orders as $order) {
$xml->startElement('order');
$xml->writeElement('id', $order['ID']);
$xml->writeElement('number', $order['ACCOUNT_NUMBER']);
$xml->writeElement('amount', $order['PRICE']);
$xml->writeElement('date', $order['DATE_INSERT']->format(\DateTime::ATOM));
// ... позиции заказа
$xml->endElement();
}
$xml->endElement();
return $xml->outputMemory();
}
}
Форматы и источники
| Формат/Источник | Инструменты | Особенности |
|---|---|---|
| XML (кастомный) | SimpleXML, XMLReader | XMLReader для файлов > 100 МБ |
| CSV/XLSX | PhpSpreadsheet, fgetcsv | XLSX — бинарный, требует библиотеку |
| JSON REST API | curl, Guzzle | Пагинация, rate limiting |
| FTP/SFTP | phpseclib | Автоматическая загрузка файлов |
| 1С CommerceML | Встроенный обмен Битрикс | Кастомизация через события |
| Google Sheets | Google Sheets API v4 | Для небольших объёмов |
Как ускорить импорт больших каталогов?
При объёме более 50 000 товаров стандартный обмен упирается в ограничения PHP по времени выполнения и памяти. Кастомный модуль использует асинхронные агенты, чанковую загрузку и профилирование запросов. Мы добавляем индексы на внешние ID и дату синхронизации, что ускоряет поиск дублей в 10 раз. В результатах клиенты получают импорт 100 000 элементов за 2–3 минуты вместо часа.
Сроки и стоимость
Стоимость разработки рассчитывается индивидуально и зависит от сложности маппинга, количества форматов и необходимости двусторонней синхронизации. Точную оценку мы дадим после анализа ваших данных.
| Этап | Срок |
|---|---|
| Анализ форматов и маппинг полей | 1–2 дня |
| Разработка парсера/экспортера | 3–5 дней |
| Пакетная обработка, агент Битрикс | 2–3 дня |
| Административный интерфейс | 2–3 дня |
| Двусторонняя синхронизация (если нужна) | 3–5 дней |
| Тестирование на реальных данных | 2–3 дня |
Итого: 2–3 недели для одностороннего импорта; 3–4 недели для двусторонней синхронизации.
Что входит в работу
- Исходный код модуля с комментариями.
- Документация API модуля и инструкция по настройке.
- Доступ к репозиторию (Git) с историей изменений.
- Обучение администраторов (до 2 часов онлайн).
- Гарантия 3 месяца на бесперебойную работу.
Получите консультацию инженера — закажите предварительный аудит вашего обмена.CommerceML — протокол обмена







