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

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

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

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

Анализ исходного кода и распространенных ошибок

Рассмотрим первоначальный вариант функции, с которым обратился автор темы:


Функция НезаполненныеДокументы() Экспорт
    Массив = Новый Массив; 
    Запрос = Новый Запрос; 
    Запрос.Текст = "ВЫБРАТЬ 
    | Поступлениетоваров.Поставщик, 
    | Поступлениетоваров.Дата, 
    | Поступлениетоваров.Номер, 
    | Поступлениетоваров.Ссылка 
    |ИЗ 
    | Документ.Поступлениетоваров КАК Поступлениетоваров 
    |ГДЕ 
    | Поступлениетоваров.Поставщик = &ПустаяСсылка"; 

    ПустаяСсылка = Справочники.Контрагенты.ПустаяСсылка(); 
    Запрос.УстановитьПараметр("ПустаяСсылка", ПустаяСсылка); 

    РезультатЗапроса = Запрос.Выполнить(); 
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выгрузить(); 
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл 
        Массив.Добавить(ВыборкаДетальныеЗаписи.Ссылка); 
    КонецЦикла; 

    Возврат Массив;
КонецФункции

Разберем основные недочеты и ошибки в данном подходе:

  1. Избыточность выбираемых полей в запросе. В секции ВЫБРАТЬ запрашиваются поля Поставщик, Дата, Номер и Ссылка. Однако в коде используется исключительно реквизит Ссылка. Выборка ненужных полей увеличивает нагрузку на СУБД, повышает объем передаваемых данных по сети и замедляет выполнение кода.
  2. Передача пустой ссылки через параметр. Для проверки реквизита на незаполненность необязательно получать пустую ссылку в коде BSL через Справочники.Контрагенты.ПустаяСсылка() и передавать ее в параметры запроса. В языке запросов 1С предусмотрена конструкция ЗНАЧЕНИЕ(...).
  3. Обход выборки в цикле вручную. Обход таблицы значений или выборки запроса через цикл для заполнения массива — избыточная операция, увеличивающая объем кода. Для выгрузки значений одной колонки у таблицы значений существует встроенный метод ВыгрузитьКолонку().
  4. Синтаксические ошибки. В последующих сообщениях темы при попытке объединить код был случайно оставлен оператор КонецЦикла; без открывающей конструкции Пока ... Цикл, что приводит к ошибке компиляции.
  5. Использование вызовов интерфейса на сервере. Вызов функции Сообщить() внутри серверных функций обработки данных противоречит стандартам разработки 1С. Вывод сообщений пользователю должен выполняться на клиентской стороне.

Оптимизированное решение задачи

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

Разберем по шагам итоговую серверную функцию:


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

Эту функцию можно сократить до лаконичной записи без потери читаемости:


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

Обратите внимание: проверка Пустой() перед выгрузкой не требуется. Если запрос ничего не найдет, метод ВыгрузитьКолонку() вернет пустой массив, а ЗагрузитьЗначения() корректно обработает его без возникновения ошибок.

Альтернативные способы решения на управляемых формах

Если задача заключается в том, чтобы просто показать пользователю во внешней обработке документы с незаполненным поставщиком, ручное написание запросов и выгрузка их в СписокЗначений — не единственный и не всегда самый эффективный способ.

Вариант 1. Использование Динамического списка (без написания BSL-кода)

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

Выполним следующую последовательность действий:

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

Если требуется установить отбор программно при создании формы на сервере, используется следующий код:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ЭлементОтбора = СписокНезаполненных.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Поставщик");
	ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.НеЗаполнено;
	ЭлементОтбора.Использование = Истина;
	
КонецПроцедуры

Вариант 2. Связывание СпискаЗначений с реквизитом формы

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

  1. Создадим реквизит формы СписокДокументовФормы с типом СписокЗначений.
  2. В свойствах реквизита в поле Тип ценностей списка укажем тип: ДокументСсылка.ПоступлениеТоваров.
  3. Вынесем реквизит на форму как элемент управления (Поле списка или Таблица).
  4. Напишем обработчик команды (например, нажатие кнопки "Обновить"):

&НаКлиенте
Процедура ОбновитьСписок(Команда)
	
	СписокДокументовФормы = ПолучитьНезаполненныеДокументы();
	
	Если СписокДокументовФормы.Количество() = 0 Тогда
		ПоказатьПредупреждение(, "Документы с незаполненным поставщиком не найдены.");
	КонецЕсли;
	
КонецПроцедуры

Стандарты и правила разработки 1С (BSL)

Проанализируем основные рекомендации стандартов 1С, которые следует соблюдать при решении подобных задач:

← На главную