При доработке типовых конфигураций через расширения часто возникает необходимость перехватить клиентское событие (например, процедуру подсистемы печати) и выполнить серверные операции — сформировать печатную форму в формате PDF и прикрепить ее к документу. Однако при вызове серверной функции напрямую из клиентского модуля разработчики часто сталкиваются с ошибкой синтаксического контроля: «Процедура или функция с указанным именем не определена».
В этой статье мы подробно проанализируем причину возникновения контекстных ошибок при работе с расширениями и разберем по шагам правильный порядок организации клиент-серверного взаимодействия.
Рассмотрим ситуацию, с которой столкнулся разработчик. В расширение был добавлен общий модуль УправлениеПечатьюКлиент, и с помощью аннотации &После была перехвачена процедура ВыполнитьКомандуПечати:
&После("ВыполнитьКомандуПечати")
Процедура Расш_ПечатьКомплектаДокументов_ВыполнитьКомандуПечати(ИмяМенеджераПечати, ИменаМакетов, МассивОбъектов, ВладелецФормы, ПараметрыПечати)
ФорматыСохранения = Новый Массив;
ФорматыСохранения.Добавить(ТипФайлаТабличногоДокумента.PDF);
РезультатВыбора = Новый Структура;
РезультатВыбора.Вставить("УпаковатьВАрхив", Истина);
РезультатВыбора.Вставить("ФорматыСохранения", ФорматыСохранения);
РезультатВыбора.Вставить("ВариантСохранения", "Присоединить");
РезультатВыбора.Вставить("ПапкаДляСохранения", "");
РезультатВыбора.Вставить("ОбъектДляПрикрепления", МассивОбъектов[0]);
РезультатВыбора.Вставить("ПереводитьИменаФайловВТранслит", Истина);
РезультатВыбора.Вставить("АдресКомплектаПечатныхФорм", ПараметрыПечати.АдресКомплектаПечатныхФорм);
ФайлыВоВременномХранилище = ПоместитьТабличныеДокументыВоВременноеХранилище(РезультатВыбора);
КонецПроцедуры
При попытке описать функцию ПоместитьТабличныеДокументыВоВременноеХранилище с директивой &НаСервере прямо в том же модуле синтаксический контроль Тонкого клиента выдает ошибку. Выясним, почему это происходит.
Модуль УправлениеПечатьюКлиент предназначен для выполнения исключительно на стороне клиента (Тонкий клиент / Web-клиент). Директива компиляции &НаСервере не может заставить клиентский модуль исполняться на сервере. В клиентском контексте серверный метод просто «не виден», из-за чего платформа не может скомпилировать вызов.
Чтобы вызывать серверные процедуры и функции из клиентских обработчиков расширения, требуется вынести серверную логику в отдельный общий модуль.
Расш_УправлениеПечатьюСервер) или задействуем существующий серверный модуль из Библиотеки Стандартных Подсистем (БСП) с поддержкой вызова сервера.Наличие флага Вызов сервера является критически важным условием: именно он разрешает тонкому клиенту обращаться к экспортным методам данного модуля.
Разместим функцию сохранения табличных документов во временное хранилище и логику прикрепления файлов в созданный серверный модуль:
// В общем модуле Расш_УправлениеПечатьюСервер (Флаги: Сервер, Вызов сервера)
Функция ПоместитьТабличныеДокументыВоВременноеХранилище(ПереданныеНастройки) Экспорт
// Выполнение формирования файлов печатных форм и помещение их во временное хранилище
// Использование стандартных механизмов БСП для работы с печатно-графическими формами
Возврат УправлениеПечатью.ПоместитьТабличныеДокументыВоВременноеХранилище(ПереданныеНастройки);
КонецФункции
Процедура ПрисоединитьПечатныеФормыКОбъекту(ФайлыВоВременномХранилище, ОбъектПрикрепления) Экспорт
УправлениеПечатью.ПрисоединитьПечатныеФормыКОбъекту(ФайлыВоВременномХранилище, ОбъектПрикрепления);
КонецПроцедуры
Теперь перепишем клиентскую процедуру в модуле УправлениеПечатьюКлиент, явно обращаясь к серверным методам через имя нового общего модуля:
&После("ВыполнитьКомандуПечати")
Процедура Расш_ПечатьКомплектаДокументов_ВыполнитьКомандуПечати(ИмяМенеджераПечати, ИменаМакетов, МассивОбъектов, ВладелецФормы, ПараметрыПечати)
Если МассивОбъектов.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ФорматыСохранения = Новый Массив;
ФорматыСохранения.Добавить(ТипФайлаТабличногоДокумента.PDF);
РезультатВыбора = Новый Структура;
РезультатВыбора.Вставить("УпаковатьВАрхив", Истина);
РезультатВыбора.Вставить("ФорматыСохранения", ФорматыСохранения);
РезультатВыбора.Вставить("ВариантСохранения", "Присоединить");
РезультатВыбора.Вставить("ПапкаДляСохранения", "");
РезультатВыбора.Вставить("ОбъектДляПрикрепления", МассивОбъектов[0]);
РезультатВыбора.Вставить("ПереводитьИменаФайловВТранслит", Истина);
РезультатВыбора.Вставить("АдресКомплектаПечатныхФорм", ПараметрыПечати.АдресКомплектаПечатныхФорм);
// Вызов методов серверного модуля расширения
ФайлыВоВременномХранилище = Расш_УправлениеПечатьюСервер.ПоместитьТабличныеДокументыВоВременноеХранилище(РезультатВыбора);
Расш_УправлениеПечатьюСервер.ПрисоединитьПечатныеФормыКОбъекту(ФайлыВоВременномХранилище, МассивОбъектов[0]);
КонецПроцедуры
При работе с печатными формами и расширениями учтем следующие нюансы:
ВыполнитьКомандуПечати запускает процесс печати. В момент вызова &После("ВыполнитьКомандуПечати") табличные документы могут находиться в процессе фонового формирования. Если адрес хранилища ПараметрыПечати.АдресКомплектаПечатныхФорм пуст, надежнее перехватывать событие закрытия или выбор действия в форме ОбщаяФорма.ПечатьДокументов.МассивОбъектов[0] прикрепляет файлы только к первому элементу. Если печать осуществляется для группы документов, потребуется обходить массив в цикле.