Почему при печати документа Word в 1С открывается пустой файл и как исправить ошибку «Поле объекта не обнаружено»?

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

Разработка внешних печатных форм на основе офисных документов Word (в форматах DOC/DOCX) — стандартная задача в экосистеме 1С, особенно при работе с кадровыми документами в конфигурациях вроде «1С:Зарплата и управление персоналом». В процессе реализации таких механизмов через Библиотеку Стандартных Подсистем (БСП) начинающие разработчики часто сталкиваются с двумя неприятными проблемами: вместо заполненного бланка на экран выводится абсолютно пустой документ Word, либо программа аварийно завершает работу с ошибкой «Поле объекта не обнаружено». В этой статье мы подробно разберем причины возникновения этих ошибок и напишем корректный код для их устранения.

Причина 1. Потеря двоичных данных макета при передаче между сервером и клиентом

Вывод пустого документа Word обычно связан с тем, что механизм печати БСП не получает сам файл шаблона. Давайте проанализируем фрагмент кода, в котором совершается эта ошибка:


&НаСервере
Функция ПолучитьДанныеДляПечатиДопСоглашенияНаОбучение
    мОбъект = РеквизитФормыВЗначение("Объект");
    ДвоичныеДанные = мОбъект.ПолучитьМакет("ПФ_DOC_ДопСоглашениеНаОбучение");
    Возврат мОбъект.ПолучитьДанныеДляПечатиДопСоглашенияНаОбучение(ОбъектПечати, ДатаВступленияСоглашенияВСилу);
КонецФункции

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


Макет = УправлениеПечатьюКлиент.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанные, ТипМакета, ИмяМакета);

Поскольку на клиенте переменная ДвоичныеДанные не была определена (или равна Неопределено), метод БСП не находит оригинального шаблона и по умолчанию создает абсолютно новый, пустой документ Microsoft Word. Чтобы решить эту проблему, необходимо передавать двоичные данные макета вместе с данными для заполнения в единой структуре.

Решение: Исправление передачи макета на клиент

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


&НаСервере
Функция ПолучитьДанныеИМакетДляПечати()
    мОбъект = РеквизитФормыВЗначение("Объект");
    
    Результат = Новый Структура;
    Результат.Вставить("Макет", мОбъект.ПолучитьМакет("ПФ_DOC_ДопСоглашениеНаОбучение"));
    Результат.Вставить("Данные", мОбъект.ПолучитьДанныеДляПечатиДопСоглашенияНаОбучение(ОбъектПечати, ДатаВступленияСоглашенияВСилу));
    
    Возврат Результат;
КонецФункции

&НаКлиенте
Процедура Печать(Команда)
    Если ДопСоглашениеНаОбучение Тогда
        ПакетПечати = ПолучитьДанныеИМакетДляПечати();
        НапечататьДопСоглашениеНаОбучение(ПакетПечати.Данные, ПакетПечати.Макет);
    КонецЕсли;
КонецПроцедуры

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

Причина 2. Ошибка «Поле объекта не обнаружено (Пол)» при работе с кадровыми данными

Эта ошибка часто возникает из-за невнимательности при работе с коллекциями данных. Метод КадровыйУчет.КадровыеДанныеСотрудников возвращает не структуру и не конкретную строку, а коллекцию — ТаблицаЗначений. Рассмотрим ошибочный фрагмент кода:


КадровыеДанные = КадровыйУчет.КадровыеДанныеСотрудников(Истина, Сотрудник, "Должность, Пол, ФамилияИО");
Если КадровыеДанные.Количество > 0 Тогда
    СтрокаКадровыеДанные = КадровыеДанные[0];
    ЗаполнитьДанныеСотрудника(Структура, СтрокаКадровыеДанные);
    Структура.Вставить("ИменуемаяЫЙ", ?(КадровыеДанные.Пол = Перечисления.ПолФизическогоЛица.Мужской, "именуемый", "именуемая"));
КонецЕсли;

В данном фрагменте допущены сразу три критические ошибки:

  1. Пропущенные скобки вызова метода: Свойство Количество у таблицы значений является методом. Проверка должна выглядеть как КадровыеДанные.Количество() > 0.
  2. Обращение к таблице значений вместо строки: В строке КадровыеДанные.Пол разработчик пытается получить значение колонки «Пол» напрямую из таблицы значений. Таблица значений не хранит данные полей в корне своего объекта — обращаться нужно к конкретной извлеченной строке СтрокаКадровыеДанные.Пол.
  3. Форматирование параметров XML в Word: Если вы вручную редактировали макет Word и вводили параметры вида {v8 Пол} частями или исправляли опечатки, текстовый процессор мог разбить эту строку внутри файла на несколько XML-тегов форматирования. В таком случае БСП не сможет распознать этот параметр как единое целое.

