Как реализовать поле со множественными значениями из табличной части для отбора в форме списка 1С:УПП

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

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

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

Метод 1: Использование вспомогательной табличной части

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

Шаги реализации:

  1. Добавим в документ ЗаказПоставщику новую табличную часть СпецификацииДляОтбора с одним реквизитом Спецификация (тип СправочникСсылка.СпецификацииНоменклатуры).
  2. В модуле объекта реализуем автоматическое заполнение этой таблицы. Посмотрим на пример кода в обработчике ПередЗаписью:

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

КонецПроцедуры

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

Метод 2: Строковый реквизит для визуализации и быстрого поиска

Рассмотрим, как вывести список спецификаций через запятую прямо в колонку списка. Для этого добавим в заголовок документа реквизит СписокСпецификацийСтрокой (тип Строка, длина неограничена или 250 символов).

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


// Продолжение процедуры ПередЗаписью
СтрокаДляПредставления = "";
Для Каждого Стр Из СпецификацииДляОтбора Цикл
    СтрокаДляПредставления = СтрокаДляПредставления + ?(ПустаяСтрока(СтрокаДляПредставления), "", ", ") + Строка(Стр.Спецификация);
КонецЦикла;

СписокСпецификацийСтрокой = СтрокаДляПредставления;

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

Метод 3: Реализация отбора в форме списка через программный фильтр

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

Рассмотрим алгоритм работы этого поля:

  1. Пользователь выбирает спецификацию в поле на форме.
  2. Программа выполняет запрос к нашей вспомогательной табличной части СпецификацииДляОтбора.
  3. Программа находит все ссылки на документы, где встречается эта спецификация.
  4. Массив найденных ссылок передается в стандартный отбор списка.

Посмотрим на пример программной реализации в обработчике события ПриИзменении поля выбора:


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

Метод 4: Использование механизма «Критерии отбора»

Проанализируем ситуацию, когда менять структуру документа (добавлять ТЧ) нежелательно. В 1С существует объект метаданных КритерииОтбора. Мы можем создать критерий ПоСпецификацииЗаказа.

Порядок действий:

  1. В дереве конфигурации находим ветку Общие -> Критерии отбора.
  2. Создаем новый критерий, указываем тип (ссылка на справочник спецификаций).
  3. На закладке «Состав» отмечаем реквизит Заказ в табличной части документа ЗаказПоставщику.

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

Оптимизация вывода данных: ПриПолученииДанных

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


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

Подведем итог: Для небольших баз и редкого использования подойдет динамический вывод через ПриПолученииДанных. Однако для крупных систем (каковой обычно является УПП) наиболее производительным решением будет комбинация Метода 1 (вспомогательная ТЧ) и Метода 2 (строковый реквизит). Это обеспечит мгновенную скорость отрисовки списка и возможность быстрого программного отбора по индексированным таблицам.

← На главную