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

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

В практике разработки на платформе 1С:Предприятие 8.3 (особенно при работе с обычными формами) часто возникает задача расширить стандартный список документов дополнительной информацией. Например, вывести статус из регистра сведений или данные из связанного бизнес-процесса. Если мы добавляем такую колонку программно и заполняем её "на лету", стандартный механизм отбора перестает работать. В этой статье мы подробно разберем, почему так происходит и какими способами можно решить эту задачу.

Почему стандартный отбор не видит программную колонку?

Для начала проанализируем ситуацию. Когда мы используем объект ДокументСписок в обычных формах, система работает напрямую с базой данных через SQL-запросы. Программное добавление колонки в ЭлементыФормы.Список.Колонки создает лишь визуальный элемент в интерфейсе. Рассмотрим типичный код добавления колонки, который часто используют разработчики:


Колонка = ЭлементыФормы.Список.Колонки.Найти(ПослеКолонкиИмя);
НомерКолонки = ЭлементыФормы.Список.Колонки.Индекс(Колонка);
НоваяКолонка = ЭлементыФормы.Список.Колонки.Вставить(НомерКолонки + 1, "Статус");
НоваяКолонка.Имя = "Статус";
НоваяКолонка.ТекстШапки = "Статус документа";

Далее разработчик обычно заполняет эту колонку в событии ПриВыводеСтроки или ПриПолученииДанных:


Процедура СписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    Запись = РегистрыСведений.СтатусыДокументов.Получить(Новый Структура("Документ", ДанныеСтроки.Ссылка));
    ОформлениеСтроки.Ячейки.Статус.УстановитьТекст(Запись.Статус);
КонецПроцедуры

Выясним причину проблемы: стандартный отбор 1С пытается найти поле "Статус" в таблице базы данных (SQL), но его там не существует. Оно существует только в памяти формы для тех 20-30 строк, которые видны на экране. Именно поэтому попытка включить НастройкаОтбора.Статус.Доступность = Истина либо вызывает ошибку "Поле объекта не обнаружено", либо приводит к пустому результату списка.

Решение №1: Программный фильтр по списку ссылок

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

Рассмотрим пошаговый алгоритм реализации этого метода:

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

Проанализируем пример кода для реализации такого отбора:


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

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

Важный нюанс: этот метод отлично работает, если количество документов, попадающих в фильтр, не превышает нескольких тысяч. Если же список ссылок будет слишком огромным, SQL-запрос может стать неоптимальным из-за слишком длинного условия IN (...).

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

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

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

Посмотрим на пример настройки такого подхода:


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

Построитель.ЗаполнитьНастройки();
// Теперь поле "Статус" доступно в Построитель.Отбор

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

Решение №3: Изменение метаданных (Оптимальный путь)

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

Рекомендуется следующий подход:

  1. Добавьте реальный реквизит "Статус" в метаданные документа.
  2. Настройте его заполнение при проведении или записи документа.
  3. Для существующих документов запустите обработку заполнения.

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

Резюме

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

Мы рассмотрели три пути решения:

Выбирайте метод, исходя из требований к производительности и гибкости вашей системы.

← На главную