Как загрузить данные из Excel в иерархический справочник 1С с автоматическим созданием групп

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Часто перед разработчиком стоит задача перенести данные из внешних файлов (Excel, CSV) в справочники 1С, имеющие сложную иерархическую структуру. Например, общероссийские классификаторы (ОКПД, ОКВЭД), где код элемента сам по себе диктует уровень вложенности. Просто загрузить строки в плоский список недостаточно — необходимо программно воссоздать «дерево» групп и подгрупп. В этой статье мы подробно разберем, как реализовать такой алгоритм, учитывая особенности платформы и структуры кодов. Для решения такой задачи без ручной разработки можно использовать универсальную обработку для импорта справочников из Excel.

Анализ исходных данных и постановка задачи

Рассмотрим ситуацию, когда в Excel-файле содержатся коды вида А, 01, 01.1, 01.11, 01.11.11.110. Нам нужно, чтобы программа понимала: элемент с кодом А — это корневая группа, 01 — подгруппа внутри А, а длинный цифровой код — конечный элемент. Основная сложность заключается в том, что в файле данные идут подряд, и нам нужно на лету определять родителя для каждой новой записи.

Для решения задачи мы разделим процесс на три этапа: чтение файла, разбор кода (парсинг) для определения уровня иерархии и корректное создание объектов в базе данных 1С.

Шаг 1. Чтение данных из Excel без использования COM-объектов

Для чтения файлов Excel наиболее стабильным и быстрым способом является использование встроенного объекта ТабличныйДокумент. Этот метод не требует наличия установленного Microsoft Office на сервере или компьютере пользователя. Проанализируем базовый код для чтения колонок:


ТабДок = Новый ТабличныйДокумент;
Попытка
    ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
    Сообщить("Не удалось прочитать файл!");
    Возврат;
КонецПопытки;

