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