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

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

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

Анализ причин ошибки компиляции

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


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

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

{Документ.СторнированиеОплаты.Форма.ФормаДокументаУФ.Форма(81,2)}: Процедура или функция с указанным именем не определена (ИнициализацияМеханизмаПечати) (Проверка: Сервер)

Выясним причину такого поведения. Существует несколько факторов, приводящих к подобной ошибке:

  1. Директивы препроцессора внутри общего модуля: если в тексте общего модуля выше по коду установлена инструкция #Если Клиент Тогда, то весь последующий код исключается из компиляции на стороне сервера. В результате серверный контекст просто «не видит» процедуру, даже если у самого модуля выставлен флаг Сервер.
  2. Флаги компиляции общего модуля: для выполнения кода на стороне тонкого клиента модуль должен иметь установленный признак Клиент (управляемое приложение). Если же модуль предназначен только для Клиент (обычное приложение) и Сервер, то на клиенте управляемой формы вызов будет недоступен.
  3. Попытка обращения к глобальным процедурам через имя модуля: если модуль объявлен как Глобальный, обращение к его процедурам по имени модуля (например, сХранилищеДополнительнойИнформации.ИнициализацияМеханизмаПечати()) приведет к ошибке Переменная не определена. К глобальным модулям обращаются напрямую по имени процедуры без указания имени модуля.

Архитектурные ограничения обычных форм в контексте управляемых форм

Даже если убрать директиву #Если Клиент Тогда, прямой перенос кода печати из обычных форм на управляемые приведет к ошибкам времени выполнения. Проанализируем, почему старый подход не работает:

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

Решение 1: Переход на типовую подсистему «Печать» БСП

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

Шаг 1. Описание команд печати в модуле менеджера объекта

Откроем модуль менеджера документа и добавим экспортную процедуру ДобавитьКомандыПечати:


// В модуле менеджера документа
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт

    КомандаПечати = КомандыПечати.Добавить();
    КомандаПечати.Идентификатор = "ПечатьДокумента";
    КомандаПечати.Представление = НСтр("ru = 'Печатная форма документа'");
    КомандаПечати.Обработчик    = "УправлениеПечатьюКлиент.ВыполнитьКомандуПечати";
    КомандаПечати.СписокФорм    = "ФормаДокумента,ФормаСписка";
    КомандаПечати.Порядок       = 1;

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

Шаг 2. Реализация формирования печатной формы на сервере

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


// В модуле менеджера документа
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт

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

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

Шаг 3. Подключение подсистемы печати в управляемой форме

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    // Подключение команд печати БСП на командную панель формы
    УправлениеПечатью.ПриСозданииНаСервере(ЭтаФорма, Элементы.ГруппаКоманднаяПанель);

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

Решение 2: Создание собственной команды печати в управляемой форме

Если внедрение механизмов БСП не планируется, построим работу с печатью напрямую через клиент-серверное взаимодействие управляемой формы:

  1. На вкладке Команды формы документа создадим команду (например, КомандаПечать) и перетащим ее в командную панель формы в виде кнопки.
  2. В обработчике команды на клиенте вызовем серверную функцию для формирования макета и откроем результат в отдельном окне:

&НаКлиенте
Процедура КомандаПечать(Команда)
    
    ТабДок = СформироватьМакетНаСервере();
    ТабДок.Показать("Печатная форма документа");
    
КонецПроцедуры

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

Рекомендации по настройке общих модулей

Чтобы избежать ошибок видимости процедур при разработке на платформе «1С:Предприятие 8.3»:

  1. Избегайте смешанных модулей: не рекомендуется объединять серверный и клиентский контексты в одном общем модуле. Разделяйте код на специализированные модули: ИмяМодуляКлиент, ИмяМодуляСервер, ИмяМодуляКлиентСервер.
  2. Отказывайтесь от глобальных модулей: флаг Глобальный засоряет глобальное пространство имен и усложняет отладку. Для новых модулей флаг Глобальный устанавливать не следует, обращаясь к методам явно: ИмяМодуля.ИмяПроцедуры().
  3. Контролируйте область действия директив препроцессора: если директива #Если Клиент Тогда или #Если Сервер Тогда открыта, обязательно закрывайте ее конструкцией #КонецЕсли перед следующими процедурами, чтобы не отсекать серверную компиляцию других методов.
← На главную