Как вызвать процедуры формы при программном создании объекта в 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке на платформе 1С:Предприятие 8.3 (Управляемое приложение) программисты часто сталкиваются с задачей программного создания документов. Типичная ситуация: вы создаете документ из обработки, заполняете ключевые реквизиты (например, БанковскийСчет или СуммаДокумента), и ожидаете, что связанные с ними поля заполнятся автоматически, как это происходит при интерактивной работе пользователя с формой. Однако логика, "зашитая" в событиях формы ПриИзменении, не срабатывает сама по себе. Рассмотрим подробнее, как правильно решить эту задачу, соблюдая стандарты разработки 1С.

Проблема разделения контекстов: Клиент против Сервера

Первое, что мы должны проанализировать — это то, где живет ваша логика. Процедуры формы, такие как БанковскийСчетПриИзменении, обычно располагаются в модуле формы и имеют директиву &НаКлиенте. Когда вы создаете объект программно на сервере с помощью функции Документы.ИмяДокумента.СоздатьДокумент(), никакой формы не существует. Попытка "дернуть" форму с сервера — это архитектурная ошибка, которая приведет к падению системы или крайне низкой производительности.

Проанализируем типичный сценарий: в документе СписаниеБезналичныхДенежныхСредств при изменении счета должен измениться и корреспондирующий счет или валюта. Если этот код написан только в модуле формы, он недоступен для серверного кода создания объекта. Разберем основные пути решения этой проблемы.

Решение 1: Использование механизма ОбработкаЗаполнения

Это наиболее правильный и рекомендуемый фирмой "1С" способ. Вместо того чтобы пытаться имитировать действия пользователя в форме, мы должны использовать стандартное событие модуля объекта — ОбработкаЗаполнения. Рассмотрим, как это работает по шагам.

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


// Код в обработке
НовыйДокумент = Документы.СписаниеБезналичныхДенежныхСредств.СоздатьДокумент();
ДанныеДляЗаполнения = Новый Структура;
ДанныеДляЗаполнения.Вставить("БанковскийСчет", НужныйСчет);
ДанныеДляЗаполнения.Вставить("Сумма", 1000);
ДанныеДляЗаполнения.Вставить("ХозОперация", Перечисления.ХозяйственныеОперации.ОплатаПоставщику);

// Вызываем стандартный механизм заполнения
НовыйДокумент.Заполнить(ДанныеДляЗаполнения);

Во-вторых, в модуле объекта документа необходимо описать реакцию на эту структуру в процедуре ОбработкаЗаполнения. Посмотрим на пример реализации:


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

Решение 2: Вынос бизнес-логики в общие модули

Если процедура на форме содержит важные расчеты, которые требуются и при программном заполнении, мы должны вынести эту логику из модуля формы. Это критически важный момент для конфигураций типа УТ 11, ERP или КА.

Рассмотрим алгоритм рефакторинга:

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

Пример процедуры в общем модуле ДенежныеСредстваСервер:


Процедура РассчитатьПараметрыПлатежа(ОбъектДокумента) Экспорт
    // Здесь сложная логика:
    // Поиск корреспондирующего счета, установка валюты счета, пересчет сумм
    // ...
КонецПроцедуры

Решение 3: Программный вызов экспортных процедур формы (только для Клиента)

Если ваша обработка запускается интерактивно пользователем и вам необходимо именно "показать" заполненную форму с отработавшей логикой, можно пойти по пути эмуляции. Выясним, как это сделать правильно. Для этого процедуры в модуле формы должны быть объявлены с ключевым словом Экспорт.


// В модуле формы документа
&НаКлиенте
Процедура ВыполнитьПересчетЭкспорт() Экспорт
    // Логика пересчета
КонецПроцедуры

Затем в коде обработки мы сначала получаем форму, заполняем её данные и вызываем экспортный метод:


// В модуле обработки (на клиенте)
ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", СтруктураДанных);
ФормаДокумента = ПолучитьФорму("Документ.СписаниеБезналичныхДенежныхСредств.ФормаОбъекта", ПараметрыФормы);
ФормаДокумента.Открыть();

// Теперь вызываем экспортную процедуру формы
ФормаДокумента.ВыполнитьПересчетЭкспорт();

Важное ограничение: этот метод не будет работать в фоновых заданиях, в регламентных заданиях или в любом коде, исполняемом на сервере без участия пользователя. Поэтому данный подход считается "грязным" и не рекомендуется для использования в тиражных решениях.

Особенности работы с типовыми конфигурациями (УТ 11, ERP)

В современных типовых решениях от "1С" разработчики уже предусмотрели большинство механизмов программного заполнения. Выясним, на что стоит обратить внимание в документе СписаниеБезналичныхДенежныхСредств:

Итоги и рекомендации

Подводя итог, разберем краткий чек-лист для программиста:

  1. Никогда не пытайтесь вызвать процедуры модуля формы из серверного кода (из модуля объекта или общего модуля без признака "Клиент").
  2. Если логика нужна и форме, и при программном создании — выносите её в модуль объекта (если она касается только этого документа) или в общий модуль (если она универсальна).
  3. Для программного создания объектов используйте метод Заполнить(СтруктураПараметров), реализуя логику в ОбработкаЗаполнения.
  4. Помните, что реквизиты формы (не путать с реквизитами объекта) существуют только пока открыта форма. Если расчеты завязаны на них, их придется перенести в дополнительные реквизиты объекта или рассчитывать заново.

Следуя этим правилам, вы обеспечите стабильную работу системы и отсутствие ошибок при выполнении кода в различных контекстах.

← На главную