Как выполнить процедуру формы из общего модуля или фонового задания?

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

При разработке на платформе 1С:Предприятие 8.3, особенно в конфигурациях на базе ЗУП 3.1, разработчики часто сталкиваются с ситуацией, когда сложная логика заполнения документа (например, ПерезаполнитьДанныеФормыНаСервере) «заперта» внутри модуля формы. Попытка вызвать такую процедуру программно из другой обработки или через механизм длительных операций (фоновых заданий) приводит к логическому тупику. Разберем детально, почему это происходит и как правильно решить эту задачу.

Почему нельзя просто вызвать процедуру формы на сервере?

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

Механизм РеквизитФормыВЗначение также работает исключительно внутри модуля формы, так как для преобразования данных формы в объект (ДокументОбъект) платформе требуется контекст текущей формы, которого нет в фоновом задании или в обычном вызове из общего модуля без передачи этого контекста.

Анализируем типовую логику (на примере ЗУП)

Проанализируем ситуацию на примере документа «Разовое начисление». В типовых конфигурациях процедура ПерезаполнитьДанныеФормыНаСервере обычно выполняет следующие действия:

  1. Собирает данные из реквизитов формы.
  2. Вызывает специализированные методы из общих модулей (ядро бизнес-логики).
  3. Обновляет таблицу данных на форме.

Наша задача — миновать форму и обратиться напрямую к «ядру» логики. Выясним причину, по которой код находится в форме: чаще всего это связано с удобством интерактивной работы, но для автоматизации это становится препятствием.

Шаг 1: Поиск программного интерфейса

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

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


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

Шаг 2: Перенос логики при отсутствии типовых методов

Если после анализа выяснилось, что нужная логика написана только в модуле формы и не вызывает никакие общие модули (что является нарушением стандартов разработки 1С, но встречается в жизни), нам придется провести рефакторинг. Разберем, как это сделать максимально безопасно для будущих обновлений:

  1. Создадим собственный общий модуль, например, _РаботаСДокументамиКастом.
  2. Установим у модуля флаги Сервер и Вызов сервера.
  3. Скопируем логику из процедуры формы в процедуру этого модуля.
  4. Заменим обращения к реквизитам формы (Объект.Сотрудники) на обращения к свойствам переданного объекта (ДокументОбъект.Сотрудники).

Посмотрим на пример трансформации кода:

Было в форме:


&НаСервере
Процедура ПерезаполнитьДанныеФормыНаСервере()
    Для Каждого Стр Из Объект.Начисления Цикл
        Стр.Результат = Объект.Сумма / Объект.Начисления.Количество();
    КонецЦикла;
КонецПроцедуры

Стало в общем модуле:


Процедура РассчитатьНачисления(ДокументОбъект) Экспорт
    Для Каждого Стр Из ДокументОбъект.Начисления Цикл
        Стр.Результат = ДокументОбъект.Сумма / ДокументОбъект.Начисления.Количество();
    КонецЦикла;
КонецПроцедуры

Шаг 3: Использование расширений для минимизации конфликтов

Чтобы не изменять типовую конфигурацию и упростить обновление, настоятельно рекомендуем использовать Расширения. Мы можем создать расширение и перенести логику из формы в модуль менеджера документа через &После или &Вместо. Модуль менеджера доступен в любом контексте, включая фоновые задания, и позволяет использовать ДокументОбъект без лишних манипуляций.

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

Рекомендации по оптимизации производительности

Если обработка документов занимает несколько часов, как в примере автора темы, использование фоновых заданий — это верное направление. Однако помните о следующих нюансах:

Таким образом, правильный ответ на вопрос «как выполнить процедуру формы» — никак. Вместо этого нужно извлечь бизнес-логику из «плена» интерфейса и перенести её на уровень сервера (общие модули или модули менеджеров), где она станет доступной для любых механизмов платформы, включая фоновые задания и внешние соединения.

← На главную