В процессе разработки на платформе 1С:Предприятие 8.3 начинающие специалисты часто сталкиваются с классической ошибкой: попыткой обратиться к менеджеру справочников или документов непосредственно из клиентского контекста управляемой формы. Типичный сценарий — желание заполнить реквизит формы значением по умолчанию сразу при ее открытии. Давайте подробно разберем, почему возникает популярная ошибка «Переменная не определена (Справочники)», как устроено клиент-серверное взаимодействие и какие современные методики существуют для решения этой задачи.
Рассмотрим ситуацию, с которой началась дискуссия на форуме. Разработчик добавил на форму реквизит Контрагент1 с типом СправочникСсылка.Контрагенты и попытался инициализировать его в обработчике события открытия формы:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Контрагент1 = Справочники.Контрагенты.НайтиПоНаименованию("ООО ...", Истина);
КонецПроцедуры
При запуске этого кода система возвращает ошибку компиляции. Выясним причину ее возникновения. В управляемом приложении 1С действует жесткое разделение контекста на клиентский и серверный:
&НаКлиенте): Выполняется на компьютере пользователя. Его задача — отображение интерфейса, взаимодействие с пользователем и простейшие вычисления. На клиенте физически отсутствуют и недоступны менеджеры прикладных объектов баз данных, такие как Справочники, Документы, РегистрыСведений и другие. Именно поэтому обращение к объекту Справочники вызывает ошибку «Переменная не определена».&НаСервере, &НаСервереБезКонтекста): Выполняется на стороне сервера приложений 1С или СУБД. Только здесь доступны прямые запросы к базе данных, объектные менеджеры, выборки и поиск элементов.Золотое правило разработки управляемых форм: Любое чтение данных, поиск элементов или обращение к объектной модели должны происходить исключительно в серверном контексте.
В кодовой базе начинающих разработчиков часто встречается конструкция Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка"). Настоятельно рекомендуем отказаться от использования этого метода для жесткого кодирования логики по следующим причинам:
Проанализируем правильные альтернативные подходы, которые соответствуют стандартам разработки фирмы «1С».
Самый простой и логичный способ заполнить реквизиты формы при ее первом открытии — использовать стандартный обработчик события ПриСозданииНаСервере. На сервере у нас есть полный доступ ко всей объектной модели базы данных.
Рассмотрим пример правильной реализации:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, что это новый объект (если реквизит принадлежит объекту формы)
Если Объект.Ссылка.Пустая() Тогда
// Выполняем поиск на сервере. В реальном коде лучше использовать более надежные способы поиска!
НайденныйКонтрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО НазваниеКонтрагента", Истина);
Если ЗначениеЗаполнено(НайденныйКонтрагент) Тогда
Объект.Контрагент1 = НайденныйКонтрагент;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ решает проблему доступности менеджера справочников, однако сам по себе поиск по строке все еще остается уязвимым местом.
В платформе 1С 8.3 существует элегантный декларативный метод автоматического заполнения реквизитов объектов, который не требует написания кода вообще.
Выполним следующие шаги в Конфигураторе:
Организация или СтавкаНДС).При создании нового объекта на форме данное поле будет заполняться автоматически силами самой платформы.
Если форма открывается программно из другого места конфигурации (например, из списка или другой формы), наиболее правильным решением будет передать нужное значение через параметры заполнения.
Рассмотрим, как это реализовать. Сначала напишем код вызова на клиенте в исходной форме:
&НаКлиенте
Процедура ОткрытьФормуДокументаСЗаполнением()
// Формируем структуру параметров. Ключ "ЗначениеЗаполнения" обрабатывается платформой автоматически
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Контрагент1", СсылкаНаНужногоКонтрагента);
ПараметрыФормы = Новый Структура("ЗначениеЗаполнения", ПараметрыЗаполнения);
ОткрытьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);
КонецПроцедуры
В открываемой форме в модуле объекта (в обработчике события ОбработкаЗаполнения) платформа автоматически подставит переданные значения в соответствующие реквизиты объекта.
Если же вам требуется вручную обработать параметры в самой форме, используйте следующий серверный код:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ЗначениеЗаполнения") Тогда
// Извлекаем переданные данные и заполняем реквизит формы
Объект.Контрагент1 = Параметры.ЗначениеЗаполнения;
КонецЕсли;
КонецПроцедуры
Если вам необходимо жестко привязаться к конкретному элементу базы данных, который создается пользователями в режиме «1С:Предприятие» и не является предопределенным в конфигураторе, воспользуйтесь поиском по уникальному идентификатору (GUID/UUID).
Разберем этот надежный способ по шагам:
"123e4567-e89b-12d3-a456-426614174000".
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Ссылка.Пустая() Тогда
// Создаем объект уникального идентификатора из строки
Идентификатор = Новый УникальныйИдентификатор("123e4567-e89b-12d3-a456-426614174000");
// Получаем прямую ссылку на элемент справочника Контрагенты
Объект.Контрагент1 = Справочники.Контрагенты.ПолучитьСсылка(Идентификатор);
КонецЕсли;
КонецПроцедуры
Преимущество метода: Даже если пользователи базы данных полностью переименуют этого контрагента или изменят любые его реквизиты, его уникальный идентификатор останется неизменным. Код продолжит стабильно работать в любых условиях.
Если целевой элемент является системным и жизненно важным для работы бизнес-логики (например, служебный контрагент «Розничный покупатель» или «Основной склад»), его следует создать в конфигураторе как предопределенный элемент справочника.
Для получения таких значений платформа предоставляет встроенную функцию ПредопределенноеЗначение, которая уникальна тем, что доступна в том числе и на клиенте (&НаКлиенте) без лишних вызовов сервера.
Посмотрим на пример клиентского кода:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Инициализируем реквизит предопределенным элементом напрямую на клиенте
Если Не ЗначениеЗаполнено(Контрагент1) Тогда
Контрагент1 = ПредопределенноеЗначение("Справочник.Контрагенты.РозничныйПокупатель");
КонецЕсли;
КонецПроцедуры
Важное предостережение: Не стоит злоупотреблять созданием сотен предопределенных элементов для обычных пользовательских данных. Предопределенные элементы усложняют процесс обновления конфигураций и должны создаваться только для статичных системных справочников (ставки НДС, базовые валюты, типы цен).
В современных конфигурациях, построенных на базе Библиотеки стандартных подсистем (БСП), жесткое кодирование конкретных значений в программном коде считается грубым нарушением стандартов разработки. Вместо этого используется механизм персональных настроек пользователя.
Проанализируем стандартную логику интеграции таких настроек:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Ссылка.Пустая() Тогда
// Пример вызова механизмов БСП для получения настроек текущего пользователя
Объект.Организация = УправлениеНастройкамиСистемы.ПолучитьНастройкуПоУмолчанию("ОсновнаяОрганизация");
КонецЕсли;
КонецПроцедуры
Этот подход является наиболее гибким, масштабируемым и профессиональным, так как позволяет конечным пользователям самостоятельно настраивать рабочие места без привлечения программистов для изменения исходного кода.