Вызов процедур и функций в 1С 8.3: от общего модуля до внешнего соединения
Содержание
Чтобы обратиться к функции в 1С, напишите её имя со скобками и присвойте результат переменной: Сумма = РассчитатьСкидку(Документ, 5);. Если функция лежит в другом модуле, у неё должно стоять слово Экспорт, а вызов идёт через имя модуля: РаботаСЦенами.РассчитатьСкидку(Документ, 5).
Типичная ситуация: программист дописал в общий модуль полезную функцию, вызвал её из формы документа — и получил Метод объекта не обнаружен. Почти всегда причина в одном из трёх мест: нет Экспорт, не тот контекст (клиент/сервер) или не выставлен флаг модуля. Те же правила видимости работают и дальше: во внешних обработках, при вызове через COM и HTTP, при динамическом вызове по имени.
Как устроен вызов процедуры и функции в 1С
Во встроенном языке два вида методов. Процедура выполняет действия и ничего не возвращает. Функция возвращает значение через Возврат.
Функция СуммаСНДС(Сумма, Ставка = 20) Экспорт
Возврат Сумма + Сумма * Ставка / 100;
КонецФункции
Процедура ПоказатьИтог(Сумма)
Сообщить("Итого: " + Формат(Сумма, "ЧДЦ=2"));
КонецПроцедуры
Вызов функции:
Итого = СуммаСНДС(1000); // 1200, ставка по умолчанию
Итого = СуммаСНДС(1000, 10); // 1100
ПоказатьИтог(Итого);
Что важно знать про параметры:
- 📌 По умолчанию параметры передаются по ссылке. Если функция изменит переменную-параметр, изменится и переменная в вызывающем коде.
- 🔒
Значперед именем параметра передаёт копию значения:Функция Проверить(Знач Код). - ➕ Необязательные параметры задают значением по умолчанию (
Ставка = 20). Их можно пропустить:СуммаСНДС(1000, )или простоСуммаСНДС(1000). - ↩️ Функцию можно вызвать как процедуру, без присваивания: результат просто отбросится.
Где лежит метод и как к нему обратиться
| Где объявлен метод | Как вызвать | Условие |
|---|---|---|
| Тот же модуль | ИмяМетода() | Объявлен выше или ниже — неважно |
| Общий модуль | ИмяМодуля.ИмяМетода() | Экспорт и подходящие флаги модуля |
| Модуль менеджера справочника | Справочники.Номенклатура.ИмяМетода() | Экспорт |
| Модуль объекта | СправочникОбъект.ИмяМетода() | Экспорт, сначала получить объект |
| Модуль формы | ЭтаФорма.ИмяМетода() или из другой формы через ссылку на форму | Экспорт для вызова снаружи |
| Глобальный общий модуль | ИмяМетода() без имени модуля | Флаг «Глобальный» |
Из модуля объекта к методу обращаются через сам объект: Объект = Ссылка.ПолучитьОбъект(); Объект.ЗаполнитьРеквизиты();. По ссылке метод модуля объекта не вызвать.
Клиент, сервер и флаги общего модуля
В управляемом приложении код выполняется либо на клиенте, либо на сервере. Функция, которая работает с базой (запросы, запись объектов), может жить только на сервере. Поэтому вызов «с формы» часто превращается в серверный вызов.
Директивы в модуле формы:
- 🖥
&НаКлиенте— метод работает на клиенте, к базе не обращается. - 🗄
&НаСервере— серверный вызов с передачей данных формы. Удобно, но тяжело: форма гоняется туда и обратно. - ⚡
&НаСервереБезКонтекста— серверный вызов без данных формы. Быстрее, но реквизиты формы внутри недоступны, их передают параметрами.
&НаКлиенте
Процедура Рассчитать(Команда)
Объект.Сумма = ПолучитьЦенуНаСервере(Объект.Номенклатура);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьЦенуНаСервере(Номенклатура)
Возврат РаботаСЦенами.ЦенаПоУмолчанию(Номенклатура);
КонецФункции
Флаги общего модуля в свойствах решают, откуда его видно:
| Флаг | Что даёт |
|---|---|
| Клиент (управляемое приложение) | Модуль доступен на клиенте |
| Сервер | Доступен в серверном коде |
| Вызов сервера | Клиент может напрямую вызвать его экспортные функции |
| Внешнее соединение | Доступен при подключении через COM |
| Привилегированный | Код выполняется без проверки прав |
| Глобальный | Методы вызываются без имени модуля |
Если с клиента нужно вызвать серверную функцию общего модуля напрямую, включите у модуля флаги «Сервер» и «Вызов сервера». Без второго флага клиентский код метод не увидит.
Ещё один частый случай — запуск функции в фоне. Метод для фонового задания должен быть экспортным и лежать в серверном общем модуле:
Параметры = Новый Массив;
Параметры.Добавить(Организация);
ФоновыеЗадания.Выполнить("ОбменДанными.ВыгрузитьОстатки", Параметры, , "Выгрузка остатков");
Вызов функций внешней обработки и внешнего отчёта
Внешняя обработка (.epf) — отдельный файл со своим модулем объекта. Её экспортные функции можно вызвать из кода конфигурации, не встраивая обработку в базу.
В клиент-серверной базе файл лежит на компьютере пользователя, а код выполняется на сервере. Поэтому файл сначала помещают во временное хранилище:
&НаКлиенте
Процедура ЗапуститьВнешнююОбработку(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмя, ДопПараметры) Экспорт
Если Результат Тогда
Сообщить(ВызватьФункциюОбработки(Адрес));
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВызватьФункциюОбработки(Адрес)
ИмяОбработки = ВнешниеОбработки.Подключить(Адрес, , Ложь);
Обработка = ВнешниеОбработки.Создать(ИмяОбработки, Ложь);
Возврат Обработка.ПосчитатьОстатки(ТекущаяДатаСеанса());
КонецФункции
Что здесь происходит:
НачатьПомещениеФайлапередаёт файл на сервер и возвращает адрес во временном хранилище.ВнешниеОбработки.Подключитьрегистрирует обработку в сеансе и возвращает её имя. Третий параметр — безопасный режим.ВнешниеОбработки.Создатьсоздаёт объект обработки.- Дальше вызывается экспортная функция из модуля объекта обработки:
Обработка.ПосчитатьОстатки(...).
Для отчётов то же самое делает ВнешниеОтчеты.Подключить и ВнешниеОтчеты.Создать.
Параметр Ложь отключает безопасный режим: код обработки получает доступ к файлам, COM и внешним ресурсам. Подключайте так только обработки, которым доверяете. Для чужого кода оставьте безопасный режим (Истина).
В типовых конфигурациях на БСП внешние обработки обычно подключают через справочник дополнительных отчётов и обработок: Администрирование → Печатные формы, отчеты и обработки → Дополнительные отчеты и обработки. Тогда в модуле обработки нужна экспортная функция СведенияОВнешнейОбработке(), которая описывает вид обработки и её команды.
Вызов функций 1С через COM-соединение
COM-соединение нужно, когда другая программа (или другая база 1С) должна вызвать функцию вашей базы без запуска окна клиента. Работает только под Windows.
Подготовка
- Зарегистрируйте COM-компоненту той же версии платформы, что и сервер. Командная строка от имени администратора:
regsvr32 "C:\Program Files\1cv8\8.3.24.1548\bin\comcntr.dll"
- Разрядность должна совпадать: 64-битная программа видит только 64-битный
comcntr.dllизProgram Files, 32-битная — изProgram Files (x86). - У общего модуля с вызываемой функцией включите флаг «Внешнее соединение», у функции —
Экспорт.
Номер версии в пути выше — пример. Подставьте каталог своей установленной платформы.
Вызов из другой базы 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-сервиса
- В конфигураторе в ветке
Общие → HTTP-сервисыдобавьте сервис, задайте корневой URL, напримерstock. - Добавьте шаблон URL
/item/{code}и методGET. Платформа создаст функцию-обработчик в модуле сервиса. - Опубликуйте базу на веб-сервере (
Администрирование → Публикация на веб-серверев конфигураторе) и отметьте сервис в списке 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-системы?
Как вызвать функцию асинхронно на клиенте?
Асинх и ждут результат через Ждать, например Ответ = Ждать ВопросАсинх(...). В старых версиях используют ОписаниеОповещения.