Оптовые покупатели работают со своими прайс-листами и спецификациями в 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 для скачивания
Особые случаи: когда требуется кастомный парсер
Если ваши клиенты присылают файлы с нестандартной структурой — плавающими заголовками, разными кодировками или дополнительными колонками — стандартный импорт Битрикса не справится. Только кастомный парсер с детектором формата обеспечит корректную загрузку.
Оценим ваш проект за один рабочий день — свяжитесь с нами, чтобы обсудить детали. Мы подготовим коммерческое предложение с точными сроками и стоимостью. Закажите разработку модуля, и мы в течение дня подготовим оценку.







