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

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

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

Проанализируем типичный пример кода, в котором возникает ошибка:


&НаСервере
Процедура СформироватьНаСервере()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    КВП_Здания.Ссылка
        |ИЗ
        |    Справочник.КВП_Здания КАК КВП_Здания
        |ГДЕ
        |    НЕ КВП_Здания.ЭтоГруппа
        |    И НЕ КВП_Здания.ПометкаУдаления";
    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        ДокОбъект = Документы.УПЖКХ_ЗакрытиеПериодаПоНачислениямЖКХ.СоздатьДокумент();
        ДокОбъект.Дата = КонецМесяца(Объект.Дата);
        ДокОбъект.Организация = УПЖКХ_ТиповыеМетодыВызовСервера.ПолучитьЗначениеПоУмолчанию("ОсновнаяОрганизация");
        ДокОбъект.КорректировкаРасчета = Истина;
        
        // Ошибка: Метод объекта не обнаружен (ЗаполнитьТабличныеЧастиДокумента)
        ДокОбъект.ЗаполнитьТабличныеЧастиДокумента(Истина);
        
        ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
    КонецЦикла;
    
КонецПроцедуры

Выясним причину ошибки: переменная ДокОбъект содержит ссылку на экземпляр ДокументОбъект, чьим контекстом является Модуль объекта. Процедура ЗаполнитьТабличныеЧастиДокумента объявлена с директивой &НаСервере Экспорт в Модуле управляемой формы. При невизуальном создании объекта через СоздатьДокумент() модуль формы вообще не инициализируется и не компилируется, а его экспортные методы недоступны для экземпляра прикладного объекта.

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

Вариант 1. Перенос логики заполнения в модуль менеджера или модуль объекта конфигурации

Если конфигурация доступна для редактирования, наиболее грамотным архитектурным решением является разделение бизнес-логики и интерфейса. Алгоритм заполнения табличных частей выносится из формы в модуль менеджера документа или модуль объекта:

  1. Переместим алгоритм в Модуль менеджера документа, сделав метод экспортным:
    
    // В модуле менеджера документа
    Процедура ЗаполнитьТабличныеЧастиДокумента(ДокументОбъект, ПолучатьОстаткиСКорректировками) Экспорт
        // Алгоритм выборки данных и заполнения табличных частей
        // Обращение к реквизитам идет через переданный параметр ДокументОбъект
    КонецПроцедуры
    
  2. В модуле формы заменим тело старой процедуры на обращение к модулю менеджера:
    
    &НаСервере
    Процедура ЗаполнитьТабличныеЧастиДокументаНаСервере()
        ДокОбъект = РеквизитФормыВЗначение("Объект");
        Документы.УПЖКХ_ЗакрытиеПериодаПоНачислениямЖКХ.ЗаполнитьТабличныеЧастиДокумента(ДокОбъект, Истина);
        ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
    КонецПроцедуры
    
  3. В обработке вызовем процедуру напрямую через менеджер документа:
    
    ДокОбъект = Документы.УПЖКХ_ЗакрытиеПериодаПоНачислениямЖКХ.СоздатьДокумент();
    ДокОбъект.Дата = КонецМесяца(Объект.Дата);
    Документы.УПЖКХ_ЗакрытиеПериодаПоНачислениямЖКХ.ЗаполнитьТабличныеЧастиДокумента(ДокОбъект, Истина);
    ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
    

Если логика заполнения стандартна при создании нового документа, ее также можно разместить в стандартном обработчике ОбработкаЗаполнения модуля объекта и вызывать через метод ДокОбъект.Заполнить(ПараметрыЗаполнения).

Вариант 2. Использование расширения конфигурации (для типовых конфигураций на поддержке)

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

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

Вариант 3. Копирование серверного алгоритма в контекст внешней обработки

Когда требуется выполнить задачу исключительно силами внешней обработки без изменений конфигурации и добавления расширений, перенесем код функции непосредственно в модуль обработки. Рассмотрим порядок адаптации кода:

  1. Скопируем функцию заполнения из модуля формы в модуль формы или объект обработки.
  2. Заменим все обращения к реквизитам формы вида Объект.ИмяРеквизита на обращения к полям локального объекта ДокОбъект.ИмяРеквизита.
  3. Удалим обращения к элементам интерфейса (Элементы.), клиентским переменным и диалогам пользователя, если они присутствовали в исходной процедуре.
  4. Вызовем адаптированную серверную процедуру внутри цикла обработки:
    
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        ДокОбъект = Документы.УПЖКХ_ЗакрытиеПериодаПоНачислениямЖКХ.СоздатьДокумент();
        ДокОбъект.Дата = КонецМесяца(Объект.Дата);
        ДокОбъект.Организация = УПЖКХ_ТиповыеМетодыВызовСервера.ПолучитьЗначениеПоУмолчанию("ОсновнаяОрганизация");
        ДокОбъект.КорректировкаРасчета = Истина;
        
        // Вызов локальной серверной процедуры обработки
        ЗаполнитьТабличныеЧастиОбработки(ДокОбъект, Истина);
        
        ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
    КонецЦикла;
    

Данный подход обеспечивает максимальную скорость выполнения при пакетной генерации документов и полностью исключает зависимость фонового серверного кода от контекста экранных форм.

← На главную