Как исправить ошибку Значение не является значением объектного типа Защита при печати в 1С

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

При доработке типовых или отраслевых печатных форм (например, в конфигурациях на базе БСП или отраслевых решениях вроде 1С:Управление автотранспортом) разработчики нередко сталкиваются с ошибкой времени выполнения: «Значение не является значением объектного типа "Защита"». Ошибка возникает в сервисных процедурах постобработки табличных документов, например, в УстановитьРедактированиеПечатныхФормДокумента.

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

Причина возникновения ошибки Защита

Рассмотрим типовой механизм работы подсистемы печати. Функция формирования печатной формы вызывается общим механизмом печати и обязана вернуть готовый объект типа ТабличныйДокумент (либо заполнить структуру/коллекцию печатных форм, где в поле ТабличныйДокумент содержится соответствующий объект).

После вызова функции модуль печати выполняет сервисные процедуры, например:


Для Каждого ТекПечФорма Из КоллекцияПечатныхФорм Цикл
    ТекПечФорма.ТабличныйДокумент.Защита = ЗащитаПечФорм;
    ТекПечФорма.ТабличныйДокумент.ТолькоПросмотр = ТолькоПросмотрПечФорм;
КонецЦикла;

Если в процессе разработки внутри тела функции печати был случайно оставлен промежуточный оператор Возврат (например, Возврат КонтрагентИКонтактноеЛицо; для отладки), функция завершает свою работу раньше времени и возвращает значение строкового или иного типа вместо объекта ТабличныйДокумент.

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

Пошаговое исправление ошибки и доработка макета

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

  1. Удаление некорректного возврата: исключим из функции промежуточные операторы Возврат, убедившись, что функция возвращает только заполненный ТабличныйДокумент в самом конце.
  2. Вынесение получения данных в отдельную функцию или запрос: получение данных контрагента и контактной информации не должно разрывать основной алгоритм формирования макета.
  3. Фильтрация запроса по ссылке на документ: запросы не должны выбирать всю таблицу документов без условий. Обязательно используем блок ГДЕ с параметром текущего документа.
  4. Форматирование контактных данных: формируем итоговую строку только из тех реквизитов, которые фактически заполнены в базе.

Вариант 1. Получение контактных данных через отдельную функцию

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


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

В основном теле функции формирования печатной формы передаем полученную строку в параметры макета:


ОбластьМакетаШапка.Параметры.ПредставлениеЗаказчика = ПолучитьПараметрыЗаказчика(ТекущийДокумент);

Вариант 2. Прямое получение номера телефона через запрос к контактной информации

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	КонтактнаяИнформация.НомерТелефонаБезКодов КАК Телефон
    |ИЗ
    |	Справочник.Контрагенты.КонтактнаяИнформация КАК КонтактнаяИнформация
    |ГДЕ
    |	КонтактнаяИнформация.Ссылка = &Контрагент";

Запрос.УстановитьПараметр("Контрагент", ТекущийКонтрагент);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Телефон = "";
Если Выборка.Следующий() Тогда
    Телефон = Выборка.Телефон;
КонецЕсли;

Вариант 3. Компактная сборка строки параметров с помощью тернарного оператора

Посмотрим на альтернативный способ конкатенации строки сведений о клиенте с использованием встроенной проверки ЗначениеЗаполнено:


ИнфоКонтрагент = "" + Выборка.Контрагент.Наименование
    + ?(ЗначениеЗаполнено(Выборка.КонтактноеЛицо), ", Контактное лицо: " + Выборка.КонтактноеЛицо, "")
    + ?(ЗначениеЗаполнено(Телефон), ", Телефон: " + Телефон, "")
    + ?(ЗначениеЗаполнено(Другое), ", Другое: " + Другое, "");

Итог

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

← На главную