В практике разработчика 1С часто возникает задача: необходимо выполнить логику, которая уже написана внутри формы существующего документа (например, расчет налогов, заполнение табличной части или проверка условий при изменении реквизита), не открывая саму форму интерактивно. Типичный пример — вызов обработчика ИмяРеквизитаПриИзменении из внешней обработки для массового пересчета данных в документах Бухгалтерия предприятия 3.0.
В данной статье мы подробно проанализируем, как можно реализовать такой вызов, разберем технические ограничения платформы 1С:Предприятие 8.3 и рассмотрим альтернативные, более надежные архитектурные решения.
Для того чтобы процедура модуля формы стала доступна «извне», она обязательно должна быть объявлена с ключевым словом Экспорт. Однако простого наличия этого слова недостаточно. Модуль формы — это контекстный объект, который существует только тогда, когда создана сама форма. Рассмотрим, как правильно инициировать этот процесс программно.
Проанализируем пример кода, который позволяет создать форму в памяти и обратиться к её методам:
&НаКлиенте
Процедура ЗаполнитьНалоговыйНаборЗаписей(СсылкаНаДокумент)
// Подготавливаем параметры для открытия формы.
// Ключ - это стандартный параметр, позволяющий открыть существующий объект.
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
// Получаем экземпляр формы. Важно: форма создается, но не открывается визуально.
ФормаДокумента = ПолучитьФорму("Документ.ОперацияБух.ФормаОбъекта", ПараметрыФормы);
// Теперь мы можем обращаться к экспортным процедурам модуля формы
// Например, если в форме есть экспортная процедура РассчитатьНалоги()
ФормаДокумента.РассчитатьНалогиНаСервере();
// После выполнения логики документ необходимо записать, если это не сделано внутри процедуры
ФормаДокумента.Записать();
КонецПроцедуры
Важные нюансы этого подхода:
ПолучитьФорму и работа с объектом формы должны происходить на стороне клиента. Попытка вызвать форму на сервере через ДокументОбъект.ПолучитьФорму() в коде серверного модуля, скорее всего, приведет к ошибке или не даст доступа к методам управляемой формы, так как визуальный слой на сервере отсутствует.ПолучитьФорму, платформа выполняет стандартные обработчики ПриСозданииНаСервере и ПриЧтенииНаСервере. Это гарантирует, что реквизиты формы будут заполнены так же, как если бы форму открыл пользователь.В некоторых старых конфигурациях или при использовании специфических механизмов (как в случае с ОперацияБух), разработчики пытаются использовать методы объектной техники. Рассмотрим ситуацию, когда метод ПолучитьФорму() вызывается непосредственно от объекта документа:
&НаСервере
Процедура ПерезаполнитьИзОбъекта(Ссылка)
ДокументОбъект = Ссылка.ПолучитьОбъект();
// Данный метод работает преимущественно в толстом клиенте
Форма = ДокументОбъект.ПолучитьФорму("ФормаОбъекта");
// Если процедура экспортная, к ней можно попытаться обратиться
Форма.ДокТиповойПриИзменении();
КонецПроцедуры
Выясним причину, почему этот код часто не работает в БП 3.0. В режиме управляемого приложения (тонкий клиент) сервер не может инстанциировать клиентскую часть формы. Поэтому, если ваша конфигурация работает в режиме управляемых форм, следует придерживаться первого способа или использовать архитектурный рефакторинг.
С точки зрения стандартов разработки «1С», размещение бизнес-логики (расчетов, заполнения) в модуле формы считается плохим тоном, если эта логика может потребоваться где-то еще. Рассмотрим правильную последовательность действий по выносу кода:
ПриИзменении в отдельную процедуру в общем модуле (например, РасчетДокументовСервер).ДокументОбъект или структуру данных, но не полагалась на элементы управления формы (кнопки, флажки).Пример реализации в общем модуле:
// В общем модуле (Сервер, Вызов сервера)
Процедура РассчитатьНалогиДокумента(ДанныеДокумента) Экспорт
// Универсальный код, работающий и с формой, и с объектом
ДанныеДокумента.СуммаНалога = ДанныеДокумента.Сумма * 0.2;
КонецПроцедуры
Если вы работаете с типовой конфигурацией (например, БП 3.0) и не хотите менять её код, чтобы не усложнять обновления, воспользуйтесь Расширениями. Проанализируем ситуацию: процедура в форме не является экспортной, и вы не можете её вызвать.
Разберем шаги:
Это позволит вам «достучаться» до скрытой логики, не снимая основную конфигурацию с поддержки.
В документах типа «Операция (бухгалтерский и налоговый учет)» движения часто отображаются непосредственно на форме через динамические списки или временные таблицы значений, которые не записываются в базу до нажатия кнопки «Записать». Если ваша цель — программно обновить экранные данные в уже открытой форме, используйте механизм оповещений:
Оповестить("Записать_ОперацияБух", ПараметрыОбновления, ЭтотОбъект);
Если же форма закрыта, и вы просто хотите вызвать алгоритм заполнения движений, который зашит в коде формы, помните: форме нужны данные. Если вы не передадите в ПараметрыФормы ссылку на реальный документ, многие обработчики выдадут ошибку при попытке обращения к Объект.Ссылка.
Программный вызов обработчика формы возможен, но это «костыль», которого стоит избегать. Если ситуация безвыходная — используйте ПолучитьФорму() на клиенте и делайте нужные методы экспортными. Если вы проектируете систему «с нуля» или имеете возможность менять код — выносите логику в модули менеджера или общие модули. Это сделает ваш код чище, быстрее и надежнее.