Автонаполнение остатков и цен из прайс-листов поставщиков 1С-Битрикс
Прайс-лист поставщика — Excel или CSV, который присылают по расписанию на почту или выкладывают на FTP. В отличие от API, прайс не обновляется в реальном времени, но для большинства b2b-магазинов обновление раз в день-два полностью достаточно. Задача: извлечь цены и остатки из нестандартного файла и обновить b_catalog_price и b_catalog_store_product.
Получение прайс-листа
Email с вложением — самый частый сценарий. Подключаемся к ящику через IMAP, ищем письма от поставщика, скачиваем вложение:
$imap = imap_open('{mail.example.com:993/imap/ssl}INBOX', $user, $pass);
$emails = imap_search($imap, 'FROM "[email protected]" UNSEEN');
foreach ($emails as $num) {
$structure = imap_fetchstructure($imap, $num);
// извлекаем вложение
}
FTP/SFTP — регулярно скачиваем файл, сравниваем дату изменения с предыдущим запуском. Если файл не изменился — пропускаем.
HTTP URL — поставщик публикует прайс по ссылке, иногда с Basic Auth.
Чтение Excel/CSV
Для Excel используем PhpSpreadsheet (преемник PHPExcel):
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);
$sheet = $spreadsheet->getActiveSheet();
$rows = $sheet->toArray();
Проблема: у каждого поставщика свой формат. Столбцы с артикулом, ценой и остатком находятся в разных позициях, первые строки могут быть заголовками разной длины.
Решение: конфигурируемый маппинг колонок, хранящийся в базе:
supplier_id: 42
sku_column: B # артикул в столбце B
price_column: D # цена в столбце D
qty_column: F # остаток в столбце F
header_rows: 3 # первые 3 строки — шапка
Обновление цен
Цены в Битриксе хранятся в b_catalog_price. Каждый тип цены — отдельная запись:
$priceType = CCatalogPriceType::GetList([], ['NAME' => 'Закупочная'])->Fetch();
CCatalogProduct::SetPrice($elementId, $priceType['ID'], $price, 'RUB');
Если у поставщика несколько типов цен (розничная, оптовая, специальная) — создаём соответствующие типы в Битриксе и обновляем каждый отдельно.
Наценка при импорте: часто нужно импортировать закупочную цену и автоматически рассчитывать розничную. Коэффициент наценки хранится в настройках поставщика и применяется при записи:
$retailPrice = $supplierPrice * $supplier->getMarkupCoefficient();
Обновление остатков
b_catalog_store_product — таблица остатков по складам. Если склады не используются, обновляем QUANTITY напрямую через CCatalogProduct::Update().
При использовании складов:
CCatalogStoreProduct::Update($storeProductId, ['AMOUNT' => $qty]);
// или добавляем запись если не существует
CCatalogStoreProduct::Add([
'PRODUCT_ID' => $elementId,
'STORE_ID' => $storeId,
'AMOUNT' => $qty,
]);
Идентификация товаров по артикулу
Прайс содержит артикулы поставщика, в Битриксе хранятся свои коды. Нужен словарь соответствий. Варианты хранения:
- Свойство
SUPPLIER_SKUв инфоблоке — простой вариант - Highload-блок
SupplierMappingс парами(supplier_id, supplier_sku, element_id)— масштабируемый
Для 50 000+ SKU строим обратный индекс в памяти при запуске воркера: загружаем все пары в массив PHP один раз, используем для маппинга без запросов к БД.
Таймлайн работ
| Этап | Срок |
|---|---|
| Настройка получения файла (email/FTP/HTTP) | 4–8 часов |
| Чтение и парсинг Excel/CSV с конфигурируемым маппингом | 1–2 дня |
| Обновление цен и остатков в Битриксе | 1 день |
| Логика идентификации товаров, словарь артикулов | 4–8 часов |
| Обработка ошибок, логирование, расписание | 4–6 часов |
Итого: 4–6 рабочих дней на одного поставщика. При нескольких поставщиках — конфигурируемый маппинг окупается с третьего подключения.







