При разработке в среде 1С часто возникает задача автоматизации ввода данных. Одной из популярных задач является заполнение реквизитов нового объекта на основании контекста его создания. Например, когда пользователь заходит в папку «Услуги» и нажимает кнопку «Создать», система должна автоматически понять, что новый элемент является услугой, и установить соответствующий ВидНоменклатуры. В этой статье мы разберем, почему стандартные попытки решить это через запросы могут не работать, и как реализовать задачу правильно и эффективно.
Рассмотрим ситуацию, с которой часто сталкиваются начинающие программисты. Попытка написать запрос ко всему справочнику Номенклатура при открытии формы создания нового элемента является в корне неверной. Проанализируем код, который часто приводит к ошибкам:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Родитель.Наименование КАК РодительНаименование,
| Номенклатура.Вид КАК Вид
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
РезультатЗапроса = Запрос.Выполнить;
ВыборкаТовары = РезультатЗапроса.Выбрать();
Пока ВыборкаТовары.Следующий() Цикл
Если ВыборкаТовары.РодительНаименование = "Услуги" Тогда
Объект.Вид = Перечисления.ВидыНоменклатуры.Услуга;
КонецЕсли;
КонецЦикла;
Почему этот подход не работает:
Объект.Вид (который является единственным реквизитом текущего создаваемого объекта) постоянно перезаписывается значением из каждой строки выборки. В итоге в реквизите останется значение из самой последней строки запроса, независимо от того, в какой папке вы находитесь.Самый простой и быстрый способ решить задачу «в лоб» для управляемых форм — использовать процедуру ПриСозданииНаСервере в модуле формы элемента. Рассмотрим, как это сделать правильно, учитывая контекст нового объекта.
Для того чтобы код срабатывал только при создании нового элемента (а не при открытии уже существующего), необходимо проверять ключ объекта. Если Параметры.Ключ пуст, значит, мы создаем новый элемент.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, что это новый объект, а не открытие существующей карточки
Если Параметры.Ключ.Пустая() Тогда
// В 1С при создании элемента в папке, родитель подставляется автоматически
// Мы можем просто проверить его наименование
Если Объект.Родитель.Наименование = "Услуги" Тогда
Объект.Вид = ПредопределенноеЗначение("Перечисление.ВидыНоменклатуры.Услуга");
ИначеЕсли Объект.Родитель.Наименование = "Товары" Тогда
Объект.Вид = ПредопределенноеЗначение("Перечисление.ВидыНоменклатуры.Товар");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Разберем важные моменты этого кода:
Параметры.Ключ.Пустая() — это критически важная проверка. Без нее при каждом открытии уже созданного товара программа будет пытаться изменить его вид, что может привести к порче данных.ПредопределенноеЗначение() — функция, позволяющая обращаться к элементам перечислений или предопределенным данным, которая работает корректно и в тонком клиенте, и на сервере.Хотя решение в форме работает, оно имеет недостаток: если номенклатура будет создаваться программно (например, загрузкой из файла), код формы не сработает. Поэтому правила «хорошего тона» в 1С диктуют перенос логики заполнения в Модуль объекта.
Выясним, как работает процедура ОбработкаЗаполнения. Она вызывается автоматически при создании нового объекта. В параметр ДанныеЗаполнения система передает ссылку на родительскую папку, если создание происходит из списка с установленным фильтром или иерархией.
// В модуле объекта Справочника Номенклатура
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Если мы создаем элемент внутри группы,
// в ДанныеЗаполнения может прийти ссылка на Родителя или Структура
Если ТипЗнч(ДанныеЗаполнения) = Тип("СправочникСсылка.Номенклатура") Тогда
РодительСсылка = ДанныеЗаполнения;
ИначеЕсли ТипЗнч(ДанныеЗаполнения) = Тип("Структура") И ДанныеЗаполнения.Свойство("Родитель") Тогда
РодительСсылка = ДанныеЗаполнения.Родитель;
Иначе
Возврат;
КонецЕсли;
// Проверяем наименование родителя
Если РодительСсылка.Наименование = "Услуги" Тогда
ЭтотОбъект.Вид = Перечисления.ВидыНоменклатуры.Услуга;
ИначеЕсли РодительСсылка.Наименование = "Товары" Тогда
ЭтотОбъект.Вид = Перечисления.ВидыНоменклатуры.Товар;
КонецЕсли;
КонецПроцедуры
Проанализируем риски использования сравнения по строке (Наименование = "Услуги"). Это крайне хрупкое решение. Если завтра пользователь переименует папку в «Услуги компании» или случайно поставит лишний пробел в конце, ваш код перестанет работать. Профессионалы рекомендуют следующие альтернативы:
Если Родитель = Справочники.Номенклатура.ПапкаУслуги Тогда....Родитель.Наименование не сработает для вложенных папок. В таких случаях в запросах или коде используют проверку ПринадлежитЭлементу(ГруппаУслуг) или аналогичные методы поиска в иерархии.Подводя итог, отметим, что для учебных задач и простых конфигураций достаточно проверки в ПриСозданииНаСервере. Однако всегда помните о производительности системы: избегайте циклов по всему справочнику там, где можно обратиться к конкретному свойству текущего объекта.