Решение: Корректное извлечение кадровых данных и заполнение новых параметров

Чтобы добавить новые параметры (например, номер и дату трудового договора сотрудника) и избежать ошибок при определении пола сотрудника, перепишем функцию получения данных следующим образом:


Функция ПолучитьДанныеДляПечатиДопСоглашенияНаОбучение(Сотрудник, ДатаВступленияСоглашенияВСилу) Экспорт
    Организация = Сотрудник.ГоловнаяОрганизация;
    Структура = Новый Структура;
    
    // Форматируем дату соглашения для вывода красивым текстом
    Структура.Вставить("ДатаВступленияСоглашенияВСилу", Формат(ДатаВступленияСоглашенияВСилу, "ДФ='''""''дд''""'' ММММ гггг ''года'''"));
    ЗаполнитьДанныеОрганизации(Структура, Организация);
    
    // Запрашиваем необходимые кадровые данные, включая пол и сведения о трудовом договоре
    СписокПолей = "Организация, НомерДоговораКонтракта, ДатаДоговораКонтракта, АдресПоПропискеПредставление, ФИОПолные, Пол, ФамилияИО, ДокументПредставление";
    КадровыеДанные = КадровыйУчет.КадровыеДанныеСотрудников(Истина, Сотрудник, СписокПолей);
    
    Если КадровыеДанные.Количество() > 0 Тогда
        СтрокаКадровыеДанные = КадровыеДанные[0];
        
        // Передаем в процедуру заполнения именно строку таблицы кадровых данных
        ЗаполнитьДанныеСотрудника(Структура, СтрокаКадровыеДанные);
        
        // Обращаемся к реквизиту Пол через СтрокаКадровыеДанные
        Структура.Вставить("ИменуемаяЫЙ", ?(СтрокаКадровыеДанные.Пол = Перечисления.ПолФизическогоЛица.Мужской, "именуемый", "именуемая"));
        
        // Безопасное заполнение номера договора
        Если ЗначениеЗаполнено(СтрокаКадровыеДанные.НомерДоговораКонтракта) Тогда
            Структура.Вставить("НомерДоговора", СтрокаКадровыеДанные.НомерДоговораКонтракта);
        Иначе
            Структура.Вставить("НомерДоговора", "___________");
        КонецЕсли;
        
        // Безопасное заполнение даты договора
        Если ЗначениеЗаполнено(СтрокаКадровыеДанные.ДатаДоговораКонтракта) Тогда
            Структура.Вставить("ДатаДоговора", Формат(СтрокаКадровыеДанные.ДатаДоговораКонтракта, "ДФ=dd.MM.yyyy"));
        Иначе
            Структура.Вставить("ДатаДоговора", "___________");
        КонецЕсли;
    КонецЕсли;
    
    Возврат Структура;
КонецФункции

Процедура ЗаполнитьДанныеСотрудника(Структура, КадровыеДанные)
    Структура.Вставить("СотрудникФИО", КадровыеДанные.ФамилияИО);
    Структура.Вставить("СотрудникАдрес", КадровыеДанные.АдресПоПропискеПредставление);
КонецПроцедуры

Как правильно подготовить Word-макет

Чтобы добавленные нами параметры успешно вывелись в файл, выполните следующие действия в самом шаблоне Microsoft Word:

  1. Откройте макет вашей печатной формы (двоичные данные макета).
  2. В нужных местах документа пропишите параметры строго в фигурных скобках: например, {v8 НомерДоговора} и {v8 ДатаДоговора}.
  3. Важное правило: Чтобы избежать разрывов во внутреннем XML-представлении Word, пишите параметр в текстовом редакторе в один прием без пауз, исправлений и изменения шрифта отдельных символов. Если параметр не заполняется программно, удалите его целиком и впишите заново одним словом.
  4. Убедитесь, что область печати (например, «Заголовок») определена в структуре документа с помощью механизма закладок (Bookmarks) Word, либо ограничена управляющими тегами БСП.
← На главную