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