При разработке внешних печатных форм (ВПФ) для конфигураций на базе БСП (Библиотека стандартных подсистем), таких как 1С:Зарплата и управление персоналом 3.1, разработчики часто сталкиваются с ошибками типизации объектов. Одной из наиболее запутанных ситуаций является ошибка обращения к полю КоличествоЭкземпляров. Проблема усугубляется, когда форма готовится для публикации в Личном кабинете сотрудника (ЛК), так как это накладывает дополнительные требования к структуре кода.
В этой статье мы подробно разберем, почему возникает данная ошибка, проанализируем поведение встроенных методов платформы 1С и научимся правильно возвращать данные в коллекцию печатных форм.
Рассмотрим фрагмент кода, в котором возникает ошибка. Разработчик подготавливает печатную форму «Обходной лист» и использует отдельную функцию для формирования табличного документа. Ошибка происходит на этапе выполнения типового кода БСП, который пытается установить количество копий для печати:
ПечатнаяФорма.ТабличныйДокумент.КоличествоЭкземпляров = ПечатнаяФорма.Экземпляров;
При этом отладчик показывает, что объект ПечатнаяФорма.ТабличныйДокумент имеет тип ОбластьЯчеекТабличногоДокумента, хотя ожидается тип ТабличныйДокумент. Именно в этом кроется причина: у «Области» нет и не может быть свойства КоличествоЭкземпляров, так как оно относится ко всему листу целиком.
Проанализируем функцию, которая формирует документ в коде автора:
Функция ТабличныйДокументНаПечать(ПараметрыПечати, МассивОбъектовДляПечати, ОбъектыПечати, ПараметрыВывода)
ТабДокумент = Новый ТабличныйДокумент;
// ... заполнение параметров макета ...
ТабДокумент.КоличествоЭкземпляров = 1;
Возврат ТабДокумент.Вывести(Обходной);
КонецФункции
Обратим внимание на последнюю строку: Возврат ТабДокумент.Вывести(Обходной);. Рассмотрим подробнее, как работает метод платформы Вывести():
Вывести() добавляет указанную область в табличный документ.ОбластьЯчеекТабличногоДокумента (та область, которая только что была выведена в документ).ТабличныйДокумент, а лишь его часть.Когда этот объект попадает в общую процедуру печати и помещается в КоллекцияПечатныхФорм, система считает его полноценным документом и пытается программно задать настройки печати. На этом этапе и происходит аварийное завершение работы.
Для решения проблемы нам необходимо разделить процесс вывода области в документ и процесс возврата самого объекта из функции. Перепишем финал функции следующим образом:
// Правильный вариант завершения формирования документа
ТабДокумент.Вывести(Обходной);
Возврат ТабДокумент; // Возвращаем именно объект типа ТабличныйДокумент
Теперь функция возвращает корректный тип данных, и обращение к свойству КоличествоЭкземпляров пройдет успешно.
Поскольку автор темы готовит форму для ЛК, важно правильно выполнить интеграцию с библиотекой «Зарплата и кадры». Рассмотрим, какие действия необходимы для того, чтобы кнопка «Опубликовать в ЛК» стала доступна и работала корректно.
Во-первых, необходимо использовать процедуру ЗарплатаКадры.ПриОпределенииОбъектовПечатнойФормы. Она инициализирует структуру ПараметрыПечати, добавляя в неё информацию о том, к какому сотруднику привязана форма. Без этого ЛК не поймет, в чьем кабинете должен появиться документ.
// В процедуре Печать()
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("РеквизитыДетализации", "Сотрудник"); // Указываем поле, по которому идет связка
// Подготовка данных для БЗК
ЗарплатаКадры.ПриОпределенииОбъектовПечатнойФормы(МассивОбъектовДляПечати, "ТДОбходнойЛист", "", ПараметрыПечати);
Во-вторых, после формирования табличного документа, его нужно зарегистрировать в коллекции и передать управление подсистеме «Зарплата и кадры»:
// Выводим документ в коллекцию БСП
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(КоллекцияПечатныхФорм, "ТДОбходнойЛист", "Обходной лист", ТабДокумент);
// Вызываем обработчик БЗК для подготовки публикации
ЗарплатаКадры.ПриПечати(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода);
// Передаем параметры внешней печатной формы в параметры вывода
ПараметрыВывода.Вставить("ПараметрыПечатиВнешнейПечатнойФормы", ПараметрыПечати);
Сведем все исправления в единый работающий модуль. Проанализируем структуру процедур и взаимодействие между ними.
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
МассивОбъектовДляПечати = ОбщегоНазначения.СкопироватьРекурсивно(МассивОбъектов);
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("РеквизитыДетализации", "Сотрудник");
// Подготовка структуры для Личного кабинета
ЗарплатаКадры.ПриОпределенииОбъектовПечатнойФормы(МассивОбъектовДляПечати, "ТДОбходнойЛист", "", ПараметрыПечати);
// Формируем сам документ
ТабДокумент = ТабличныйДокументНаПечать(ПараметрыПечати, МассивОбъектовДляПечати, ОбъектыПечати, ПараметрыВывода);
// Регистрация в коллекции
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(КоллекцияПечатныхФорм, "ТДОбходнойЛист", "Обходной лист", ТабДокумент);
// Финализация процесса для БЗК
ЗарплатаКадры.ПриПечати(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода);
ПараметрыВывода.Вставить("ПараметрыПечатиВнешнейПечатнойФормы", ПараметрыПечати);
КонецПроцедуры
Функция ТабличныйДокументНаПечать(ПараметрыПечати, МассивОбъектовДляПечати, ОбъектыПечати, ПараметрыВывода)
ТабДокумент = Новый ТабличныйДокумент;
ТабДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_ОбходнойЛист";
// Работаем с данными документа (на примере первого объекта)
СсылкаНаДокумент = МассивОбъектовДляПечати[0];
Сотрудник = СсылкаНаДокумент.Сотрудник;
МакетикОЛ = ПолучитьОбщийМакет("ОбходнойЛист");
Обходной = МакетикОЛ.ПолучитьОбласть("Обходной");
// Заполнение параметров
Обходной.Параметры.ФИОРаботника = Сотрудник.ФизическоеЛицо.Наименование;
Обходной.Параметры.ДатаРождения = Формат(Сотрудник.ФизическоеЛицо.ДатаРождения, "ДФ=dd.MM.yyyy");
Обходной.Параметры.ДатаДок = Формат(СсылкаНаДокумент.Дата, "ДЛФ=DD");
Обходной.Параметры.Подразделение = СсылкаНаДокумент.Подразделение;
Обходной.Параметры.Должность = СсылкаНаДокумент.Должность;
Обходной.Параметры.ДатаПриема = Формат(СсылкаНаДокумент.ДатаПриема, "ДЛФ=DD");
// Выводим область
ТабДокумент.Вывести(Обходной);
// Устанавливаем свойства документа
ТабДокумент.КоличествоЭкземпляров = 1;
// Возвращаем полноценный ТабличныйДокумент
Возврат ТабДокумент;
КонецФункции
Подведем итоги нашего исследования. Ошибка «Поле объекта не обнаружено (КоличествоЭкземпляров)» — это классический пример нарушения типизации. Программист ожидал ТабличныйДокумент, но из-за особенностей метода Вывести() передал ОбластьЯчеекТабличногоДокумента.
Основные правила, которые помогут избежать подобных проблем в будущем:
Возврат ТабДокумент.Вывести(...). Всегда делайте Вывести() отдельной строкой, а Возврат — следующей.ЗарплатаКадры, если планируется публикация документов в Личном кабинете сотрудника.ОбластьЯчеек..., значит, вы допустили ошибку при формировании или возврате документа.Соблюдение этих простых правил сделает ваш код стабильным, а процесс разработки внешних печатных форм — предсказуемым и быстрым.