Почему переменная в процедуре 1С возвращает Неопределено и как правильно передать значение из функции

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Причина 1: Жесткая сигнатура обработчиков команд

Первое, на что нам стоит обратить внимание, — это объявление процедуры ИС_СоздатьЗаказНаПроизводствоПосле(Команда, Орг). Если эта процедура назначена обработчиком команды на форме (кнопки), то платформа 1С ожидает строго определенное количество параметров. Для команды это всегда **один** параметр — Команда.

Рассмотрим подробнее: когда пользователь нажимает на кнопку, платформа сама вызывает процедуру и передает в нее объект команды. Платформа ничего не знает о вашей переменной Орг и не может её туда «пробросить». В итоге второй параметр инициализируется значением Неопределено по умолчанию. Нам необходимо убрать лишний параметр из заголовка процедуры и получать значение внутри её тела.


// Неправильно
&НаКлиенте
Процедура ИС_СоздатьЗаказНаПроизводствоПосле(Команда, Орг) 

// Правильно
&НаКлиенте
Процедура ИС_СоздатьЗаказНаПроизводствоПосле(Команда)
    // Переменную получаем здесь
    Орг = ПоискОрганизации();
    // Далее работаем с переменной Орг
КонецПроцедуры

Причина 2: Отсутствие явного вызова функции

Проанализируем исходный код автора. В тексте сообщения переменная Орг просто фигурирует в параметрах процедуры, но сама функция ПоискОрганизации внутри процедуры не вызывается. Программирование в 1С не предполагает автоматической связи между именами переменных в разных методах. Чтобы результат функции попал в процедуру, мы должны явно присвоить результат вызова функции переменной.

Выясним причину, почему это важно: функция ПоискОрганизации помечена директивой &НаСервере. Это означает, что при её вызове происходит контекстный переход с клиента на сервер. Без явной команды Переменная = Функция(); этот переход не случится, и данные не будут получены.

Причина 3: Особенности работы расширений и аннотации &После

Судя по префиксу ИС_ и постфиксу После, используется механизм расширений конфигурации. При использовании аннотации &После крайне важно, чтобы сигнатура (количество и порядок параметров) вашей процедуры в расширении **полностью совпадала** с сигнатурой оригинальной процедуры в основной конфигурации.

Если в типовой конфигурации процедура СоздатьЗаказНаПроизводство принимает только один параметр Команда, то добавление второго параметра в расширении приведет к тому, что код либо вообще не выполнится, либо (как в нашем случае) дополнительный параметр будет проигнорирован платформой и останется Неопределено.

Причина 4: Инициализация возвращаемого значения в функции

Посмотрим на код функции ПоискОрганизации. Там используется конструкция Перем Орг;. В языке 1С это означает, что переменная создана, но её значение изначально равно Неопределено.


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

Разберем, как сделать код более надежным. Хорошим тоном считается инициализация переменной конкретным типом в самом начале. Если мы ожидаем булево значение (Истина/Ложь), то лучше сразу присвоить Ложь. Тогда функция всегда будет возвращать предсказуемый результат, а не Неопределено.


&НаСервере
Функция ПоискОрганизации()
    Орг = Ложь; // Инициализация
    Запрос = Новый Запрос;
    // ... текст запроса ...
    РезультатЗапроса = Запрос.Выполнить();
    Если Не РезультатЗапроса.Пустой() Тогда
        Орг = Истина;
    КонецЕсли;
    Возврат Орг;
КонецФункции

Причина 5: Данные в базе против данных на форме

В коде функции используется запрос к таблице Документ.ЗаказПоставщику с фильтром по Объект.Ссылка. Проанализируем ситуацию: если пользователь только что создал документ, заполнил организацию, но еще **не нажал кнопку Записать**, то в базе данных этого документа еще нет (или там старые данные). Запрос по Объект.Ссылка вернет пустой результат, так как ссылка еще не сформирована или указывает на пустой объект.

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


&НаСервере
Функция ПоискОрганизации()
    // Проверяем данные прямо в объекте формы, не обращаясь к БД
    НаименованиеОрг = Объект.Организация.Наименование;
    Если Найти(НаименованиеОрг, "ООО") > 0 Тогда
        Возврат Истина;
    Иначе
        Возврат Ложь;
    КонецЕсли;
КонецФункции

Итоговое правильное решение

Соберем все рекомендации воедино и напишем корректный код для модуля формы. Рассмотрим пошагово: мы исправляем сигнатуру, добавляем явный вызов функции и обеспечиваем инициализацию значений.


&НаКлиенте
Процедура ИС_СоздатьЗаказНаПроизводствоПосле(Команда)
    
    // 1. Явно вызываем функцию и получаем результат
    ОрганизацияНайдена = ПоискОрганизации();
    
    // 2. Обрабатываем результат
    Если ОрганизацияНайдена Тогда
        Сообщить("Нужная организация найдена!");
    Иначе
        Сообщить("Организация не соответствует условиям.");
    КонецЕсли;

    // 3. Логика открытия формы нового документа
    Если ЗначениеЗаполнено(Объект.Ссылка) Тогда
        ПараметрыФормы = Новый Структура("Основание", Объект.Ссылка);
        ОткрытьФорму("Документ.ЗаказНаПроизводство.ФормаОбъекта", ПараметрыФормы);
    Иначе
        Сообщить("Пожалуйста, сначала запишите документ!");
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Функция ПоискОрганизации()
    
    // Проверяем, записан ли документ, чтобы запрос имел смысл
    Если Объект.Ссылка.Пустая() Тогда
        // Если не записан, проверяем данные напрямую из реквизитов формы
        Возврат СтрНайти(Объект.Организация.Наименование, "ООО") > 0;
    КонецЕсли;
    
    // Если документ в базе, можно использовать запрос
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ИСТИНА КАК Результат
        |ИЗ
        |   Документ.ЗаказПоставщику КАК ЗаказПоставщику
        |ГДЕ
        |   ЗаказПоставщику.Ссылка = &Ссылка
        |   И ЗаказПоставщику.Организация.Наименование ПОДОБНО &Организация";
    
    Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
    Запрос.УстановитьПараметр("Организация", "%ООО%");
    
    РезультатЗапроса = Запрос.Выполнить();
    Возврат Не РезультатЗапроса.Пустой();
    
КонецФункции

Таким образом, мы решили проблему Неопределено, обеспечили корректную передачу данных между клиентом и сервером и сделали код устойчивым к ситуациям, когда документ еще не записан в базу данных. Помните, что в управляемом приложении четкое разделение контекста и понимание жизненного цикла команды — залог отсутствия подобных ошибок.

← На главную