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