Вызов процедур и функций в 1С 8.3: от общего модуля до внешнего соединения

· 9 мин

Содержание

Чтобы обратиться к функции в 1С, напишите её имя со скобками и присвойте результат переменной: Сумма = РассчитатьСкидку(Документ, 5);. Если функция лежит в другом модуле, у неё должно стоять слово Экспорт, а вызов идёт через имя модуля: РаботаСЦенами.РассчитатьСкидку(Документ, 5).

Типичная ситуация: программист дописал в общий модуль полезную функцию, вызвал её из формы документа — и получил Метод объекта не обнаружен. Почти всегда причина в одном из трёх мест: нет Экспорт, не тот контекст (клиент/сервер) или не выставлен флаг модуля. Те же правила видимости работают и дальше: во внешних обработках, при вызове через COM и HTTP, при динамическом вызове по имени.

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

Во встроенном языке два вида методов. Процедура выполняет действия и ничего не возвращает. Функция возвращает значение через Возврат.

Функция СуммаСНДС(Сумма, Ставка = 20) Экспорт
    Возврат Сумма + Сумма * Ставка / 100;
КонецФункции

Процедура ПоказатьИтог(Сумма)
    Сообщить("Итого: " + Формат(Сумма, "ЧДЦ=2"));
КонецПроцедуры

Вызов функции:

Итого = СуммаСНДС(1000);      // 1200, ставка по умолчанию
Итого = СуммаСНДС(1000, 10);  // 1100
ПоказатьИтог(Итого);

Что важно знать про параметры:

  • 📌 По умолчанию параметры передаются по ссылке. Если функция изменит переменную-параметр, изменится и переменная в вызывающем коде.
  • 🔒 Знач перед именем параметра передаёт копию значения: Функция Проверить(Знач Код).
  • ➕ Необязательные параметры задают значением по умолчанию (Ставка = 20). Их можно пропустить: СуммаСНДС(1000, ) или просто СуммаСНДС(1000).
  • ↩️ Функцию можно вызвать как процедуру, без присваивания: результат просто отбросится.

Где лежит метод и как к нему обратиться

Где объявлен методКак вызватьУсловие
Тот же модульИмяМетода()Объявлен выше или ниже — неважно
Общий модульИмяМодуля.ИмяМетода()Экспорт и подходящие флаги модуля
Модуль менеджера справочникаСправочники.Номенклатура.ИмяМетода()Экспорт
Модуль объектаСправочникОбъект.ИмяМетода()Экспорт, сначала получить объект
Модуль формыЭтаФорма.ИмяМетода() или из другой формы через ссылку на формуЭкспорт для вызова снаружи
Глобальный общий модульИмяМетода() без имени модуляФлаг «Глобальный»

Из модуля объекта к методу обращаются через сам объект: Объект = Ссылка.ПолучитьОбъект(); Объект.ЗаполнитьРеквизиты();. По ссылке метод модуля объекта не вызвать.

Клиент, сервер и флаги общего модуля

В управляемом приложении код выполняется либо на клиенте, либо на сервере. Функция, которая работает с базой (запросы, запись объектов), может жить только на сервере. Поэтому вызов «с формы» часто превращается в серверный вызов.

Директивы в модуле формы:

  • 🖥 &НаКлиенте — метод работает на клиенте, к базе не обращается.
  • 🗄 &НаСервере — серверный вызов с передачей данных формы. Удобно, но тяжело: форма гоняется туда и обратно.
  • ⚡ &НаСервереБезКонтекста — серверный вызов без данных формы. Быстрее, но реквизиты формы внутри недоступны, их передают параметрами.
&НаКлиенте
Процедура Рассчитать(Команда)
    Объект.Сумма = ПолучитьЦенуНаСервере(Объект.Номенклатура);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьЦенуНаСервере(Номенклатура)
    Возврат РаботаСЦенами.ЦенаПоУмолчанию(Номенклатура);
КонецФункции

Флаги общего модуля в свойствах решают, откуда его видно:

ФлагЧто даёт
Клиент (управляемое приложение)Модуль доступен на клиенте
СерверДоступен в серверном коде
Вызов сервераКлиент может напрямую вызвать его экспортные функции
Внешнее соединениеДоступен при подключении через COM
ПривилегированныйКод выполняется без проверки прав
ГлобальныйМетоды вызываются без имени модуля

Если с клиента нужно вызвать серверную функцию общего модуля напрямую, включите у модуля флаги «Сервер» и «Вызов сервера». Без второго флага клиентский код метод не увидит.

Ещё один частый случай — запуск функции в фоне. Метод для фонового задания должен быть экспортным и лежать в серверном общем модуле:

Параметры = Новый Массив;
Параметры.Добавить(Организация);
ФоновыеЗадания.Выполнить("ОбменДанными.ВыгрузитьОстатки", Параметры, , "Выгрузка остатков");

Вызов функций внешней обработки и внешнего отчёта

