Как отсортировать СправочникСписок по товарам из другого списка значений (остаткам)

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

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

Анализ проблемы: ограничения объекта СправочникСписок

Для начала разберем, почему задача не решается «в лоб». Объект СправочникСписок в обычных формах напрямую связан с таблицей базы данных. Его основная функция — обеспечивать быстрый просмотр данных за счет динамического считывания строк. Сортировка в таком объекте возможна только по тем полям, которые:

  1. Физически существуют в таблице справочника в базе данных.
  2. Имеют установленное свойство «Индексировать».

Поскольку данные об остатках или информация из вашего СписокЗначений (или ТаблицаЗначений) хранятся в оперативной памяти или в других таблицах (регистрах), СправочникСписок просто «не видит» их в контексте сортировки. Даже если мы добавим колонку в табличное поле на форме, она будет расчетной, и попытка сортировки по ней стандартными средствами платформы не приведет к успеху. Давайте проанализируем доступные альтернативы.

Решение №1: Использование Таблицы Значений вместо списка

Это самый надежный и гибкий способ для обычных форм. Суть заключается в том, чтобы отказаться от прямой привязки к объекту СправочникСписок и использовать обычное табличное поле с типом значения ТаблицаЗначений.

Рассмотрим пошагово, как это реализовать:

  1. Разместим на форме табличное поле и установим ему тип значения ТаблицаЗначений.
  2. Сформируем запрос, который объединит данные справочника и данные об остатках (или приоритетный список).
  3. Выгрузим результат запроса в таблицу значений и свяжем её с табличным полем.

Посмотрим на пример кода, который формирует такую таблицу с учетом сортировки:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Товары.Ссылка КАК Ссылка,
    |	Товары.Код КАК Код,
    |	Товары.Наименование КАК Наименование,
    |	ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииОстаток, 0) КАК Остаток,
    |	ВЫБОР
    |		КОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииОстаток, 0) > 0 ТОГДА 0
    |		ИНАЧЕ 1
    |	КОНЕЦ КАК ПорядокСортировки
    |ИЗ
    |	Справочник.Номенклатура КАК Товары
    |		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК ТоварыНаСкладахОстатки
    |		ПО Товары.Ссылка = ТоварыНаСкладахОстатки.Номенклатура
    |ГДЕ
    |	Товары.ЭтоГруппа = ЛОЖЬ
    |УПОРЯДОЧИТЬ ПО
    |	ПорядокСортировки,
    |	Наименование";

Запрос.УстановитьПараметр("Период", ТекущаяДата());
ТаблицаРезультат = Запрос.Выполнить().Выгрузить();

// Привязываем результат к табличному полю на форме
ЭлементыФормы.ТабличноеПолеТовары.Значение = ТаблицаРезультат;
ЭлементыФормы.ТабличноеПолеТовары.СоздатьКолонки();

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

Недостатки: Нам придется вручную реализовывать стандартные функции: открытие формы элемента, иерархию, поиск и кнопки управления (создание, копирование).

Решение №2: Использование Построителя Отчета

Если нам нужно сохранить функциональность динамического списка (сортировки пользователем, отборы), но при этом добавить данные из других таблиц, проанализируем возможности объекта ПостроительОтчета. В обычных формах его часто использовали как «движок» для отображения списков.

Выясним, как это работает:

  1. Создаем объект ПостроительОтчета.
  2. Передаем ему текст запроса, аналогичный приведенному выше.
  3. В качестве источника данных для табличного поля указываем ПостроительОтчета.Результат или выводим данные напрямую.

Построитель позволяет пользователю интерактивно менять порядок сортировки, и при этом он умеет работать с виртуальными таблицами остатков в реальном времени. Это более продвинутый вариант, чем простая таблица значений.

Решение №3: Технический реквизит «Порядок»

Если справочник небольшой, а требования к производительности позволяют периодическую запись в базу, разберем метод с техническим реквизитом. Мы можем добавить в справочник Номенклатура реквизит ПорядокСортировки (тип Число), проиндексировать его и обновлять перед открытием формы.

Проанализируем алгоритм:


// Процедура обновления признака наличия для сортировки
Для Каждого СтрокаТЗ Из ТаблицаСВычисленнымиОстатками Цикл
    ОбъектТовар = СтрокаТЗ.Товар.ПолучитьОбъект();
    ОбъектТовар.ПорядокСортировки = ?(СтрокаТЗ.ВНаличии, 0, 1);
    ОбъектТовар.Записать();
КонецЦикла;

// После обновления устанавливаем сортировку в СправочникСписок
СправочникСписок.Порядок.Установить("ПорядокСортировки Возр, Наименование Возр");

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

Решение №4: Визуальная эмуляция через два списка

Рассмотрим ситуацию, когда товаров с остатками (которые должны быть первыми) относительно немного. Мы можем пойти на хитрость и разделить экран на две части:

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

Резюме

Подведем итог. В рамках стандартного объекта СправочникСписок на обычных формах задача сортировки по внешним данным не имеет прямого решения. Чтобы добиться желаемого результата, мы должны выбрать один из обходных путей:

  1. Перейти на использование ТаблицыЗначений, если важна гибкость и справочник не слишком велик.
  2. Использовать ПостроительОтчета для сохранения динамики.
  3. Применить Динамический список, если ваша версия платформы (поздние релизы 8.2 или 8.3) позволяет разместить этот элемент управления на обычной форме.

Наиболее профессиональным и стабильным решением для обычных форм остается использование запроса с левым соединением и выводом данных в таблицу значений или построитель.

← На главную