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

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

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

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

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

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

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

Главное правило разработки: если логика должна вызываться из нескольких мест (из формы списка, регламентного задания или обработки), её необходимо выносить из модуля формы в модуль объекта, модуль менеджера или общий модуль.

Вариант 1. Перенос логики в модуль объекта (работа с конкретным документом)

Рассмотрим случай, когда процедура изменяет данные самого документа: пересчитывает суммы, заполняет табличные части, изменяет реквизиты или проводит документ. В этой ситуации алгоритм должен располагаться в Модуле объекта документа.

Разберем по шагам, как это реализовать:

  1. Откроем модуль объекта нужного документа и создадим экспортную процедуру:
    
    // В модуле объекта документа
    Процедура РассчитатьИЗаполнитьДанные() Экспорт
        
        // Алгоритм обработки данных документа
        Для Каждого Стр Из Товары Цикл
            Стр.Сумма = Стр.Количество * Стр.Цена;
        КонецЦикла;
        
    КонецПроцедуры
    
  2. В форме списка документов (на сервере) получим объект по ссылке, вызовем процедуру и запишем изменения:
    
    &НаСервере
    Процедура ОбработатьДокументНаСервере(СсылкаНаДокумент)
        
        ОбъектДокумента = СсылкаНаДокумент.ПолучитьОбъект();
        ОбъектДокумента.РассчитатьИЗаполнитьДанные();
        ОбъектДокумента.Записать(РежимЗаписиДокумента.Запись);
        
    КонецПроцедуры
    

Вариант 2. Перенос логики в модуль менеджера (расчетные и сервисные функции)

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

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

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

Вариант 3. Взаимодействие с уже открытой формой через оповещения

Если задача заключается в том, чтобы передать команду или обновить данные в форме документа, которая уже открыта на рабочем столе пользователя, используется стандартный механизм оповещений платформы 1С.

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

Вариант 4. Передача параметров при открытии формы документа

Если требуется открыть форму документа из списка и сразу выполнить в ней определенное действие, передадим параметры при вызове метода ОткрытьФорму():


&НаКлиенте
Процедура ОткрытьДокументСДействием(Команда)
    
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("Ключ", Элементы.Список.ТекущаяСтрока);
    ПараметрыОткрытия.Вставить("АвтоматическийРасчет", Истина);
    
    ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыОткрытия);
    
КонецПроцедуры

В самой форме документа в процедуре ПриСозданииНаСервере или ПриОткрытии проверяем переданное значение:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    Если Параметры.Свойство("АвтоматическийРасчет") И Параметры.АвтоматическийРасчет Тогда
        // Выполняем требуемую инициализацию
    КонецЕсли;
    
КонецПроцедуры
← На главную