Настройка массового обновления цен 1С-Битрикс
Поставщик прислал прайс с новыми закупочными ценами — 3000 позиций. Розничная наценка 40%. Нужно обновить розничные цены к утру. Вручную — нереально. Импорт через 1С — не всегда есть связка. Прямое обновление через API Битрикса — решение за несколько часов настройки.
Таблица цен и типы цен
Цены хранятся в b_catalog_price. Ключевые поля: PRODUCT_ID, CATALOG_GROUP_ID (тип цены), PRICE, CURRENCY, QUANTITY_FROM, QUANTITY_TO (для ценовых диапазонов).
Типы цен — b_catalog_group: BASE — базовая, остальные — дополнительные (розничная, оптовая, закупочная). CATALOG_GROUP_ID = 1 обычно — базовая цена, но это зависит от конкретной установки.
Получить ID типа цены по названию:
$priceType = \Bitrix\Catalog\GroupTable::getList([
'filter' => ['NAME' => 'Розничная'],
'select' => ['ID'],
])->fetch();
$priceTypeId = $priceType['ID'];
Массовое обновление через D7
Обновление цены одного товара:
// Проверить, существует ли цена
$existing = \Bitrix\Catalog\PriceTable::getList([
'filter' => ['PRODUCT_ID' => $productId, 'CATALOG_GROUP_ID' => $priceTypeId],
'select' => ['ID'],
])->fetch();
if ($existing) {
\Bitrix\Catalog\PriceTable::update($existing['ID'], [
'PRICE' => $newPrice,
'CURRENCY' => 'BYN',
]);
} else {
\Bitrix\Catalog\PriceTable::add([
'PRODUCT_ID' => $productId,
'CATALOG_GROUP_ID' => $priceTypeId,
'PRICE' => $newPrice,
'CURRENCY' => 'BYN',
]);
}
Для массового обновления — цикл с батчингом. При 3000 позиций рекомендуется батч по 100 с паузой 50ms, чтобы не создавать пиков нагрузки на MySQL.
Расчёт цены по наценке
При загрузке закупочных цен розничная рассчитывается автоматически:
function calcRetailPrice(float $purchasePrice, float $markup): float {
return round($purchasePrice * (1 + $markup / 100), 2);
}
foreach ($newPrices as $item) {
$retail = calcRetailPrice($item['purchase_price'], 40.0);
updatePrice($item['product_id'], RETAIL_PRICE_TYPE_ID, $retail);
updatePrice($item['product_id'], PURCHASE_PRICE_TYPE_ID, $item['purchase_price']);
}
Загрузка из Excel/CSV
Прайс от поставщика чаще всего приходит в Excel или CSV. Для парсинга Excel используется PhpSpreadsheet:
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load('/path/to/price.xlsx');
$sheet = $spreadsheet->getActiveSheet();
foreach ($sheet->getRowIterator(2) as $row) { // со второй строки (пропускаем заголовок)
$cells = $row->getCellIterator();
$cells->setIterateOnlyExistingCells(false);
$rowData = [];
foreach ($cells as $cell) {
$rowData[] = $cell->getValue();
}
$articul = $rowData[0]; // A: артикул
$newPurchase = (float)$rowData[3]; // D: закупочная цена
// Найти товар по артикулу
$productId = findProductByArticul($articul);
if ($productId) {
updatePrice($productId, PURCHASE_PRICE_TYPE_ID, $newPurchase);
updatePrice($productId, RETAIL_PRICE_TYPE_ID, calcRetailPrice($newPurchase, 40.0));
}
}
Инвалидация кэша после обновления
После массового обновления цен страницы каталога показывают старые цены из кэша. Сброс кэша для всего каталога:
// Удалить кэш компонентов каталога
\Bitrix\Main\Application::getInstance()->getTaggedCache()->clearByTag('catalog');
// Или сброс по инфоблоку
\Bitrix\Main\Application::getInstance()->getTaggedCache()->clearByTag('iblock_id_' . $iblockId);
Альтернатива — не сбрасывать кэш массово, а дождаться естественного устаревания (TTL). Но если цены изменились на акционные с конкретным сроком, дожидаться нельзя — сброс обязателен.
Лог изменений цен
Для аудита рекомендуется перед обновлением сохранять старые цены в кастомную таблицу catalog_price_history с полями (product_id, price_type_id, old_price, new_price, changed_by, changed_at). Это позволяет откатить ошибочное обновление и анализировать динамику цен.







