Почему во внешней печатной форме возникает ошибка «Поле объекта не обнаружено (Дата)» и как ее исправить?

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

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

В этой статье мы подробно разберем, почему возникает данная проблема на примере документа «Увольнение» в конфигурации «1С:Зарплата и управление персоналом», выясним внутренние механизмы работы БСП и рассмотрим правильные, оптимизированные способы написания кода для печатных форм.

В чем причина ошибки: анализируем поведение БСП

Давайте посмотрим на типичный фрагмент кода, который вызывает ошибку у начинающих разработчиков:


Функция СформироватьПечатнуюФорму(СсылкаНаОбъект, ОбъектыПечати) 
    
    ТабДок = Новый ТабличныйДокумент;
    Макет = ПолучитьМакет("Макет");
    Макет.Параметры.ДатаДок = СсылкаНаОбъект.Дата; // Здесь происходит падение

На первый взгляд код выглядит логичным. У документа «Увольнение» гарантированно есть реквизит Дата. Однако при выполнении функции система сообщает, что у объекта СсылкаНаОбъект такого поля нет. Почему так происходит?

Дело в том, что в подсистеме печати БСП первый параметр экспортной функции формирования печатной формы (который разработчик ошибочно назвал СсылкаНаОбъект) всегда является массивом ссылок, а не одиночной ссылкой на документ. Даже если пользователь нажал кнопку печати, выделив в списке всего один документ, система все равно упакует эту единственную ссылку в массив и передаст ее в обработку.

Это архитектурное решение БСП необходимо для реализации групповой (пакетной) печати. Пользователь в журнале документов может выделить сразу 10 или 50 документов и нажать кнопку печати. Чтобы программа не обращалась к серверу 50 раз по отдельности, БСП собирает все ссылки в один массив и передает его в функцию формирования печатной формы за один вызов.

Поскольку параметр является массивом, обращение к нему «через точку» (например, Массив.Дата) закономерно вызывает ошибку платформы, так как у объекта типа Массив нет свойства Дата.

Неочевидная опасность: почему нельзя обращаться «через точку» к ссылкам

Даже если мы обойдем массив и обратимся к реквизитам конкретной ссылки внутри цикла (например, ЭлементМассива.Дата), такой подход считается крайне нежелательным в профессиональной разработке на 1С.

Давайте разберем техническую причину этого ограничения:

  1. Избыточное чтение данных (Overfetching): Когда в коде происходит обращение вида Ссылка.Реквизит, платформа 1С:Предприятие осуществляет неявный запрос к базе данных и считывает весь объект целиком. В память сервера приложений загружаются все реквизиты шапки, все табличные части, а также тяжелые поля (например, прикрепленные файлы, картинки или хранилища значений).
  2. Падение производительности: Если мы отправляем на печать реестр из 100 или 1000 документов, и в цикле обращаемся к их реквизитам через точку, платформа совершит 1000 отдельных полных чтений объектов из СУБД. Это создаст колоссальную нагрузку на дисковую систему сервера, сеть и оперативную память, что приведет к зависанию сеанса пользователя.

Поэтому стандарты разработки фирмы «1С» требуют использовать более оптимизированные механизмы получения данных.

Вариант решения №1: Быстрое исправление кода через обход массива

Если вам нужно оперативно исправить ошибку «здесь и сейчас», достаточно просто переименовать первый параметр функции в МассивОбъектов и организовать цикл обхода этого массива. Рассмотрим пример такого исправления:


Функция СформироватьПечатнуюФорму(МассивОбъектов, ОбъектыПечати) Экспорт
    
    ТабДок = Новый ТабличныйДокумент;
    Макет = ПолучитьМакет("Макет");
    
    // Обходим переданный массив документов в цикле
    Для Каждого СсылкаНаДокумент Из МассивОбъектов Цикл
        
        // Внутри цикла мы работаем с конкретной ссылкой
        Макет.Параметры.ДатаДок = СсылкаНаДокумент.Дата; 
        
        // Здесь продолжается формирование областей макета...
        
    КонецЦикла;
    
    Возврат ТабДок;
    
КонецФункции

Этот вариант исправит ошибку падения, но он все еще содержит неоптимальное обращение через точку внутри цикла. Давайте рассмотрим, как сделать этот код правильным с точки зрения производительности.

Вариант решения №2: Использование быстрых функций БСП

Для оптимизации чтения отдельных реквизитов без загрузки объектов целиком, библиотека БСП предоставляет разработчикам отличный инструмент — функции общего модуля ОбщегоНазначения. Они выполняют легкий SQL-запрос только по тем полям, которые вы укажете.

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


Функция СформироватьПечатнуюФорму(МассивОбъектов, ОбъектыПечати) Экспорт
    
    ТабДок = Новый ТабличныйДокумент;
    Макет = ПолучитьМакет("Макет");
    
    // Получаем реквизиты сразу для всего массива объектов одним запросом
    ТаблицаРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(МассивОбъектов, "Дата, Номер");
    
    Для Каждого СсылкаНаДокумент Из МассивОбъектов Цикл
        
        // Находим строку с реквизитами для текущего документа
        СтрокаРеквизитов = ТаблицаРеквизитов[СсылкаНаДокумент];
        
        Если СтрокаРеквизитов <> Неопределено Тогда
            // Заполняем параметры макета без обращения "через точку"
            Макет.Параметры.ДатаДок  = СтрокаРеквизитов.Дата;
            Макет.Параметры.НомерДок = СтрокаРеквизитов.Номер;
        КонецЕсли;
        
    КонецЦикла;
    
    Возврат ТабДок;
    
КонецФункции

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

Вариант решения №3: Идеальный стандарт разработки (Best Practice)

Несмотря на удобство функций модуля ОбщегоНазначения, при создании сложных печатных форм лучшим решением всегда является написание прямого запроса к базе данных. Это позволяет за одно обращение к СУБД получить не только реквизиты шапки (дата, номер, организация), но и данные всех необходимых табличных частей документов.

Проанализируем пример построения печатной формы с использованием оптимального запроса:


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

Подведем итоги

Мы успешно разобрали причины возникновения ошибки «Поле объекта не обнаружено (Дата)» во внешней печатной форме 1С и изучили методы её устранения. Для того чтобы ваши разработки работали быстро и без сбоев, придерживайтесь следующих правил:

← На главную