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

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

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

Причина ограничения: клиент-серверное разделение контекстов

Рассмотрим архитектуру управляемого приложения 1С:Предприятие 8.3. Управляемая форма (объект ФормаОбъекта) существует исключительно на стороне клиента. В то же время подписки на события объектов (такие как ПередЗаписью, ПриЗаписи, ОбработкаПроведения) исполняются строго на сервере в контексте `ДокументОбъект` или `СправочникОбъект`.

Попытка обратиться к форме из подписки на событие невозможна по следующим причинам:

  1. Отсутствие контекста: На сервере контекст формы недоступен, а переменная ЭтаФорма или реквизиты формы не существуют в модуле объекта и подписке.
  2. Разделение кода: Процедуры модуля формы с директивой &НаКлиенте физически не исполняются на сервере, а процедуры с директивой &НаСервере в модуле формы доступны только из самого контекста этой формы.
  3. Транзакционные риски: Попытка интерактивного открытия или манипулирования формами во время проведения документа нарушает целостность серверных транзакций.

Способ 1. Вынос бизнес-логики в серверные общие модули

Разберем классический правильный подход к рефакторингу кода. Если расчет цен, сумм, налогов или подстановка договоров привязана к форме (например, в процедуре ОрганизацияПриИзменении), необходимо вынести алгоритм из модуля формы в экспортную процедуру серверного общего модуля.

При этом метод должен принимать в качестве параметра не контекст формы (ЭтаФорма), а объект данных (ДокументОбъект) или структуру с параметрами.

Посмотрим на пример вызова процедуры из подписки на событие:


// В подписке на событие (Сервер)
Процедура ОбработкаПриЗаписиДокумента(Источник, Отказ) Экспорт

    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Создаем новый документ для другой организации
    НовыйДокумент = Документы.ПриобретениеТоваровУслуг.СоздатьДокумент();
    ЗаполнитьЗначенияСвойств(НовыйДокумент, Источник, , "Ссылка, Номер, Организация");
    
    // Передаем необходимую организацию
    НовыйДокумент.Организация = ПолучитьОрганизациюПолучателя(Источник.Организация);
    
    // Вызываем экспортный серверный модуль для пересчета данных
    ЗакупкиСервер.РассчитатьРеквизитыДокумента(НовыйДокумент);
    
    НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

КонецПроцедуры

В самом общем модуле процедура работает с данными объекта без обращения к элементам формы:


// Общий модуль: ЗакупкиСервер (Сервер, Вызов сервера)
Процедура РассчитатьРеквизитыДокумента(ДокументОбъект) Экспорт

    ДопПараметры = ЗакупкиСервер.ДополнительныеПараметрыОтбораДоговоров();
    ДопПараметры.ВалютаВзаиморасчетов = ДокументОбъект.Валюта;
    
    // Заполняем договор по алгоритму конфигурации
    ДокументОбъект.Договор = ЗакупкиСервер.ПолучитьДоговорПоУмолчанию(
        ДокументОбъект, 
        ДокументОбъект.ХозяйственнаяОперация, 
        ДопПараметры
    );

КонецПроцедуры

Способ 2. Использование штатного механизма "ОбработкаЗаполнения"

Выясним, как использовать платформенные средства заполнения документов на основании других объектов. Платформа 1С предоставляет встроенный метод Заполнить(), который вызывает событие ОбработкаЗаполнения в модуле объекта создаваемого документа.

Этот подход позволяет заполнить все реквизиты объекта на сервере без необходимости создавать форму:


// Вызов в подписке на событие или алгоритме на сервере
НовыйДокумент = Документы.ПриобретениеТоваровУслуг.СоздатьДокумент();

// В качестве параметра передается структура или ссылка на документ-основание
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("ДокументОснование", Источник.Ссылка);
ПараметрыЗаполнения.Вставить("НоваяОрганизация", ОрганизацияПолучатель);

// Платформа вызывает ОбработкаЗаполнения в модуле создаваемого документа
НовыйДокумент.Заполнить(ПараметрыЗаполнения);
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

В модуле объекта создаваемого документа пересчет реализуется следующим образом:


// Модуль объекта Документа "ПриобретениеТоваровУслуг"
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
        СтандартнаяОбработка = Ложь;
        
        // Заполняем основные реквизиты и табличные части
        ЗаполнитьПоОснованию(ДанныеЗаполнения.ДокументОснование);
        ЭтотОбъект.Организация = ДанныеЗаполнения.НоваяОрганизация;
        
        // Выполняем серверный пересчет сторонних данных
        ЗакупкиСервер.ЗаполнитьРеквизитыПоУмолчанию(ЭтотОбъект);
    КонецЕсли;

КонецПроцедуры

Способ 3. Отложенное создание документов (Фоновые задания и очереди)

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

Для предотвращения этих проблем рекомендуется использовать механику очереди задач:

  1. В подписке на событие ПриЗаписи фиксируется необходимость создания нового документа (например, путем добавления записи в специальный регистр сведений-очередь).
  2. Регламентное или фоновое задание периодически считывает данные из регистра очереди и создает новые документы в отдельных независимых транзакциях.

Пример записи в регистр очереди из подписки:


Процедура ЗафиксироватьОчередьСоздания(Источник, Отказ) Экспорт

    Если Источник.ОбменДанными.Загрузка Или Отказ Тогда
        Возврат;
    КонецЕсли;

    МенеджерЗаписи = РегистрыСведений.ОчередьСозданияДокументов.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.ДокументИсточник = Источник.Ссылка;
    МенеджерЗаписи.Период = ТекущаяДатаСеанса();
    МенеджерЗаписи.Состояние = Перечисления.СостоянияОчереди.ВОчереди;
    МенеджерЗаписи.Записать();

КонецПроцедуры

Итоги

Попытка вызова клиентских процедур управляемой формы из подписки на событие противоречит базовым принципам архитектуры 1С 8.3. Вся бизнес-логика заполнения, расчета и обработки данных должна быть вынесена в серверные модули объектов или общие модули, принимающие параметры типа ДокументОбъект. Для тяжелых операций создания связанных объектов правильным решением является использование механизма заполнения по основанию (ОбработкаЗаполнения) либо фоновая обработка очереди задач.

← На главную