Почему возникает ошибка «Переменная не определена» при вызове общего модуля в 1С и как её исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Проанализируем исходную ситуацию и код

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

Код обработчика события на клиенте выглядит следующим образом:


&НаКлиенте
Процедура изделияКоличествоПриИзменении()
    СтрокаТаблицы = Элементы.Изделия.ТекущиеДанные;
    СобытияДокументов.ВычислитьСумму(СтрокаТаблицы);
КонецПроцедуры

Код в самом общем модуле СобытияДокументов:


Процедура ВычислитьСумму(СтрокаТаблицы) Экспорт
    СтрокаТаблицы.Сумма = СтрокаТаблицы.Количество * СтрокаТаблицы.Цена;
КонецПроцедуры

При проверке модуля формы или в режиме предприятия мы получаем ошибку компиляции: {Документ.ПриходнаяНакладная.Форма.ФормаДокумента.Форма(6,1)}: Переменная не определена (СобытияДокументов). Платформа воспринимает имя общего модуля как неизвестную переменную. Разберем, почему это происходит.

Разберем причину: флаги общих модулей и контекст выполнения

В архитектуре 1С:Предприятие 8.3 четко разделен контекст выполнения кода: клиент (управляемое приложение, веб-клиент) и сервер. Когда мы пишем код с директивой &НаКлиенте, платформа ожидает, что все вызываемые объекты и модули будут доступны именно в клиентском контексте.

Если код обращается к какому-либо имени (в нашем случае СобытияДокументов), и платформа не находит в текущем контексте ни локальной переменной, ни доступной функции, ни видимого общего модуля с таким именем, она выдает ошибку «Переменная не определена». Общий модуль может быть "невидим" для формы по нескольким причинам:

  1. Несоответствие контекста (отсутствуют нужные флажки). У модуля не стоят флажки контекста, из которого к нему обращаются. Например, форма работает на клиенте, а у модуля в палитре свойств установлен только флаг Сервер.
  2. Установлен флаг «Глобальный». Глобальные модули не вызываются по своему имени. Их экспортные процедуры становятся частью глобального контекста платформы и вызываются напрямую, без указания имени модуля (просто ВычислитьСумму()). Однако использовать глобальные модули без крайней необходимости категорически не рекомендуется.

Как правильно настроить общий модуль для решения проблемы

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

Шаги для решения:

  1. Откройте конфигуратор и найдите в дереве метаданных общий модуль СобытияДокументов.
  2. Откройте палитру свойств этого модуля.
  3. Проверьте, снят ли флаг Глобальный (он должен быть снят).
  4. Установите флаг Клиент (управляемое приложение). Если модуль используется и в серверных процедурах, можно оставить флаг Сервер.
  5. Сохраните конфигурацию и проверьте работу кода.

Если бы алгоритм требовал выполнения запросов к базе данных, нам пришлось бы оставить флаг Сервер и дополнительно установить флаг Вызов сервера, чтобы клиентский код мог "достучаться" до этого модуля. Но для простых математических операций это излишне.

Оптимизация передачи данных: работа со структурами

Рассмотрим еще один важный аспект, затронутый в обсуждении. В исходном коде переменная СтрокаТаблицы получает тип ДанныеФормыЭлементКоллекции и передается в процедуру общего модуля целиком.

Если процедура выполняется на клиенте, передача строки табличной части допустима. Однако, если бы мы вызывали серверную процедуру (с флагом Вызов сервера), передавать туда объекты интерфейса целиком — это плохая практика. Почему? Потому что это вызывает лишние затраты ресурсов на сериализацию (перевод объемных данных формы в формат для передачи по сети на сервер и обратно).

Правильный подход — создать структуру, поместить в нее только нужные для расчета данные, передать на сервер, а обратно получить готовый результат. Посмотрим на пример такого кода:


// В модуле формы на клиенте:
&НаКлиенте
Процедура изделияКоличествоПриИзменении(Элемент)
    СтрокаТЧ = Элементы.Изделия.ТекущиеДанные;
    
    // Создаем структуру только с необходимыми данными
    ДанныеДляРасчета = Новый Структура;
    ДанныеДляРасчета.Вставить("Количество", СтрокаТЧ.Количество);
    ДанныеДляРасчета.Вставить("Цена", СтрокаТЧ.Цена);
    
    // Вызываем серверную функцию (если расчет сложный)
    СтрокаТЧ.Сумма = ОбщийМодульСервер.РассчитатьСумму(ДанныеДляРасчета);
КонецПроцедуры

// В серверном общем модуле:
Функция РассчитатьСумму(ДанныеРасчета) Экспорт
    Возврат ДанныеРасчета.Количество * ДанныеРасчета.Цена;
КонецФункции

Проблема копеек при расчете НДС: как избежать погрешностей округления

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

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

Как эта задача решается в типовых конфигурациях 1С:

  1. Сначала рассчитывается общая сумма документа и от неё исчисляется общая «правильная» сумма НДС документа.
  2. Затем рассчитывается НДС построчно и округляется.
  3. Сумма НДС по строкам суммируется.
  4. Вычисляется разница между общим НДС документа и суммой построчного НДС.
  5. Эта разница (погрешность округления) прибавляется или вычитается из строки с максимальной суммой (или, в некоторых случаях, из последней строки документа, если у нее не нулевая цена).

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

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

← На главную