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