В практике разработчика 1С часто возникают задачи, когда типовую печатную форму (например, форму Т-1 «Приказ о приеме на работу») необходимо вызывать не из профильного документа, а из смежного. В нашем случае мы рассмотрим ситуацию, когда форму Т-1 требуется распечатать из документа Продление контракта, договора в конфигурации «Зарплата и управление персоналом 3.1». Основная сложность здесь заключается в том, что данные для формы Т-1 хранятся в документе Прием на работу, а внешняя печатная форма запускается из контекста другого объекта.
Разберем по шагам, как правильно настроить внешнюю печатную форму, переопределить массив объектов и избежать распространенных ошибок, таких как «Табличный документ не сформирован».
Для того чтобы система «понимала», в каком документе должна появиться кнопка печати, нам необходимо правильно заполнить функцию СведенияОВнешнейОбработке. Проанализируем, что нужно изменить. В массиве Назначение должен быть указан именно тот документ, из которого мы планируем запускать печать.
Рассмотрим пример кода регистрации:
Функция СведенияОВнешнейОбработке() Экспорт
Назначение = Новый Массив;
Назначение.Добавить("Документ.ПродлениеКонтрактаДоговора"); // Указываем целевой документ
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.3.1.73");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидДополнительнойОбработкиПечатнаяФорма();
ПараметрыРегистрации.Наименование = "Приказ о приеме (Т-1) из Продления";
ПараметрыРегистрации.Назначение = Назначение;
ПараметрыРегистрации.Идентификатор = "ФормаТ1";
// Команды печати
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Приказ о приеме (Т-1)";
НоваяКоманда.Идентификатор = "ФормаТ1"; // Этот ID должен совпадать с тем, что передается в коллекцию
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
НоваяКоманда.Модификатор = "ПечатьMXL";
Возврат ПараметрыРегистрации;
КонецФункции
Важный момент: если вы просто скопируете код из типовой формы Т-1, она не заработает, так как будет ожидать на входе ссылку на ПриемНаРаботу, а получит ПродлениеКонтрактаДоговора.
Когда пользователь нажимает кнопку «Печать», система передает в процедуру Печать массив МассивОбъектов, содержащий ссылки на документы Продление контракта. Наша задача — проанализировать ситуацию и найти для каждого такого документа соответствующий ему Прием на работу.
Выясним причину, по которой поиск только по физическому лицу может быть ошибочным. У сотрудника может быть несколько приемов (например, по основному месту и по внутреннему совместительству). Поэтому искать документ-основание нужно строго по связке Сотрудник + ФизическоеЛицо.
Проанализируем правильный подход к запросу:
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// 1. Создаем новый массив, куда сложим найденные Приемы на работу
МассивОбъектовПрием = Новый Массив;
// 2. Ищем Приемы на работу по сотрудникам из исходных документов Продления
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продление.Сотрудник КАК Сотрудник,
| КадроваяИстория.Регистратор КАК ДокументПриема
|ИЗ
| Документ.ПродлениеКонтрактаДоговора КАК Продление
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудников КАК КадроваяИстория
| ПО Продление.Сотрудник = КадроваяИстория.Сотрудник
|ГДЕ
| Продление.Ссылка В(&МассивОбъектов)
| И КадроваяИстория.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Прием)
| И КадроваяИстория.Активность = ИСТИНА";
Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Если МассивОбъектовПрием.Найти(Выборка.ДокументПриема) = Неопределено Тогда
МассивОбъектовПрием.Добавить(Выборка.ДокументПриема);
КонецЕсли;
КонецЦикла;
// Проверка на наличие данных
Если МассивОбъектовПрием.Количество() = 0 Тогда
Сообщить("Не найдены документы приема на работу для выбранных сотрудников!");
Возврат;
КонецЕсли;
// 3. Формируем табличный документ
ТабличныйДокумент = СформироватьПечатнуюФормуТ1(МассивОбъектовПрием, ОбъектыПечати);
// 4. Выводим результат в коллекцию
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ФормаТ1",
"Приказ о приеме (Т-1)",
ТабличныйДокумент
);
КонецПроцедуры
Для формирования самой печатной формы Т-1 крайне не рекомендуется «рисовать» макет вручную или писать свои запросы к данным сотрудника. В ЗУП 3.1 реализован мощный механизм программного интерфейса (API). Посмотрим на пример вызова типового метода формирования данных.
Рассмотрим функцию СформироватьПечатнуюФормуТ1. Вместо того чтобы изобретать велосипед, мы можем обратиться к менеджеру документа ПриемНаРаботу или использовать общие модули кадрового учета.
Функция СформироватьПечатнуюФормуТ1(МассивПриемов, ОбъектыПечати)
// Устанавливаем параметры печати
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("ДополнитьНаименованиеВозвратнойТарой", Ложь);
// В ЗУП 3.1 обычно используется менеджер документа ПриемНаРаботу
// Вызываем стандартную печать, передавая наш "подмененный" массив
ТабДок = Документы.ПриемНаРаботу.СформироватьПечатныеФормыПриказаОПриеме(МассивПриемов, ОбъектыПечати, "ФормаТ1");
Возврат ТабДок;
КонецФункции
Эта ошибка — самая частая при разработке внешних печатных форм (ВПФ). Разберем причины её возникновения:
СведенияОВнешнейОбработке вы указали идентификатор "ФормаТ1", а при выводе в коллекцию написали "Форма Т1" (с пробелом). БСП не сможет сопоставить эти данные и выдаст ошибку.ПриемНаРаботу, табличный документ останется пустым. БСП интерпретирует пустой ТабличныйДокумент как ошибку формирования.ОбъектыПечати, убедитесь, что в них передаются ссылки из исходного МассивОбъектов, иначе механизм предварительного просмотра не будет знать, к какому документу относится страница.Проанализируем ситуацию, описанную автором темы. В его коде внутри цикла по МассивОбъектовПрием вызывалась функция печати, в которую передавался весь массив целиком. Это классическая логическая ошибка.
Как было: В цикле 5 раз вызывается печать 5-ти документов. Итог: 25 страниц в печатной форме.
Как надо: Либо мы передаем весь массив в типовую функцию один раз (если она поддерживает массовую печать), либо в цикле формируем табличный документ по одной ссылке и используем метод Вывести().
Рассмотрим правильный пример формирования общего документа:
БольшойТабДок = Новый ТабличныйДокумент;
Для Каждого ТекущийПрием Из МассивОбъектовПрием Цикл
// Создаем временный массив из одного элемента для типовой функции
ОдиночныйМассив = Новый Массив;
ОдиночныйМассив.Добавить(ТекущийПрием);
// Получаем форму на одного сотрудника
МаленькийТабДок = Документы.ПриемНаРаботу.СформироватьПечатныеФормыПриказаОПриеме(ОдиночныйМассив, ОбъектыПечати, "ФормаТ1");
// Добавляем страницу к общему документу
Если БольшойТабДок.ВысотаТаблицы > 0 Тогда
БольшойТабДок.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
БольшойТабДок.Вывести(МаленькийТабДок);
КонецЦикла;
Используя этот подход, мы гарантируем, что каждый сотрудник будет на отдельной странице, и при этом данные будут получены корректно.
Подводя итог, отметим: для реализации «хитрой» печати из другого документа не нужно переписывать всю логику формирования Т-1. Достаточно подменить ссылки в массиве объектов в самом начале работы процедуры Печать. Главное — использовать корректные связи через регистры сведений (КадроваяИсторияСотрудников) и соблюдать идентичность имен в метаданных обработки.
Теперь мы знаем, как программно связать Продление контракта с Приемом на работу и вывести стандартную форму Т-1 без лишних трудозатрат.