Мы часто сталкиваемся с задачей упорядочивания данных в табличных частях документов таким образом, чтобы это было удобно для работы. Один из распространенных сценариев – сортировка строк по иерархии справочника, например, чтобы товары в документе следовали порядку их расположения на складе. Давайте разберем, как эффективно решить эту проблему на примере документа "Реализация товаров и услуг" и его табличной части "Товары" в конфигурации 1С:Управление торговлей 11.5.
Предположим, у нас есть код, который пытается отсортировать табличную часть документа:
&НаСервере
Процедура Сортировка()
Этотобъект.Записать(); // Важно: сохраняем документ перед выполнением запроса
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслугТовары.Ссылка КАК Ссылка,
| РеализацияТоваровУслугТовары.НомерСтроки КАК НомерСтроки,
| РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура,
| РеализацияТоваровУслугТовары.Характеристика КАК Характеристика,
| РеализацияТоваровУслугТовары.Назначение КАК Назначение,
| // ... (другие поля табличной части)
| РеализацияТоваровУслугТовары.СуммаНачисленныхБонусныхБалловВВалюте КАК СуммаНачисленныхБонусныхБалловВВалюте
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
| РеализацияТоваровУслугТовары.Ссылка = &Ссылка
|
|УПОРЯДОЧИТЬ ПО
|Номенклатура ИЕРАРХИЯ";
Результат = Запрос.Выполнить();
Товар = Результат.Выгрузить();
Объект.Товары.Загрузить(Товар);
КонецПроцедуры
Давайте внимательно рассмотрим строку УПОРЯДОЧИТЬ ПО Номенклатура ИЕРАРХИЯ. На первый взгляд кажется, что это именно то, что нам нужно. Однако, на практике такой подход сортирует строки не по визуальному положению элементов в иерархии справочника, а по внутреннему представлению ссылки на элемент номенклатуры. Это означает, что группы и элементы будут упорядочены по их уникальным идентификаторам, что редко совпадает с желаемым логическим или алфавитным порядком в иерархии.
Чтобы добиться истинной иерархической сортировки, которая учитывает порядок групп и элементов так, как мы их видим в справочнике (например, по наименованию), нам необходимо указать поле наименования справочника в условии упорядочивания. Таким образом, запрос будет сортировать по наименованию, следуя иерархической структуре.
Предлагаем следующее корректирующее решение для запроса:
&НаСервере
Процедура Сортировка()
Этотобъект.Записать(); // Сохраняем документ
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслугТовары.* // Выбираем все поля табличной части
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
| РеализацияТоваровУслугТовары.Ссылка = &Ссылка
|
|УПОРЯДОЧИТЬ ПО
|РеализацияТоваровУслугТовары.Номенклатура.Наименование ИЕРАРХИЯ";
Результат = Запрос.Выполнить();
// Получаем ТаблицуЗначений из результата запроса
ТаблицаТоваров = Результат.Выгрузить();
// Загружаем отсортированные данные обратно в табличную часть
Объект.Товары.Загрузить(ТаблицаТоваров);
КонецПроцедуры
Обратите внимание на ключевое изменение: УПОРЯДОЧИТЬ ПО РеализацияТоваровУслугТовары.Номенклатура.Наименование ИЕРАРХИЯ. Теперь система будет использовать наименование номенклатуры для построения иерархического порядка, что соответствует нашим ожиданиям, например, для удобства сборки товаров на складе.
Мы также изменили выбор полей на РеализацияТоваровУслугТовары.*. Это очень важный момент. Использование символа * позволяет выбрать все существующие реквизиты табличной части документа. Если в будущем в конфигурацию будут добавлены новые реквизиты в табличную часть "Товары", наш запрос автоматически включит их в выборку. В противном случае, если мы явно перечислим поля, а затем добавим новые, эти новые поля могут быть обнулены или потеряны при обратной загрузке данных методом Загрузить(). Хотя ваш исходный запрос перечислял почти все поля, использование * делает код более устойчивым к изменениям конфигурации.
Методы, которые мы используем здесь:
Новый Запрос: Создание нового объекта запроса.Запрос.УстановитьПараметр(): Установка значений для параметров запроса.Запрос.Выполнить(): Выполнение запроса и получение объекта РезультатЗапроса.РезультатЗапроса.Выгрузить(): Выгрузка данных из результата запроса в объект ТаблицаЗначений.Объект.Товары.Загрузить(): Загрузка данных из ТаблицыЗначений обратно в табличную часть документа.Представим ситуацию, когда иерархия справочника "Номенклатура" не всегда идеально соответствует физическому расположению товаров на складе, или нам требуется более сложный, нестандартный порядок обхода. В этом случае мы можем использовать дополнительный реквизит справочника "Номенклатура" для управления порядком сортировки.
Рассмотрим по шагам, как реализовать этот подход:
Номенклатура, например, с именем ПорядокНаСкладе. Этот реквизит может быть числового типа, строкового или даже ссылочного, в зависимости от сложности нашей логики сортировки. Например, для простой нумерации подойдет числовой тип.УПОРЯДОЧИТЬ ПО нашего запроса.Посмотрим на пример модификации запроса с использованием дополнительного реквизита:
&НаСервере
Процедура СортировкаПоПорядкуНаСкладе()
Этотобъект.Записать(); // Сохраняем документ
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслугТовары.*,
| РеализацияТоваровУслугТовары.Номенклатура.ПорядокНаСкладе КАК ПорядокНаСкладе // Выбираем новый реквизит
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
| РеализацияТоваровУслугТовары.Ссылка = &Ссылка
|
|УПОРЯДОЧИТЬ ПО
|ПорядокНаСкладе,
|РеализацияТоваровУслугТовары.Номенклатура.Наименование ИЕРАРХИЯ"; // Дополнительная сортировка по наименованию
// внутри одного значения ПорядокНаСкладе
Результат = Запрос.Выполнить();
ТаблицаТоваров = Результат.Выгрузить();
Объект.Товары.Загрузить(ТаблицаТоваров);
КонецПроцедуры
В этом примере мы сначала сортируем по нашему кастомному полю ПорядокНаСкладе, а затем, для элементов с одинаковым значением этого поля, используем иерархическую сортировку по наименованию. Это дает нам очень гибкий инструмент для управления порядком строк.
Также мы можем реализовать сортировку на стороне клиента, если нам нужно больше гибкости или если данные уже находятся в ТаблицеЗначений. Для этого мы сначала выгружаем табличную часть в ТаблицуЗначений, добавляем в нее колонку для сортировки, заполняем эту колонку значениями из соответствующего реквизита номенклатуры (полученными, например, через запрос или обходом), затем используем метод ТаблицаЗначений.Сортировать() и только потом загружаем данные обратно в табличную часть документа. Однако, для простых случаев, сортировка непосредственно в запросе является более производительным и рекомендуемым подходом.
Важно понимать, что существуют и пользовательские способы сортировки табличных частей в 1С. Например, пользователи могут щелкнуть по заголовку колонки в форме документа, чтобы отсортировать данные, или использовать меню "Еще" - "Настроить список" для более сложной настройки порядка. Однако эти методы являются интерактивными и не обеспечивают автоматическую программную сортировку, которая нам нужна для оптимизации процессов, таких как сборка товаров на складе.
Не забывайте о строке Этотобъект.Записать(); в начале процедуры. Если вы вносите какие-либо изменения в документ до выполнения сортировки (например, добавляете новые строки или меняете существующие), обязательно сохраните документ перед тем, как выполнять запрос. Запрос всегда работает с данными, которые были записаны в базу данных, а не с данными, которые находятся только в оперативной памяти формы.
В итоге, для большинства задач, связанных с иерархической сортировкой табличной части по справочнику, наиболее эффективным и надежным решением является изменение запроса с УПОРЯДОЧИТЬ ПО Номенклатура ИЕРАРХИЯ на УПОРЯДОЧИТЬ ПО Номенклатура.Наименование ИЕРАРХИЯ. Если же требуется более сложная логика, использование дополнительного реквизита в справочнике и его включение в условие сортировки запроса предоставит необходимую гибкость.