Как программно определить, в каком документе мы находимся при выполнении печати

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

В процессе разработки в среде 1С:Предприятие 8.3, особенно при использовании Библиотеки стандартных подсистем (БСП), программисты часто сталкиваются с необходимостью реализовать универсальную процедуру печати. Типичная ситуация: одна и та же внешняя печатная форма или общая процедура в модуле менеджера должна обрабатывать разные типы документов, применяя к ним различную логику формирования табличного документа. Рассмотрим подробнее, как правильно определить тип документа в процедуре Печать.

Анализ контекста процедуры Печать

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


Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
    // Здесь должен быть код определения типа документа
КонецПроцедуры

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

Способ 1: Определение типа через функцию ТипЗнч (Рекомендуемый)

Самый быстрый и методически верный способ определить, с каким документом мы работаем — это использование функции ТипЗнч и сравнение её с типом ссылки конкретного документа. Рассмотрим по шагам, как это реализовать. Поскольку в МассивОбъектов может быть несколько документов (групповая печать), нам нужно проверить хотя бы первый элемент массива.


Если МассивОбъектов.Количество() > 0 Тогда
    СсылкаНаДокумент = МассивОбъектов[0];
    
    Если ТипЗнч(СсылкаНаДокумент) = Тип("ДокументСсылка.ДанныеДляРасчетаЗарплаты") Тогда
        // Логика для документа Данные для расчета зарплаты
    ИначеЕсли ТипЗнч(СсылкаНаДокумент) = Тип("ДокументСсылка.НачислениеЗарплаты") Тогда
        // Логика для документа Начисление зарплаты
    КонецЕсли;
КонецЕсли;

Почему это работает лучше всего? Сравнение типов в 1С происходит очень быстро, так как идентификаторы типов кэшируются платформой. Выполнение Тип("ДокументСсылка.Имя") не требует обращения к базе данных или тяжелых операций с метаданными.

Способ 2: Использование свойств метаданных

Иногда нам нужно получить строковое имя документа, чтобы использовать его в динамических условиях или логах. В этом случае мы можем обратиться к свойству Метаданные() ссылки. Проанализируем пример кода:


ИмяДокумента = МассивОбъектов[0].Метаданные().Имя;

Если ИмяДокумента = "ДанныеДляРасчетаЗарплаты" Тогда
    // Обработка конкретного типа
КонецЕсли;

Этот способ удобен тем, что Метаданные().Имя возвращает именно то имя документа, которое задано в конфигураторе. Однако стоит помнить, что частое обращение к метаданным в циклах может быть чуть менее производительным, чем прямое сравнение типов.

Типичные ошибки при определении документа

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

Если Документы.ДанныеДляРасчетаЗарплаты Тогда...

В чем ошибка? Документы.ДанныеДляРасчетаЗарплаты — это обращение к Менеджеру документа. В языке 1С менеджер объекта существует всегда (если такой объект определен в конфигурации). Поэтому проверка этого значения в условии Если всегда будет возвращать Истина, так как объект менеджера не равен Неопределено или Ложь. Эта проверка никак не связана с тем, какой именно документ в данный момент находится в обработке.

Работа с разнородными данными в МассивеОбъектов

Рассмотрим ситуацию, когда печать вызывается из общего журнала документов, и пользователь выделил документы разных типов. В этом случае проверка только первого элемента МассивОбъектов[0] приведет к ошибке при обработке последующих элементов. Правильный алгоритм должен выглядеть так:


Для Каждого Ссылка Из МассивОбъектов Цикл
    МетаданныеОбъекта = Ссылка.Метаданные();
    
    Если МетаданныеОбъекта = Метаданные.Документы.ДанныеДляРасчетаЗарплаты Тогда
        // Индивидуальная логика формирования данных для Т-11
    ИначеЕсли МетаданныеОбъекта = Метаданные.Документы.НачислениеЗарплаты Тогда
        // Другая логика
    КонецЕсли;
КонецЦикла;

Оптимизация: Получение данных без обращения к объекту

При определении типа документа нам часто нужно получить и его реквизиты (например, «Вид операции» или «Организация»). Помните, что в процедуре печати мы имеем дело со ссылками. Вызов Ссылка.ПолучитьОбъект() крайне нежелателен, так как он считывает все данные документа из базы данных, что замедляет работу системы.

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


// Пример получения реквизита без получения всего объекта
ВидДокумента = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаДокумент, "ВидОперации");

Альтернативный подход: Использование идентификатора команды

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

Посмотрим на пример регистрации команды:


Команда = КомандыПечати.Добавить();
Команда.Идентификатор = "ПриказТ11_Спец"; // Уникальный ID
Команда.Представление = НСтр("ru = 'Приказ (специальный)'");
// ... остальные параметры

В самой процедуре печати мы можем проверить, какая именно печатная форма запрошена:


Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПриказТ11_Спец") Тогда
    // Мы точно знаем, что нужно печатать, даже если тип документа совпадает
КонецЕсли;

Резюме

Для надежного определения документа в коде 1С 8.3 придерживайтесь следующих правил:

  1. Всегда проверяйте ТипЗнч(МассивОбъектов[0]) для быстрой идентификации типа.
  2. Используйте МассивОбъектов[0].Метаданные().Имя, если вам нужно строковое представление имени объекта метаданных.
  3. Никогда не используйте конструкцию Если Документы.ИмяДокумента Тогда для проверки текущего контекста.
  4. При обработке списков документов разных типов делайте проверку внутри цикла по каждому элементу массива.
  5. Старайтесь минимизировать обращения к базе данных, работая со свойствами ссылок через функции ЗначениеРеквизитаОбъекта.

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

← На главную