Разработка функционала загрузки заказа из Excel 1С-Битрикс
Оптовые покупатели работают со своими прайс-листами и спецификациями в Excel. Они хотят взять готовую таблицу «артикул — количество», загрузить её на сайт и сразу получить корзину. Без этого функционала менеджер тратит час на ручной ввод, делает ошибки, и клиент уходит к конкуренту с более удобным сайтом. Стандартный Битрикс не умеет читать Excel — нужна кастомная реализация.
Парсинг Excel на сервере
Для чтения .xlsx файлов без установки MS Office используется библиотека 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);
}
Резолвинг артикулов
После парсинга получаем массив артикулов. Резолвим их пакетным 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)
);
// ...
}
Превью перед добавлением в корзину
После загрузки файла пользователь видит таблицу с результатами:
| Артикул из файла | Найденный товар | Кол-во | Цена | Статус |
|---|---|---|---|---|
| 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.
Кейс: дистрибьютор строительных материалов
Ситуация: 300+ корпоративных клиентов, каждый со своей таблицей заказа, менеджеры тратили 2–3 часа в день на ввод позиций вручную.
Реализация:
- Детектор формата: распознаёт 7 вариантов шапок (артикул, код, SKU, арт и др.)
- Поддержка
.xlsxи.xls(через PhpSpreadsheet) - Ограничение: максимум 1 000 строк за загрузку, файл до 5 МБ
- Превью с возможностью редактирования количества
- Автоматическое сопоставление по
XML_IDесли артикул не найден в свойстве
Результат: менеджеры освободили 2+ часа в день, клиенты размещают заказы самостоятельно.
| Этап | Срок |
|---|---|
| Настройка PhpSpreadsheet, загрузка файла | 1 день |
| Парсер с детектором заголовков | 2 дня |
| Резолвинг артикулов, пакетный запрос | 1 день |
| Превью-таблица с редактированием | 2 дня |
| Пакетное добавление в корзину | 1 день |
| Тестирование на реальных файлах клиентов | 1 день |
Что входит в разработку
- Загрузчик файлов
.xlsx/.xlsс валидацией формата - Парсер с автоопределением заголовков и позиций колонок
- Пакетный резолвинг артикулов по
b_iblock_element_property - Превью результатов с возможностью коррекции перед добавлением в корзину
- Пакетное добавление найденных товаров в корзину
\Bitrix\Sale\Basket - Шаблон Excel для скачивания







