Своя функция в коде 1С 8.3: где её объявить и как вызвать из любого места
Содержание
Чтобы вставить функцию в 1С, откройте нужный модуль в Конфигураторе (или в расширении), поставьте курсор вне других процедур и напишите блок Функция Имя(Параметры) … КонецФункции с хотя бы одним оператором Возврат. Если функцию будут вызывать из других модулей, добавьте после скобок слово Экспорт и положите её в общий модуль.
Частая ошибка новичков — написать функцию прямо в модуле формы, а потом пытаться вызвать её из документа или другой обработки. Код формы виден только самой форме. Место размещения решает почти всё: от него зависит, откуда функцию видно и на какой стороне (клиент или сервер) она выполнится.
С чего начать: в какой модуль вставить функцию
В 1С 8.3 нет «просто файла с кодом». Каждая функция живёт в каком-то модуле, и у каждого модуля своя зона видимости.
| Модуль | Откуда видна функция | Когда выбирать |
|---|---|---|
| Модуль формы | Только из этой формы | Обработка кнопок, заполнение реквизитов формы |
| Модуль объекта (документа, справочника) | Из объекта через точку: ДокументОбъект.Имя() | Логика конкретного объекта: заполнение, проверки перед записью |
| Модуль менеджера | Через менеджер: Документы.Реализация.Имя() | Действия без конкретного экземпляра: поиск, печать, общий расчёт |
| Общий модуль | Из любого места конфигурации: ИмяМодуля.Имя() | Функции, которые нужны в нескольких местах |
| Модуль сеанса, приложения | Ограниченно | Почти никогда для прикладных функций |
Общий модуль создаётся в дереве конфигурации: ветка Общие → Общие модули, правой кнопкой — «Добавить». Сразу задайте имя без пробелов, например РаботаСКонтрагентамиСервер.
В свойствах общего модуля стоят флажки, которые определяют, где он компилируется:
- 🖥️ Сервер — код выполняется на сервере, есть доступ к базе и запросам;
- 💻 Клиент (управляемое приложение) — код доступен на клиенте;
- 🔁 Вызов сервера — серверные функции можно вызывать с клиента;
- ⚙️ Привилегированный — код работает без проверки прав пользователя;
- 🌐 Глобальный — функции вызываются без имени модуля.
Типовые конфигурации называют общие модули по суффиксу: …Сервер, …Клиент, …ВызовСервера, …КлиентСервер. Следуйте той же схеме — через полгода вы сразу поймёте, где что лежит.
Не правьте типовую конфигурацию на поддержке без нужды. Свою функцию надёжнее положить в расширение: при обновлении типовой код заменится, а расширение останется.
Как записать функцию: синтаксис объявления и параметры
Каркас функции во встроенном языке 1С:
Функция СуммаСНДС(Знач Сумма, Знач СтавкаПроцент = 20) Экспорт
Результат = Сумма + Сумма * СтавкаПроцент / 100;
Возврат Окр(Результат, 2);
КонецФункции
Разберём строку объявления по частям:
Функция— ключевое слово. Можно писать иFunction, оба варианта равноправны.СуммаСНДС— имя. Без пробелов, начинается с буквы или подчёркивания.(Знач Сумма, …)— список параметров через запятую.= 20— значение по умолчанию. Такой параметр при вызове можно пропустить.Экспорт— функция видна из других модулей.
Необязательные параметры ставьте в конец списка. Пропустить параметр в середине тоже можно, через пустое место между запятыми: Имя(1, , 3). Но читать такой вызов тяжело.
Знач: передача по значению и по ссылке
По умолчанию 1С передаёт параметры по ссылке. Если функция присвоит параметру новое значение, оно изменится и у вызывающего кода. Это частый источник странных ошибок.
Функция Удвоить(Число)
Число = Число * 2; // изменит переменную у вызывающего
Возврат Число;
КонецФункции
Слово Знач перед параметром делает копию. Внутри функции с ней можно делать что угодно, снаружи ничего не поменяется.
Знач копирует только саму переменную. Если передать таблицу значений или структуру, функция получит ссылку на тот же объект. Добавленные в таблицу строки увидит и вызывающий код.
Функция или процедура
Разница одна: функция возвращает значение, процедура — нет.
| Функция | Процедура | |
|---|---|---|
| Ключевые слова | Функция … КонецФункции | Процедура … КонецПроцедуры |
Возврат | Обязательно со значением | Без значения, просто выход |
| Вызов в выражении | А = Имя() | Нельзя |
| Вызов отдельной строкой | Можно, результат отбросится | Можно |
Если результат не нужен, пишите процедуру. Функция без смыслового возврата только путает.
Директивы компиляции: где выполнится вставленная функция
В модуле формы перед каждой функцией ставится директива. Она говорит платформе, на какой стороне выполнять код.
| Директива | Где выполняется | Доступ к форме | Доступ к базе |
|---|---|---|---|
&НаКлиенте | Клиент | Да | Нет |
&НаСервере | Сервер | Да, данные формы передаются на сервер | Да |
&НаСервереБезКонтекста | Сервер | Нет | Да |
&НаКлиентеНаСервереБезКонтекста | Там, откуда вызвали | Нет | Зависит от стороны |
Пример: кнопка на клиенте получает остаток через быструю серверную функцию.
&НаКлиенте
Процедура ПоказатьОстаток(Команда)
Остаток = ОстатокНоменклатуры(Объект.Номенклатура);
Сообщить("Остаток: " + Формат(Остаток, "ЧДЦ=3; ЧН=0"));
КонецПроцедуры
&НаСервереБезКонтекста
Функция ОстатокНоменклатуры(Номенклатура)
// Здесь запрос к регистру остатков
Возврат 0;
КонецФункции
&НаСервереБезКонтекста работает заметно быстрее &НаСервере: на сервер не уходят данные всей формы. Если функции не нужны реквизиты формы, выбирайте её.
В модулях объектов и менеджеров директивы не пишут: эти модули и так серверные. В общих модулях директивы тоже не нужны, сторону определяют флажки в свойствах модуля.
Видимость переменных внутри и снаружи функции
Переменная, впервые получившая значение внутри функции, локальная. После КонецФункции её нет.
Функция Пример()
Счетчик = 0; // локальная переменная
Перем Итог; // тоже локальная, объявлена явно
Итог = Счетчик + 1;
Возврат Итог;
КонецФункции
Переменные модуля объявляются в самом начале модуля, до всех процедур, через Перем:
Перем КэшКурсов; // видна во всех функциях этого модуля
Перем РежимЗагрузки Экспорт; // видна и снаружи, через объект
Правила, которые стоит держать в голове:
- 📌 В общих модулях переменные уровня модуля объявлять нельзя. Нужно хранить значение между вызовами — используйте параметры сеанса или повторное использование возвращаемых значений.
- 📌 Переменная модуля формы с
&НаКлиентена сервере недоступна, и наоборот. - 📌 Имя локальной переменной, совпадающее с переменной модуля, перекроет её внутри функции.
Кэширование результата
У общего модуля есть свойство «Повторное использование возвращаемых значений». Варианты: «На время вызова» и «На время сеанса». Функция такого модуля при повторном вызове с теми же параметрами вернёт сохранённый результат без выполнения.
Это удобно для настроек и констант, которые редко меняются. Для данных, которые меняются в течение дня, это ловушка: пользователь увидит устаревшее значение.
Что возвращает функция: Возврат и типы значений
Функция возвращает значение оператором Возврат. После него код функции дальше не выполняется.
Встроенный язык 1С не требует указывать тип результата. Функция может вернуть число, строку, дату, ссылку, Неопределено, структуру или таблицу. Компилятор тип не проверяет, поэтому за порядком следите сами.
Несколько практических правил:
- Один тип на выходе. Если функция ищет контрагента, пусть возвращает ссылку или
Неопределено, а не то ссылку, то строку с ошибкой. - Несколько значений — через структуру.
- Пустая ссылка и Неопределено — разные вещи. Проверку пишите под то, что реально возвращаете.
- Каждая ветка с Возвратом. Если
Возвратстоит только внутриЕсли, при невыполненном условии функция вернётНеопределено.
Пример возврата нескольких значений:
Функция ПроверитьИНН(Знач ИНН) Экспорт
Результат = Новый Структура("Корректен, Текст", Истина, "");
ИНН = СокрЛП(ИНН);
Если СтрДлина(ИНН) <> 10 И СтрДлина(ИНН) <> 12 Тогда
Результат.Корректен = Ложь;
Результат.Текст = СтрШаблон("ИНН должен содержать 10 или 12 цифр, сейчас %1", СтрДлина(ИНН));
КонецЕсли;
Возврат Результат;
КонецФункции
Вызов и разбор результата:
Проверка = ПроверкаРеквизитов.ПроверитьИНН(Объект.ИНН);
Если Не Проверка.Корректен Тогда
Сообщить(Проверка.Текст);
КонецЕсли;
Между клиентом и сервером передаются только сериализуемые значения: примитивы, ссылки, структуры, массивы. Объект документа, ТаблицаЗначений и Запрос с сервера на клиент вернуть нельзя. Таблицу превратите в массив структур.
Как вызвать функцию из существующего кода
Способ вызова зависит от места, где функция лежит.
| Где функция | Как вызвать |
|---|---|
| Тот же модуль | Имя(Параметры) |
| Общий модуль | ИмяОбщегоМодуля.Имя(Параметры) |
| Глобальный общий модуль | Имя(Параметры) |
| Модуль объекта | ДокОбъект = Ссылка.ПолучитьОбъект(); ДокОбъект.Имя() |
| Модуль менеджера | Документы.ИмяДокумента.Имя() или Справочники.ИмяСправочника.Имя() |
Во всех вариантах, кроме вызова из того же модуля, функция должна быть объявлена с Экспорт.
Порядок действий в Конфигураторе
- Откройте модуль: двойной клик по объекту в дереве, вкладка «Прочее» → «Модуль объекта» или «Модуль менеджера». Для общего модуля — двойной клик по нему.
- Поставьте курсор между двумя
КонецПроцедуры/Процедура, не внутри чужого блока. - Напишите функцию. Подсказка по встроенным функциям —
Ctrl+Пробел, по параметрам —Ctrl+Shift+Пробел. - Проверьте синтаксис:
Ctrl+F7. - Сохраните конфигурацию и обновите конфигурацию базы данных (
F7). Без этого шага пользователи изменений не увидят.
Чтобы быстро найти функцию в длинном модуле, откройте список процедур и функций модуля: кнопка на панели модуля или Ctrl+Alt+P.
Функция в расширении
В расширении можно не только добавить свою функцию, но и вмешаться в типовую. Для этого в расширение заимствуют объект, открывают его модуль и ставят аннотацию перед своей функцией:
&Перед("ИмяТиповой")— ваш код выполнится до типовой функции;&После("ИмяТиповой")— после;&Вместо("ИмяТиповой")— вместо неё; внутри можно вызвать оригинал черезПродолжитьВызов();&ИзменениеИКонтроль("ИмяТиповой")— копия типового кода с вашими вставками#Вставка … #КонецВставки. Если при обновлении типовой код поменяется, платформа сообщит об этом.
Аннотация &ИзменениеИКонтроль есть только в новых версиях платформы, начиная с 8.3.16. На более старых используйте &Вместо с ПродолжитьВызов().
После правки расширения его сохраняют и обновляют в базе отдельно: команда «Обновить конфигурацию базы данных» в окне расширения.
Отладка и типичные ошибки при создании функции
Проверить, что функция работает, проще всего отладчиком:
- Поставьте точку останова на первой строке функции:
F9. - Запустите отладку:
F5. - Выполните действие, которое вызывает функцию.
- Когда выполнение остановится, смотрите значения в табло или вызовите
Shift+F9— «Вычислить выражение». - Шаг с заходом в функцию —
F11, шаг через строку —F10.
Для серверного кода в клиент-серверной базе нужна отладка на сервере. Её включают параметром -debug у службы агента кластера, это делает администратор сервера.
Ещё две ошибки не дают сообщений, но портят данные:
- 🐞 Изменение параметра без Знач. Функция «почистила» строку, а у вызывающего кода тоже пропали пробелы или поменялась сумма.
- 🐞 Вызов сервера в цикле. Каждая итерация — отдельный запрос на сервер. Сто строк дают сто вызовов и заметную задержку. Соберите данные в массив и отправьте одним вызовом.