Оптовые покупатели работают со своими прайс-листами и спецификациями в Excel. Они хотят взять готовую таблицу «артикул — количество», загрузить её на сайт и сразу получить корзину. Без этого функционала менеджер тратит час на ручной ввод, делает ошибки, и клиент уходит к конкуренту с более удобным сайтом. Стандартный Битрикс не включает инструментов для чтения Excel — необходима кастомная реализация. Наше решение — модуль загрузки заказов из Excel под ключ, адаптированный под ваши бизнес-процессы и форматы файлов. Это исключает рутину, сокращает операционные затраты на десятки тысяч рублей ежемесячно и снижает нагрузку на менеджеров.
Как работает загрузка заказа из Excel?
Загрузка состоит из нескольких этапов: парсинг файла на сервере, детектор заголовков, резолвинг артикулов и добавление в корзину. Рассмотрим каждый шаг с реальным кодом.
Парсинг Excel на сервере
Для чтения .xlsx файлов используется библиотека PhpSpreadsheet (преемник PHPExcel). Подключается через Composer:
composer require phpoffice/phpspreadsheet
AJAX-контроллер обработки файла:
public function uploadAction(): array
{
$file = $_FILES['excel_file'];
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
return ['status' => 'error', 'message' => 'Файл не загружен'];
}
$allowedMimes = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
];
if (!in_array($file['type'], $allowedMimes)) {
return ['status' => 'error', 'message' => 'Неверный формат файла'];
}
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createAutomatic(
\PhpOffice\PhpSpreadsheet\IOFactory::identify($file['tmp_name'])
);
$spreadsheet = $reader->load($file['tmp_name']);
$sheet = $spreadsheet->getActiveSheet();
$rows = $sheet->toArray();
return $this->processRows($rows);
}
Логика разбора строк
Формат файла клиента непредсказуем: шапка может быть в первой или второй строке, колонки — в любом порядке. Реализуем детектор заголовков:
private function processRows(array $rows): array
{
// Ищем строку-заголовок по ключевым словам
$headerRow = null;
$articleCol = null;
$quantityCol = null;
foreach ($rows as $i => $row) {
foreach ($row as $j => $cell) {
$cell = mb_strtolower(trim((string)$cell));
if (in_array($cell, ['артикул', 'арт', 'article', 'sku', 'код'])) {
$articleCol = $j;
$headerRow = $i;
}
if (in_array($cell, ['количество', 'кол-во', 'qty', 'quantity', 'кол'])) {
$quantityCol = $j;
}
}
if ($headerRow !== null) break;
}
// Если заголовок не найден — предполагаем: колонка 0 = артикул, колонка 1 = количество
$articleCol = $articleCol ?? 0;
$quantityCol = $quantityCol ?? 1;
$dataStart = ($headerRow ?? -1) + 1;
$items = [];
for ($i = $dataStart; $i < count($rows); $i++) {
$article = trim((string)($rows[$i][$articleCol] ?? ''));
$qty = (float)str_replace(',', '.', $rows[$i][$quantityCol] ?? 1);
if ($article !== '') {
$items[] = ['article' => $article, 'quantity' => max(1, $qty)];
}
}
return $this->resolveArticles($items);
}
Полный код детектора заголовков
Этот метод перебирает строки, ищет клетки с ключевыми словами ('артикул', 'sku', 'qty' и т.д.) и определяет позиции колонок. Если заголовок не обнаружен, используется предположение по первой колонке и второй.Резолвинг артикулов
После парсинга получаем массив артикулов. Резолвим их пакетным SQL-запросом — это быстрее, чем N отдельных запросов:
private function resolveArticles(array $items): array
{
$articles = array_column($items, 'article');
// Ищем в свойствах торговых предложений
$placeholders = implode(',', array_fill(0, count($articles), '?'));
$rs = $connection->query(
"SELECT ie.ID, iep.VALUE AS ARTICLE, ie.IBLOCK_ELEMENT_ID AS PRODUCT_ID
FROM b_iblock_element ie
JOIN b_iblock_element_property iep ON iep.IBLOCK_ELEMENT_ID = ie.ID
WHERE iep.IBLOCK_PROPERTY_ID = ? AND iep.VALUE IN ($placeholders)",
array_merge([$articlePropertyId], $articles)
);
// ...
}
Почему пакетный запрос быстрее?
При импорте 1000 строк выполнение 1000 отдельных SELECT-запросов создаёт колоссальную нагрузку на базу данных. Пакетный запрос с одним WHERE IN снижает время резолвинга с десятков секунд до долей секунды. В наших проектах это даёт ускорение в 10–15 раз на каталогах от 10 000 товаров.
Превью перед добавлением в корзину
После загрузки файла пользователь видит таблицу с результатами:
| Артикул из файла | Найденный товар | Кол-во | Цена | Статус |
|---|---|---|---|---|
| ABC-123 | Болт М8×20 | 100 | 2.50 р. | Найден |
| XYZ-999 | — | 5 | — | Не найден |
| DEF-456 | Гайка М8 | 50 | 1.20 р. | Нет на складе |
Клиент может скорректировать количество, убрать не найденные позиции и нажать «Добавить в корзину». Добавление — то же пакетное \Bitrix\Sale\Basket из предыдущего сценария.
Шаблон для скачивания
На странице загрузки размещаем ссылку на скачивание шаблона Excel — файл с правильными заголовками колонок. Генерируется через PhpSpreadsheet или хранится как статичный файл в /upload/templates/order_template.xlsx.
Почему стоит доверить разработку нам?
Мы специализируемся на Битриксе более 10 лет и реализовали десятки интеграций с Excel для оптовых заказов. Наши решения проходят нагрузочное тестирование на каталогах до 100 000 товаров. Гарантируем стабильную работу и поддержку после внедрения.
Кейс: дистрибьютор строительных материалов (из нашей практики)
Ситуация: 300+ корпоративных клиентов, каждый со своей таблицей заказа, менеджеры тратили 2–3 часа в день на ввод позиций вручную.
Реализация:
- Детектор формата: распознаёт 7 вариантов шапок (артикул, код, SKU, арт и др.)
- Поддержка
.xlsxи.xls(через PhpSpreadsheet) - Ограничение: максимум 1 000 строк за загрузку, файл до 5 МБ
- Превью с возможностью редактирования количества
- Автоматическое сопоставление по
XML_IDесли артикул не найден в свойстве
Результат: менеджеры освободили 2+ часа в день, клиенты размещают заказы самостоятельно. Экономия: снижение затрат на обработку заказов до 70%. Весь функционал был внедрён за 8 рабочих дней.
| Этап | Срок |
|---|---|
| Настройка PhpSpreadsheet, загрузка файла | 1 день |
| Парсер с детектором заголовков | 2 дня |
| Резолвинг артикулов, пакетный запрос | 1 день |
| Превью-таблица с редактированием | 2 дня |
| Пакетное добавление в корзину | 1 день |
| Тестирование на реальных файлах клиентов | 1 день |
Что входит в разработку?
- Загрузчик файлов
.xlsx/.xlsс валидацией формата - Парсер с автоопределением заголовков и позиций колонок
- Пакетный резолвинг артикулов по
b_iblock_element_property - Превью результатов с возможностью коррекции перед добавлением в корзину
- Пакетное добавление найденных товаров в корзину
\Bitrix\Sale\Basket - Шаблон Excel для скачивания
Особые случаи: когда требуется кастомный парсер
Если ваши клиенты присылают файлы с нестандартной структурой — плавающими заголовками, разными кодировками или дополнительными колонками — стандартный импорт Битрикса не справится. Только кастомный парсер с детектором формата обеспечит корректную загрузку.
Оценим ваш проект за один рабочий день — свяжитесь с нами, чтобы обсудить детали. Мы подготовим коммерческое предложение с точными сроками и стоимостью. Закажите разработку модуля, и мы в течение дня подготовим оценку.







