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

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

В практике разработчика 1С часто возникает задача: пользователь открывает список документов (например, «Заказы покупателей»), накладывает сложные фильтры по организации, периоду или контрагенту, а затем хочет выполнить групповое действие над результатом. Самый типичный пример — проведение всех документов, попавших в текущий список. В обычных формах (1С 8.2 и 8.3 в режиме обычного приложения) это решается не так прямолинейно, как в управляемых формах, где есть ЭтаФорма.Список.КомпоновщикНастроек. Рассмотрим, как эффективно справиться с этой задачей.

Метод 1: Использование Построителя Запроса

Наиболее правильным и надежным способом получения данных из динамического списка с учетом отборов является использование объекта ПостроительЗапроса. Этот объект позволяет динамически формировать текст запроса, накладывая условия, идентичные тем, что видит пользователь на экране. Разберем этот механизм по шагам.

Проанализируем ситуацию: в обычной форме список документов базируется на объекте типа ДокументСписок. У этого объекта есть свойство Отбор. Наша задача — перенести настройки из этого отбора в ПостроительЗапроса.

Рассмотрим пример кода, который можно разместить в обработчике нажатия кнопки на форме списка:


// Создаем новый построитель запроса
Построитель = Новый ПостроительЗапроса;

// Задаем базовый текст запроса. 
// Важно использовать конструкцию {ГДЕ ...}, чтобы построитель знал, куда подставлять отборы.
Построитель.Текст = 
"ВЫБРАТЬ
|	ЗаказПокупателя.Ссылка КАК Ссылка
|ИЗ
|	Документ.ЗаказПокупателя КАК ЗаказПокупателя
|{ГДЕ
|	ЗаказПокупателя.Ссылка.*,
|	ЗаказПокупателя.Организация.*,
|	ЗаказПокупателя.Контрагент.*,
|	ЗаказПокупателя.Дата,
|	ЗаказПокупателя.Проведен}";

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

// Выполняем запрос
Построитель.Выполнить();
РезультатТаблица = Построитель.Результат.Выгрузить();

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

Важные нюансы использования Построителя Запроса

Разберем подробнее, почему в коде выше мы использовали проверку Использование. Пользователь может настроить десятки фильтров, но в текущий момент времени активировать только один. Если мы просто скопируем все значения, ПостроительЗапроса применит даже пустые условия, что приведет к пустому результату или ошибке.

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

Метод 2: Работа с выделенными строками

Выясним причину, почему иногда метод с ПостроительЗапроса может быть избыточным. Если задача стоит так: «провести только те документы, которые я сейчас выделил в списке», то нам вообще не нужно анализировать отборы. Мы можем обратиться к коллекции выделенных строк элемента управления.

Посмотрим на пример реализации:


// Элемент списка в обычной форме — это обычно ТабличноеПоле
Для Каждого СсылкаНаДокумент Из ЭлементыФормы.Список.ВыделенныеСтроки Цикл
    // ВыделенныеСтроки возвращают непосредственно ссылки на объекты
    Если ТипЗнч(СсылкаНаДокумент) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
        // Выполняем действия
    КонецЕсли;
КонецЦикла;

Этот способ идеален, если пользователь хочет обработать 5-10 конкретных документов из 100 отфильтрованных. Однако, если документов тысячи, ручное выделение становится неудобным.

Почему нельзя использовать «ПриВыводеСтроки» для получения списка

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

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

Альтернатива: Построитель Отчета

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

Использование СКД в обычных формах

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

  1. Создаем временную схему компоновки данных.
  2. В качестве источника указываем таблицу документов.
  3. Переносим настройки из Список.Отбор в КомпоновщикНастроек.Настройки.Отбор СКД.
  4. Выполняем компоновку и получаем результат в таблицу значений.

Этот путь более трудозатратный, но он гарантирует 100% идентичность отборов, так как современные механизмы фильтрации в списках 1С построены на тех же алгоритмах, что и СКД.

Заключение и рекомендации

Подводя итог, можно сказать: если вам нужно получить весь список документов, который видит пользователь после фильтрации, используйте ПостроительЗапроса. Не забывайте проверять свойство Использование у каждого элемента отбора и корректно обрабатывать виды сравнения (такие как «В списке», «В иерархии», «Между»).

Для массового проведения документов всегда добавляйте обработку ошибок через блок Попытка...Исключение, так как один заблокированный документ не должен прерывать обработку всей остальной выборки.

← На главную