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

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

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

Выбор оптимального места для размещения программного кода

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

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

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

Реализация через запрос и метод Загрузить()

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

Проанализируем пример кода, который необходимо разместить в модуле объекта документа:


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

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

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

Тонкости фильтрации элементов: Активные и Неактивные

Часто в справочниках хранятся как актуальные записи, так и архивные. Выясним, как исключить «лишние» строки из заполнения. В запросе выше мы уже добавили условие НЕ ПометкаУдаления и НЕ ЭтоГруппа. Если этого не сделать, в документ могут попасть удаленные элементы или группы (папки), что приведет к логическим ошибкам при проведении.

Если справочник иерархический и активные участники лежат в определенной папке, мы можем уточнить запрос, используя конструкцию В ИЕРАРХИИ:


// Предположим, у нас есть ссылка на папку "Активные"
Запрос.УстановитьПараметр("ПапкаАктивные", СсылкаНаПапку);
Запрос.Текст = 
	"ВЫБРАТЬ
	|	Участники.Ссылка КАК Участник
	|ИЗ
	|	Справочник.Участники КАК Участники
	|ГДЕ
	|	Участники.Ссылка В ИЕРАРХИИ(&ПапкаАктивные)
	|	И НЕ Участники.ЭтоГруппа";

Альтернативный метод: Обход выборкой

Хотя метод Загрузить() очень быстр, иногда нам требуется более сложная логика — например, рассчитать какое-то значение для каждой строки «на лету» или проверить дополнительные условия, которые сложно описать в запросе. В таких случаях рассмотрим использование цикла Для каждого или обход выборки.


Выборка = РезультатЗапроса.Выбрать();

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

Метод Добавить() работает медленнее, чем Загрузить(), при больших объемах данных (тысячи строк), но он гораздо гибче.

Работа с типовыми конфигурациями и расширениями

Если вы работаете в современной типовой конфигурации (например, БП 3.0 или УТ 11), крайне не рекомендуется вносить изменения напрямую в модуль объекта. Для реализации нашей задачи лучше всего использовать Расширение конфигурации.

Посмотрим на алгоритм действий в этом случае:

  1. Создайте новое расширение и добавьте в него ваш документ.
  2. В модуле объекта документа в расширении создайте метод с директивой &После("ОбработкаЗаполнения").
  3. Вставьте туда код заполнения. Это позволит основной конфигурации выполнить свои стандартные проверки, а затем добавит вашу логику заполнения участников.

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

Добавление сервисной команды «Заполнить»

Проанализируем ситуацию: пользователь создал документ, но спустя час в справочник добавились новые участники. Чтобы не пересоздавать документ заново, полезно добавить кнопку «Заполнить участниками» непосредственно на форму документа, над табличной частью.

Для этого:

  1. В модуле объекта создадим экспортную процедуру ЗаполнитьУчастников(), куда вынесем логику запроса.
  2. В ОбработкаЗаполнения будем просто вызывать эту процедуру.
  3. На форме создадим команду, которая на сервере также будет вызывать ЭтотОбъект.ЗаполнитьУчастников().

Такой подход делает код чистым (отсутствие дублирования) и дает пользователю удобный инструмент для актуализации данных в документе.

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

← На главную