В процессе разработки конфигураций на платформе 1С часто возникает задача автоматизации рутинного ввода данных. Типичный пример — создание ежедневного документа, где в табличную часть должны автоматически попадать все актуальные элементы определенного справочника (например, список участников, сотрудников или активных торговых точек). Рассмотрим подробно, как реализовать этот механизм правильно с точки зрения архитектуры 1С, обеспечив высокую производительность и удобство поддержки кода.
Первый вопрос, который возникает у начинающего разработчика: где именно прописать алгоритм заполнения? В обсуждении предлагались варианты использования модуля формы (процедура ПриСозданииНаСервере) и модуля объекта. Проанализируем эти подходы.
Если мы напишем код в модуле формы, заполнение будет срабатывать только тогда, когда пользователь открывает форму нового документа интерактивно. Однако в реальных бизнес-системах документы часто создаются программно: через обработки, регламентные задания или механизмы интеграции (API). В этих случаях форма не открывается, и ваш код просто не выполнится.
Правильное решение: использовать обработчик ОбработкаЗаполнения в модуле объекта документа. Этот метод вызывается платформой при создании нового объекта на основании другого объекта или просто при нажатии кнопки «Создать». Это гарантирует, что бизнес-логика заполнения сработает в любом сценарии.
Разберем самый быстрый и эффективный способ заполнения табличной части — использование метода Загрузить(). Этот метод позволяет мгновенно перенести данные из таблицы значений в табличную часть, если имена колонок совпадают.
Проанализируем пример кода, который необходимо разместить в модуле объекта документа:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Если документ создается не на основании чего-то, а просто новым
Если ДанныеЗаполнения = Неопределено Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Участники.Ссылка КАК Участник
|ИЗ
| Справочник.Участники КАК Участники
|ГДЕ
| НЕ Участники.ПометкаУдаления
| И НЕ Участники.ЭтоГруппа";
РезультатЗапроса = Запрос.Выполнить();
// Выгружаем результат запроса в таблицу значений
ТаблицаРезультата = РезультатЗапроса.Выгрузить();
// Загружаем таблицу в табличную часть документа
// Важно: имя колонки в запросе (Участник) должно совпадать с именем реквизита ТЧ
ЭтотОбъект.УчастникиСписок.Загрузить(ТаблицаРезультата);
КонецЕсли;
КонецПроцедуры
В данном примере мы используем псевдоним КАК Участник в тексте запроса. Это критически важный момент: метод Загрузить() сопоставляет данные именно по именам колонок. Если в вашей табличной части реквизит называется Субъект, то и в запросе поле должно называться так же.
Часто в справочниках хранятся как актуальные записи, так и архивные. Выясним, как исключить «лишние» строки из заполнения. В запросе выше мы уже добавили условие НЕ ПометкаУдаления и НЕ ЭтоГруппа. Если этого не сделать, в документ могут попасть удаленные элементы или группы (папки), что приведет к логическим ошибкам при проведении.
Если справочник иерархический и активные участники лежат в определенной папке, мы можем уточнить запрос, используя конструкцию В ИЕРАРХИИ:
// Предположим, у нас есть ссылка на папку "Активные"
Запрос.УстановитьПараметр("ПапкаАктивные", СсылкаНаПапку);
Запрос.Текст =
"ВЫБРАТЬ
| Участники.Ссылка КАК Участник
|ИЗ
| Справочник.Участники КАК Участники
|ГДЕ
| Участники.Ссылка В ИЕРАРХИИ(&ПапкаАктивные)
| И НЕ Участники.ЭтоГруппа";
Хотя метод Загрузить() очень быстр, иногда нам требуется более сложная логика — например, рассчитать какое-то значение для каждой строки «на лету» или проверить дополнительные условия, которые сложно описать в запросе. В таких случаях рассмотрим использование цикла Для каждого или обход выборки.
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = ЭтотОбъект.УчастникиСписок.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
// Здесь можно добавить произвольную логику
Если НоваяСтрока.Участник.ВидУчастника = Перечисления.Виды.VIP Тогда
НоваяСтрока.Статус = "Особое внимание";
КонецЕсли;
КонецЦикла;
Метод Добавить() работает медленнее, чем Загрузить(), при больших объемах данных (тысячи строк), но он гораздо гибче.
Если вы работаете в современной типовой конфигурации (например, БП 3.0 или УТ 11), крайне не рекомендуется вносить изменения напрямую в модуль объекта. Для реализации нашей задачи лучше всего использовать Расширение конфигурации.
Посмотрим на алгоритм действий в этом случае:
&После("ОбработкаЗаполнения").Это обеспечит легкость при обновлении основной конфигурации, так как ваши изменения будут изолированы.
Проанализируем ситуацию: пользователь создал документ, но спустя час в справочник добавились новые участники. Чтобы не пересоздавать документ заново, полезно добавить кнопку «Заполнить участниками» непосредственно на форму документа, над табличной частью.
Для этого:
ЗаполнитьУчастников(), куда вынесем логику запроса.ОбработкаЗаполнения будем просто вызывать эту процедуру.ЭтотОбъект.ЗаполнитьУчастников().Такой подход делает код чистым (отсутствие дублирования) и дает пользователю удобный инструмент для актуализации данных в документе.
Важный нюанс: при повторном заполнении по кнопке не забудьте решить, нужно ли очищать текущую табличную часть. Если нужно — используйте метод ЭтотОбъект.ИмяТЧ.Очистить() перед загрузкой новых данных.