При работе в конфигурациях 1С (таких как «Управление производственным предприятием», «Бухгалтерия предприятия» и др.) часто возникает задача автоматического заполнения реквизитов при создании нового документа. Например, при оформлении актов списания или требований-накладных необходимо, чтобы поле Утверждающий (имеющее тип ссылки на справочник физических лиц) автоматически заполнялось ФИО действующего Главного инженера организации.
В этой статье мы подробно разберем, как решить эту задачу, проанализируем различные архитектурные подходы (для обычных и управляемых форм) и выясним, как сделать автозаполнение надежным и удобным для поддержки.
Рассмотрим классический вариант для обычных форм. Нам необходимо получить срез последних из регистра сведений ОтветственныеЛицаОрганизаций по ответственному лицу «Главный инженер» на дату документа и для выбранной организации.
Важный нюанс: Автозаполнение должно отрабатывать строго для новых документов. Если выполнять этот код при открытии уже существующего (ранее сохраненного) документа, программа перезапишет исторические данные актуальным на текущий момент инженером, что приведет к искажению учета. Поэтому весь код инициализации мы помещаем внутрь условия Если ЭтоНовый() Тогда.
Разберем по шагам код обработчика события ПриОткрытии в модуле формы документа:
Процедура ПриОткрытии()
// [Стандартный типовой код инициализации формы]
Если ЭтоНовый Тогда
ЗаполнениеДокументов.ЗаполнитьШапкуДокумента(ЭтотОбъект, глТекущийПользователь);
ОбщегоНазначения.УстановитьНомерДокумента(ЭтотОбъект);
УстановитьОперациюПоУмолчанию;
ЗаполнениеДокументов.ЗаполнитьРеквизитыДокумента(ЭтотОбъект, глТекущийПользователь, , Организация);
Если ЗначениеЗаполнено(ПодразделениеОрганизации) Тогда
ПриИзмененииПодразделения;
КонецЕсли;
НомерАктаДляПечати = ЗаполнениеДокументов.ПолучитьНомерНаПечать(ЭтотОбъект);
// НАШ КОД АВТОЗАПОЛНЕНИЯ:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОтветственныеЛицаОрганизацийСрезПоследних.ФизическоеЛицо КАК ФизическоеЛицо
|ИЗ
| РегистрСведений.ОтветственныеЛицаОрганизаций.СрезПоследних(
| &Дата,
| СтруктурнаяЕдиница = &Организация
| И ОтветственноеЛицо = ЗНАЧЕНИЕ(Перечисление.ОтветственныеЛицаОрганизаций.ГлавныйИнженер)
| ) КАК ОтветственныеЛицаОрганизацийСрезПоследних";
Запрос.УстановитьПараметр("Дата", Дата);
Запрос.УстановитьПараметр("Организация", Организация);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Утверждающий = Выборка.ФизическоеЛицо;
КонецЕсли;
Иначе
Если НЕ Операция.Пустая() Тогда
ЭлементыФормы.ДействияФормы.Кнопки.ПодменюОперации.Текст = Строка(Операция);
КонецЕсли;
КонецЕсли;
// [Прочий типовой код настройки видимости элементов...]
КонецПроцедуры
Если вы работаете в управляемом интерфейсе, стандартной процедуры ПриОткрытии может не быть на форме. Вся логика инициализации обычно переносится в событие ПриСозданииНаСервере.
Чтобы не «курочить» типовой код и сделать доработку максимально изолированной (что упростит последующие обновления системы), можно воспользоваться механизмом переопределения действий. Для этого в самый конец модуля формы вставляется специальная область:
#Область МоиИзменения
&НаСервере
Процедура моя_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Выполняем типовой предопределенный обработчик
ПриСозданииНаСервере(Отказ, СтандартнаяОбработка);
// Переопределяем поведение при изменении организации на форме
Элементы.Организация.УстановитьДействие("ПриИзменении", "моя_ОрганизацияПриИзменении");
моя_ОрганизацияПриИзмененииНаСервере();
КонецПроцедуры
&НаКлиенте
Процедура моя_ОрганизацияПриИзменении(Элемент)
// Выполняем базовый типовой обработчик
ОрганизацияПриИзменении(Элемент);
// Вызываем заполнение инженера под новую организацию
моя_ОрганизацияПриИзмененииНаСервере();
КонецПроцедуры
&НаСервере
Процедура моя_ОрганизацияПриИзмененииНаСервере()
// Запрос получения главного инженера на основе текущей организации и даты документа
Запрос = Новый Запрос;
Запрос.Tекст =
"ВЫБРАТЬ
| ОтветственныеЛицаОрганизацийСрезПоследних.ФизическоеЛицо КАК ФизическоеЛицо
|ИЗ
| РегистрСведений.ОтветственныеЛицаОрганизаций.СрезПоследних(
| &Дата,
| СтруктурнаяЕдиница = &Организация
| И ОтветственноеЛицо = ЗНАЧЕНИЕ(Перечисление.ОтветственныеЛицаОрганизаций.ГлавныйИнженер)
| ) КАК ОтветственныеЛицаОрганизацийСрезПоследних";
Запрос.УстановитьПараметр("Дата", Объект.Дата);
Запрос.УстановитьПараметр("Организация", Объект.Организация);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Объект.Утверждающий = Выборка.ФизическоеЛицо;
КонецЕсли;
КонецПроцедуры
// Переопределяем стандартный обработчик создания формы
&НаСервере
Процедура моя_ПереопределениеДействийФормы()
УстановитьДействие("ПриСозданииНаСервере", "моя_ПриСозданииНаСервере");
КонецПроцедуры
// Вызов инициализации при загрузке модуля формы
моя_ПереопределениеДействийФормы();
#КонецОбласти
Хотя методы, описанные выше, полностью работоспособны, размещение логики автозаполнения в модуле формы считается плохой практикой (антипаттерном) в профессиональной разработке на платформе «1С:Предприятие 8».
Почему код в форме — это плохо? Если документ будет создаваться программно (например, при импорте данных из внешних систем, загрузке из Excel, через веб-сервисы или в фоновом задании), форма документа вообще не будет открываться. Соответственно, реквизит Утверждающий останется пустым.
Для правильной инициализации новых объектов существует стандартное событие ОбработкаЗаполнения, расположенное в Модуле объекта документа. Оно гарантированно срабатывает как при интерактивном создании документа пользователем в интерфейсе, так и при программном создании в коде.
Дополнительно, чтобы не писать громоздкие запросы к срезу последних вручную, мы можем использовать готовые функции общих модулей, которые уже есть в любой типовой конфигурации.
Проанализируем пример реализации в Модуле объекта вашего документа:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстоваяСтрока, СтандартнаяОбработка)
// Вызываем стандартное заполнение реквизитов (например, по умолчанию)
// ...
// Получаем главного инженера через стандартные функции общих модулей
// Вариант А: Для конфигураций на базе УПП / КА 1.1:
Если ЗначениеЗаполнено(Организация) Тогда
Утверждающий = ОбщегоНазначения.ОтветственноеЛицоОрганизации(
Организация,
Перечисления.ОтветственныеЛицаОрганизаций.ГлавныйИнженер,
Дата
);
КонецЕсли;
// Вариант Б: Для конфигураций на базе БП 3.0 / ERP / КА 2:
// Если ЗначениеЗаполнено(Организация) Тогда
// Утверждающий = ОтветственныеЛицаБП.ПолучитьФизическоеЛицо(
// Организация,
// "ГлавныйИнженер",
// Дата
// );
// КонецЕсли;
КонецПроцедуры
Использование методов общих модулей (ОбщегоНазначения или ОтветственныеЛицаБП) гарантирует оптимальное выполнение запроса к базе данных и защищает ваш код от сбоев при обновлении конфигурации.
В процессе работы часто возникает дополнительный вопрос: как автоматически заполнять в документах списания номер и дату приказа о назначении инвентаризационной комиссии (например, «Приказ № 184 от 24.09.2018»)?
В современных конфигурациях 1С для этих целей предусмотрен типовой Справочник «Комиссии» (или аналогичный регистр сведений).
Мы рекомендуем использовать следующую схему автоматизации:
Комиссия со ссылкой на справочник комиссий.