КоличествоСтрок = ТабДок.ВысотаТаблицы;
// Цикл по строкам файла, начиная со второй (пропускаем заголовок)
Для НомерСтроки = 2 По КоличествоСтрок Цикл
    КодИзФайла = СокрЛП(ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0") + "C1").ТекущаяОбласть.Текст);
    НаименованиеИзФайла = СокрЛП(ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0") + "C2").ТекущаяОбласть.Текст);
    // Далее следует логика обработки...
КонецЦикла;

Шаг 2. Разбор иерархии кода

Чтобы определить, является ли запись группой или элементом, и кто ее «родитель», необходимо разбить код на составляющие по разделителю (точке). В современных версиях платформы 8.3 для этого используется функция СтрРазделить. Однако, если вы работаете на более старых релизах, нам потребуется вспомогательная функция.

Рассмотрим универсальную функцию разложения строки в массив, которую можно использовать в любом модуле:


Функция РазложитьСтрокуВМассивПодстрок(Знач Строка, Знач Разделитель = ".") Экспорт
    Результат = Новый Массив;
    Позиция = Найти(Строка, Разделитель);
    Пока Позиция > 0 Цикл
        Подстрока = Лев(Строка, Позиция - 1);
        Если Не ПустаяСтрока(Подстрока) Тогда
            Результат.Добавить(Подстрока);
        КонецЕсли;
        Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
        Позиция = Найти(Строка, Разделитель);
    КонецЦикла;
    Если Не ПустаяСтрока(Строка) Тогда
        Результат.Добавить(Строка);
    КонецЕсли;
    Возврат Результат;
КонецФункции

Важный нюанс: В некоторых классификаторах иерархия определяется не только точками, но и длиной строки. Например, код 01 может быть группой, а 01.1 — ее подгруппой. Проанализируем логику: количество элементов в массиве после деления по точке подскажет нам уровень вложенности.

Шаг 3. Алгоритм создания групп и поиска родителя

Теперь объединим чтение данных и создание объектов. Нам нужно проверять наличие родительской группы в базе. Чтобы не замедлять работу постоянным поиском через НайтиПоКоду, рекомендуется использовать кэширование или структуру соответствия, но для простоты разберем базовый надежный алгоритм.

Рассмотрим логику создания объекта:


// Внутри цикла по строкам Excel
МассивЧастей = РазложитьСтрокуВМассивПодстрок(КодИзФайла, ".");
УровеньВложенности = МассивЧастей.Количество();

// Определяем, группа это или конечный элемент
// Например, если точек в коде меньше 3 — это группы
ЭтоГруппа = ?(УровеньВложенности < 4, Истина, Ложь);

СправочникМенеджер = Справочники.СВ_КлассификаторПродукции;

// Ищем, не создан ли уже такой элемент
СуществующаяСсылка = СправочникМенеджер.НайтиПоКоду(КодИзФайла);

Если СуществующаяСсылка.Пустая() Тогда
    Если ЭтоГруппа Тогда
        НовыйОбъект = СправочникМенеджер.СоздатьГруппу();
    Иначе
        НовыйОбъект = СправочникМенеджер.СоздатьЭлемент();
    КонецЕсли;
    НовыйОбъект.Код = КодИзФайла;
Иначе
    НовыйОбъект = СуществующаяСсылка.ПолучитьОбъект();
КонецЕсли;

НовыйОбъект.Наименование = НаименованиеИзФайла;

// Поиск родителя (усекаем код до предыдущего уровня)
Если УровеньВложенности > 1 Тогда
    // Пытаемся найти родительский код. 
    // Если код "01.11.12", то родитель имеет код "01.11"
    ПозицияПоследнейТочки = НайтиРеверс(КодИзФайла, "."); // Самописная функция или Лев() до точки
    КодРодителя = Лев(КодИзФайла, СтрДлина(КодИзФайла) - (СтрДлина(МассивЧастей[УровеньВложенности-1]) + 1));
    
    РодительСсылка = СправочникМенеджер.НайтиПоКоду(КодРодителя);
    Если Не РодительСсылка.Пустая() Тогда
        НовыйОбъект.Родитель = РодительСсылка;
    КонецЕсли;
КонецЕсли;

НовыйОбъект.Записать();

Оптимизация и важные советы

Проанализируем несколько критически важных моментов, которые помогут сделать загрузку профессиональной:

  1. Использование транзакций. Запись каждого элемента в цикле создает огромную нагрузку на базу. Обязательно используйте конструкцию НачатьТранзакцию() перед началом цикла и ЗафиксироватьТранзакцию() в конце. Это ускорит загрузку в десятки раз.
  2. Тип иерархии. В настройках справочника (в конфигураторе) должно быть установлено свойство «Иерархия групп и элементов». Если установлена «Иерархия элементов», то метод СоздатьГруппу() вызовет ошибку, и все записи нужно будет создавать через СоздатьЭлемент().
  3. Обработка дублей. Всегда проверяйте существование элемента по коду перед созданием нового. Это позволит запускать загрузку повторно (например, при обновлении наименований) без замусоривания базы.
  4. Очистка данных. Используйте функцию СокрЛП() для кодов и наименований. Лишний пробел в конце кода в Excel может привести к тому, что 1С не найдет родителя по «визуально похожему» коду.

Разберем ситуацию с буквенными префиксами (например, код А.01). В этом случае логика разбиения по точке остается прежней, но первым элементом массива будет буква. Если ваша конфигурация подразумевает, что А — это корень, убедитесь, что в справочнике разрешены коды произвольной длины и типа «Строка».

Выясним причину возможных ошибок при записи: если система сообщает «Родитель не может быть элементом», значит, вы пытаетесь назначить родителем объект, который был создан методом СоздатьЭлемент(). Для иерархических справочников «Группы и элементы» родителем всегда должна выступать именно Группа.

Таким образом, мы построили надежный механизм, который анализирует структуру кода Excel-файла, определяет иерархическую соподчиненность и корректно переносит данные в 1С, сохраняя структуру классификатора. При необходимости можно воспользоваться готовой обработкой для загрузки данных в иерархические справочники 1С.

← На главную