Оптові покупці працюють зі своїми прайс-листами та специфікаціями в 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-запитом — це в 10-15 разів швидше, ніж 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 для оптових замовлень та виконали понад 50 успішних проектів у цій сфері. Наші рішення проходять навантажувальне тестування на каталогах до 100 000 товарів. Гарантуємо стабільну роботу та підтримку після впровадження.
Кейс: дистриб'ютор будівельних матеріалів (наш клієнт, з нашої практики)
Ситуація: 300+ корпоративних клієнтів, кожен зі своєю таблицею замовлення, менеджери витрачали 2–3 години на день на введення позицій вручну.
Реалізація:
- Детектор формату: розпізнає 7 варіантів шапок (артикул, код, SKU, арт та ін.)
- Підтримка
.xlsxта.xls(через PhpSpreadsheet) - Обмеження: максимум 1 000 рядків за завантаження, файл до 5 МБ
- Прев'ю з можливістю редагування кількості
- Автоматичне зіставлення по
XML_IDякщо артикул не знайдено у властивості
Результат: менеджери звільнили 2+ години на день, клієнти розміщують замовлення самостійно. Економія: зниження витрат на обробку замовлень до 70% (близько 15 000 грн щомісяця). Весь функціонал був впроваджений за 8 робочих днів.
| Етап | Термін |
|---|---|
| Налаштування PhpSpreadsheet, завантаження файлу | 1 день |
| Парсер з детектором заголовків | 2 дні |
| Резолвінг артикулів, пакетний запит | 1 день |
| Прев'ю-таблиця з редагуванням | 2 дні |
| Пакетне додавання до кошика | 1 день |
| Тестування на реальних файлах клієнтів | 1 день |
Що входить у розробку?
- Завантажувач файлів
.xlsx/.xlsз валідацією формату - Парсер з авто визначенням заголовків та позицій колонок
- Пакетний резолвінг артикулів по
b_iblock_element_property - Прев'ю результатів з можливістю корекції перед додаванням до кошика
- Пакетне додавання знайдених товарів до кошика
\Bitrix\Sale\Basket - Шаблон Excel для завантаження
Особливі випадки: коли потрібен кастомний парсер
Якщо ваші клієнти надсилають файли з нестандартною структурою — плаваючими заголовками, різними кодуваннями або додатковими колонками — стандартний імпорт Бітрікса не впорається. Тільки кастомний парсер з детектором формату забезпечить коректне завантаження.
Оцінимо ваш проект за один робочий день — зв'яжіться з нами, щоб обговорити деталі. Ми підготуємо комерційну пропозицію з точними термінами та вартістю. Замовте розробку модуля, і ми протягом дня підготуємо оцінку.







