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