Как правильно реализовать сортировку строк документа по иерархии номенклатуры?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки часто встречается требование от складских работников или менеджеров: "Сделайте так, чтобы товары в документе шли по порядку папок в справочнике". Это кажется логичным для сборки заказа. Однако при реализации этой задачи начинающие разработчики часто совершают две ошибки: используют неправильную конструкцию запроса и применяют опасные методы перезаписи данных. Разберем эту ситуацию подробно, проанализируем ошибки и найдем верные решения.

Анализ проблемы и ошибок в коде

Рассмотрим типичный код, который вызывает вопросы. Разработчик пытается получить таблицу товаров, отсортировать её запросом и загрузить обратно в документ.


// Пример ошибочного подхода
Запрос.Текст = 
    "ВЫБРАТЬ
    |    РеализацияТоваровУслугТовары.Ссылка,
    |    ... // перечисление всех полей
    |ИЗ
    |    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
    |ГДЕ
    |    РеализацияТоваровУслугТовары.Ссылка = &Ссылка
    |
    |УПОРЯДОЧИТЬ ПО  
    |Номенклатура ИЕРАРХИЯ"; // Ошибка логики сортировки

Результат = Запрос.Выполнить();
Товар = Результат.Выгрузить();
Объект.Товары.Загрузить(Товар); // Критическая ошибка безопасности данных

Давайте разберем, что здесь не так.

Проблема 1: Сортировка ИЕРАРХИЯ в плоской таблице

Конструкция УПОРЯДОЧИТЬ ПО Номенклатура ИЕРАРХИЯ предназначена для построения древовидных структур (обычно вместе с итогами). Когда мы применяем её к плоской выборке (только элементы, без групп), платформа пытается сгруппировать записи по родителям. Но так как родителей в выборке нет, визуально сортировка может выглядеть хаотично или происходить по внутренним идентификаторам, а не по алфавиту папок.

Решение: Если нам нужно, чтобы сначала шли товары из папки "А", потом из папки "Б", нам нужно явно указать это в сортировке, используя разыменование полей.


УПОРЯДОЧИТЬ ПО 
    Номенклатура.Родитель.Наименование, 
    Номенклатура.Наименование

Если уровень вложенности папок большой, такой подход тоже может быть не идеален. В этом случае правильнее использовать механизмы СКД или специализированные алгоритмы с левым соединением справочника самого с собой, но для простых задач сортировки по "основной папке" вышеуказанного кода обычно достаточно.

Проблема 2: Опасность метода Загрузить()

Использование метода Объект.Товары.Загрузить(Товар) — это "мина замедленного действия". Рассмотрим почему:

  1. При обновлении конфигурации фирма 1С может добавить в табличную часть "Товары" новые реквизиты (например, "КодМаркировки", "ИдентификаторСтроки", "СтатусПроверки").
  2. В вашем запросе эти новые поля отсутствуют (вы их не выбирали).
  3. Метод Загрузить() полностью очищает текущую таблицу и заполняет её данными из вашей таблицы значений.
  4. В итоге: новые важные реквизиты будут очищены (обнулены), что приведет к ошибкам в учете или обмене данными.

Правильный подход: Вместо полной перезагрузки данных, мы должны менять порядок строк в существующей таблице или сортировать таблицу значений и загружать её только если мы контролируем все поля (например, во временной структуре).

Безопасный алгоритм сортировки строк

Давайте реализуем безопасный механизм сортировки. Мы не будем перезаписывать данные, мы просто поменяем их порядок с помощью индексов или метода Сдвинуть, либо воспользуемся сортировкой таблицы значений с последующим сопоставлением.

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

Рассмотрим вариант с сортировкой через служебную таблицу значений:


&НаСервере
Процедура СортироватьТоварыНаСервере()
    
    // 1. Выгружаем табличную часть в Таблицу Значений
    ТаблицаТоваров = Объект.Товары.Выгрузить();
    
    // 2. Добавляем колонки, которых нет в ТЧ, но нужны для сортировки
    ТаблицаТоваров.Колонки.Добавить("НаименованиеРодителя", Новый ОписаниеТипов("Строка"));
    
    // 3. Заполняем данные для сортировки
    // Для оптимизации лучше сделать это одним запросом к базе, передав массив номенклатуры
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Номенклатура,
        |   Номенклатура.Родитель.Наименование КАК НаименованиеРодителя
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.Ссылка В (&МассивНоменклатуры)";
        
    МассивНоменклатуры = ТаблицаТоваров.ВыгрузитьКолонку("Номенклатура");
    Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        НайденныеСтроки = ТаблицаТоваров.НайтиСтроки(Новый Структура("Номенклатура", Выборка.Номенклатура));
        Для Каждого СтрокаТЗ Из НайденныеСтроки Цикл
            СтрокаТЗ.НаименованиеРодителя = Выборка.НаименованиеРодителя;
        КонецЦикла;
    КонецЦикла;
    
    // 4. Сортируем таблицу значений
    ТаблицаТоваров.Сортировать("НаименованиеРодителя, Номенклатура");
    
    // 5. Загружаем обратно. 
    // ВАЖНО: Метод Загрузить здесь безопасен ТОЛЬКО если ТаблицаТоваров была получена методом Выгрузить() из ТОЙ ЖЕ ТЧ
    // и мы не удаляли колонки.
    Объект.Товары.Загрузить(ТаблицаТоваров);
    
КонецПроцедуры

Альтернативное решение: Сортировка в печатной форме

Часто менять порядок строк в самом документе нецелесообразно. Менеджеры привыкли видеть товары в хронологическом порядке добавления. Сортировка по иерархии нужна в основном кладовщикам для удобства сбора заказа.

В этом случае наиболее профессиональным решением будет оставить порядок строк в документе без изменений, а сортировку применить только при формировании печатной формы или в рабочем месте кладовщика.

Если же цель сортировки — упростить набор на складе, стоит обратить внимание на механизм ячеистого хранения. В современных конфигурациях (УТ 11, ERP) система сама выстраивает маршрут сборщика по ячейкам ("змейкой"), игнорируя иерархию папок номенклатуры, так как товары из одной группы могут физически лежать в разных концах склада.

← На главную