Перейти к содержимому

Выгрузка каталога в файл - прайс-лист, отбор, расписание

Собираем прайс-лист из каталога: с ценами, остатками и отбором, без падения по памяти и без часового ожидания в браузере.

Решение

Открываем файл и пишем заголовок:

$fp = fopen('/home/bitrix/www/upload/price/price.csv', 'w');
fwrite($fp, "\xEF\xBB\xBF"); // метка кодировки для таблиц
fputcsv($fp, ['Артикул', 'Название', 'Цена', 'Остаток'], ';');
// разделитель точка с запятой: с ним таблицы разбирают строки без вопросов

Метка кодировки в начале файла и точка с запятой как разделитель - два условия того, что файл откроется в табличном редакторе сразу. Без них получается знакомая картина: одна колонка с непонятными символами.

Обходим каталог порциями и пишем строки:

$lastId = 0;
while (true) {
$res = CIBlockElement::GetList(['ID' => 'ASC'], ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y',
'>ID' => $lastId], false, ['nTopCount' => 500], ['ID', 'NAME', 'PROPERTY_CML2_ARTICLE']);
$rows = 0;
while ($row = $res->Fetch()) { $lastId = $row['ID']; $rows++; /* запись ниже */ }
if (!$rows) { break; }
}

Файл пишут построчно, а не собирают целиком в памяти. Каталог на десятки тысяч позиций в одном массиве - это гарантированное падение по памяти, а построчная запись работает на любом объёме.

Добавляем цены и остатки:

$price = CCatalogProduct::GetOptimalPrice($row['ID'], 1, ['2']); // группа покупателей
$product = CCatalogProduct::GetByID($row['ID']);
fputcsv($fp, [$row['PROPERTY_CML2_ARTICLE_VALUE'], $row['NAME'],
$price['DISCOUNT_PRICE'] ?? '', $product['QUANTITY'] ?? 0], ';');

Цена зависит от группы покупателя, и в прайсе это решают явно и заранее. Файл «для всех» с розничной ценой и файл для оптовиков - разные выгрузки, а не одна с пометкой в шапке.

Ставим выгрузку в расписание:

Окно терминала
30 4 * * * /usr/bin/php /home/bitrix/www/local/tools/price.php >> /var/log/price.log 2>&1
# ночью каталог не мешает посетителям, а файл готов к началу рабочего дня

Долгую выгрузку каталога запускают вне окна браузера. Ночной запуск снимает и вопрос ограничения времени выполнения, и вопрос нагрузки: тяжёлая выборка не борется за базу с посетителями.

Отбор для прайса стоит держать точно таким же, как и на витрине сайта. Файл, где есть снятые с продажи позиции, возвращается вопросами от клиентов, а расхождение с сайтом подрывает доверие к обоим источникам.

Готовый файл кладут в место, закрытое от посторонних глаз. Прайс-лист с оптовыми ценами в открытом каталоге загрузок находится поисковой системой за неделю и живёт в её выдаче ещё месяц.

Проверять стоит не только сам факт создания файла, но и число строк. Пустой или вдвое короче обычного файл означает, что отбор изменился или обмен что-то выключил, а узнать об этом лучше раньше клиентов.

Типичные проблемы

Таблица открывает файл одной колонкой.

Разделитель не тот, которого ждёт табличный редактор. С точкой с запятой строки разбираются вообще без настроек.

Вместо русских букв нечитаемые символы.

В самом начале файла нет метки кодировки. Табличный редактор определяет кодировку файла именно по ней.

Скрипт падает по памяти.

Данные собираются в общий массив вместо построчной записи. Каталог целиком в память процесса не помещается.

В прайсе цены не той группы.

Цена взята без указания группы покупателя. Розничная и оптовая цены - это две разные выгрузки, а не одна общая.

Оптовый прайс нашли в поиске.

Файл лежит в открытом всем каталоге загрузок. Такие файлы кладут в закрытое место либо отдают только по проверке прав.

Частые вопросы

В каком формате отдавать прайс?

Текстовым файлом с разделителем: он открывается везде и весит мало. Готовые таблицы нужны реже, чем кажется.

Как отдать прайс только своим?

Скриптом с проверкой прав, который читает файл из закрытого каталога. Ссылка на файл в открытом каталоге проверкой не является.

Сколько строк выдержит выгрузка?

Любое число при построчной записи: ограничение только по времени. Сотня тысяч позиций укладывается в минуты.

Как выгрузить с картинками?

Столбцом с адресами картинок, а не файлами. Архив с изображениями собирают отдельно и по запросу.

Смежное

Первоисточник