Внешняя обработка (.epf) — отдельный файл со своим модулем объекта. Её экспортные функции можно вызвать из кода конфигурации, не встраивая обработку в базу.

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

&НаКлиенте
Процедура ЗапуститьВнешнююОбработку(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
    НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры

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

&НаСервереБезКонтекста
Функция ВызватьФункциюОбработки(Адрес)
    ИмяОбработки = ВнешниеОбработки.Подключить(Адрес, , Ложь);
    Обработка = ВнешниеОбработки.Создать(ИмяОбработки, Ложь);
    Возврат Обработка.ПосчитатьОстатки(ТекущаяДатаСеанса());
КонецФункции

Что здесь происходит:

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

Для отчётов то же самое делает ВнешниеОтчеты.Подключить и ВнешниеОтчеты.Создать.

Параметр Ложь отключает безопасный режим: код обработки получает доступ к файлам, COM и внешним ресурсам. Подключайте так только обработки, которым доверяете. Для чужого кода оставьте безопасный режим (Истина).

В типовых конфигурациях на БСП внешние обработки обычно подключают через справочник дополнительных отчётов и обработок: Администрирование → Печатные формы, отчеты и обработки → Дополнительные отчеты и обработки. Тогда в модуле обработки нужна экспортная функция СведенияОВнешнейОбработке(), которая описывает вид обработки и её команды.

Вызов функций 1С через COM-соединение

COM-соединение нужно, когда другая программа (или другая база 1С) должна вызвать функцию вашей базы без запуска окна клиента. Работает только под Windows.

Подготовка

  1. Зарегистрируйте COM-компоненту той же версии платформы, что и сервер. Командная строка от имени администратора:
regsvr32 "C:\Program Files\1cv8\8.3.24.1548\bin\comcntr.dll"
  1. Разрядность должна совпадать: 64-битная программа видит только 64-битный comcntr.dll из Program Files, 32-битная — из Program Files (x86).
  2. У общего модуля с вызываемой функцией включите флаг «Внешнее соединение», у функции — Экспорт.

Номер версии в пути выше — пример. Подставьте каталог своей установленной платформы.

Вызов из другой базы 1С

Коннектор = Новый COMОбъект("V83.COMConnector");

// Клиент-серверная база
СтрокаСоединения = "Srvr=""srv-1c"";Ref=""buh_main"";Usr=""Обмен"";Pwd=""пароль"";";
// Файловая база: "File=""D:\Bases\Buh"";Usr=""Обмен"";Pwd=""пароль"";"

База = Коннектор.Connect(СтрокаСоединения);

Остаток = База.ОбменДанными.ОстатокТовара("00-00000123");
Сообщить("Остаток: " + Формат(Остаток, "ЧГ=0"));

Через объект База доступно почти всё, что видно во встроенном языке: База.Справочники.Номенклатура.НайтиПоКоду(...), База.НовыйЗапрос()… Но каждое обращение — межпроцессный вызов, поэтому медленно.

Правила, которые экономят время

  • 🎯 Считайте на стороне базы-источника. Одна функция общего модуля, которая возвращает готовую строку или число, работает в разы быстрее, чем цикл по COM-объектам.
  • 🔄 Возвращайте простые типы. Ссылки и коллекции приходят как COM-объекты чужой базы, напрямую в свою базу их не записать. Строка, число, дата, булево передаются без проблем.
  • 🔑 Заведите отдельного пользователя для внешнего соединения с ограниченными правами.

Вызов из внешней программы

Тот же коннектор доступен любому языку с поддержкой COM. Пример на Python с пакетом pywin32:

import win32com.client

connector = win32com.client.Dispatch("V83.COMConnector")
base = connector.Connect('Srvr="srv-1c";Ref="buh_main";Usr="Обмен";Pwd="пароль";')
print(base.ОбменДанными.ОстатокТовара("00-00000123"))

Если нужен открытый интерфейс 1С (окна, формы), вместо коннектора используют V83.Application — он запускает полноценный клиент. Для серверных расчётов это лишняя нагрузка.

HTTP-сервисы и JSON: вызов функций 1С по сети

HTTP-сервис позволяет внешней системе вызвать функцию 1С обычным запросом по адресу, без COM и без Windows на стороне клиента.

Публикация функции как HTTP-сервиса

  1. В конфигураторе в ветке Общие → HTTP-сервисы добавьте сервис, задайте корневой URL, например stock.
  2. Добавьте шаблон URL /item/{code} и метод GET. Платформа создаст функцию-обработчик в модуле сервиса.
  3. Опубликуйте базу на веб-сервере (Администрирование → Публикация на веб-сервере в конфигураторе) и отметьте сервис в списке HTTP-сервисов.

Обработчик:

Функция ItemGET(Запрос)
    Код = Запрос.ПараметрыURL["code"];
    Данные = Новый Структура("code, stock", Код, ОбменДанными.ОстатокТовара(Код));

    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    ЗаписатьJSON(Запись, Данные);

    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    Ответ.УстановитьТелоИзСтроки(Запись.Закрыть());
    Возврат Ответ;
КонецФункции

Адрес вызова строится так: https://сервер/имя_публикации/hs/stock/item/00-00000123. Сегмент hs добавляет сама платформа.

Вызов внешнего HTTP-сервиса из 1С

Обратная задача — из 1С вызвать чужой API и разобрать JSON-ответ:

Соединение = Новый HTTPСоединение("api.example.ru", 443, , , , 30,
    Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос("/v1/rates?currency=USD");
Ответ = Соединение.Получить(Запрос);

Если Ответ.КодСостояния = 200 Тогда
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
    Результат = ПрочитатьJSON(Чтение);   // Структура
    Чтение.Закрыть();
КонецЕсли;
  • 📤 Для POST-запроса используйте Соединение.ОтправитьДляОбработки(Запрос), тело задайте через Запрос.УстановитьТелоИзСтроки(...).
  • 🔤 Если ключи JSON не годятся в имена свойств структуры (дефисы, цифры в начале), читайте в соответствие: ПрочитатьJSON(Чтение, Истина).
  • ⏱ Шестой параметр HTTPСоединение — таймаут в секундах. Без него зависший сервер подвесит и сеанс 1С.

Динамический вызов: Вычислить, Выполнить и вызов по имени

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

ОператорЧто делаетПример
Вычислить(Выражение)Вычисляет выражение и возвращает значениеЦена = Вычислить("РаботаСЦенами." + ИмяМетода + "(Товар)");
Выполнить(Текст)Выполняет фрагмент кода, ничего не возвращаетВыполнить("Обработчики." + ИмяПроцедуры + "(Документ);");

Внутри строки доступны локальные переменные вызывающего метода. Поэтому Товар в примере берётся из контекста — параметры не нужно склеивать в строку.

В конфигурациях на БСП есть безопасная обёртка:

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

Для получения общего модуля по имени — ОбщегоНазначения.ОбщийМодуль("РаботаСЦенами"). Это нужно, когда модуля может не быть в конфигурации, а прямое обращение к нему вызвало бы ошибку при компиляции.

Никогда не передавайте в Выполнить строку, которую ввёл пользователь или прислала внешняя система. Это прямой путь к выполнению чужого кода. Если без этого никак, перед вызовом включите УстановитьБезопасныйРежим(Истина).

Минусы динамического вызова: синтаксический контроль конфигуратора ошибку в имени не найдёт, «Найти все ссылки» такой вызов не покажет, а при рефакторинге он сломается молча.

Ошибки при вызове функций и их обработка

Функция может упасть: нет связи, нет прав, битые данные. Чтобы один сбой не обрывал всю операцию, вызов оборачивают в Попытка:

Попытка
    Остаток = База.ОбменДанными.ОстатокТовара(Код);
Исключение
    Инфо = ИнформацияОбОшибке();
    ЗаписьЖурналаРегистрации("Обмен.ОстаткиCOM", УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(Инфо));
    Остаток = 0;
КонецПопытки;
  • 📝 ПодробноеПредставлениеОшибки даёт текст со стеком вызовов — его пишут в журнал регистрации.
  • 👤 КраткоеПредставлениеОшибки — для сообщения пользователю.
  • 🚨 Свою ошибку поднимают через ВызватьИсключение "Не задан склад";. Без текста внутри блока Исключение оператор пробрасывает исходную ошибку дальше.

В транзакции правило жёсткое: после ошибки транзакцию нужно отменить.

НачатьТранзакцию();
Попытка
    ЗаписатьДвижения(Документ);
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

Не глушите исключение молча (Исключение КонецПопытки без кода): ошибка исчезнет, а данные останутся наполовину записанными.

Что означают типичные сообщения

Диагностика: выберите симптом

Частые вопросы

Можно ли вызвать функцию модуля формы из общего модуля?
Напрямую нет. Передайте форму параметром и вызовите экспортный метод через неё: Форма.ОбновитьИтоги(). Чаще логику лучше перенести в общий модуль.
Чем Вычислить отличается от Выполнить?
Вычислить возвращает значение выражения, Выполнить выполняет операторы и ничего не возвращает. Для вызова функции по имени нужен Вычислить.
Почему COM-соединение работает медленно?
Каждое обращение к свойству или методу — отдельный межпроцессный вызов. Соберите расчёт в одну экспортную функцию на стороне базы и возвращайте простой результат.
Можно ли вызвать функцию 1С из Linux-системы?
Через COM нет, он есть только в Windows. Опубликуйте HTTP-сервис и вызывайте функцию обычным HTTP-запросом.
Как вызвать функцию асинхронно на клиенте?
С платформы 8.3.18 метод объявляют с Асинх и ждут результат через Ждать, например Ответ = Ждать ВопросАсинх(...). В старых версиях используют ОписаниеОповещения.