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

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

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

Постановка задачи и базовые требования

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

Для реализации этой задачи нам потребуется работать на стороне сервера, так как доступ к глобальному объекту Метаданные на стороне клиента в управляемом приложении невозможен из-за соображений производительности и безопасности платформы.

Способ 1. Обход метаданных конфигурации через вложенные циклы

Самый очевидный и быстрый в реализации способ — прямой программный обход дерева метаданных конфигурации. Метаданные представляют собой иерархическую структуру. Все документы системы находятся в коллекции Метаданные.Документы, а подчиненные им макеты — в коллекции каждого конкретного документа.

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


Для Каждого ОбъектМетаданных Из Метаданные.Документы Цикл
    Для Каждого текМакет из Метаданные.Документы[ОбъектМетаданных.Имя].Макеты Цикл
        Сообщить(текМакет.Имя);
    КонецЦикла;    
КонецЦикла;

Этот код вполне работоспособен, однако он содержит избыточное обращение к коллекции. Конструкция Метаданные.Документы[ОбъектМетаданных.Имя] заставляет платформу выполнять повторный поиск объекта в коллекции по его строковому имени на каждой итерации внешнего цикла. Это снижает общую производительность, особенно в крупных конфигурациях с сотнями видов документов.

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


Для Каждого ДокументМетаданные Из Метаданные.Документы Цикл
    Для Каждого Макет Из ДокументМетаданные.Макеты Цикл
        ИмяМакета = Макет.Имя;
        СинонимМакета = ?(ЗначениеЗаполнено(Макет.Синоним), Макет.Синоним, Макет.Имя);
        // Выполняем полезное действие с полученными данными
    КонецЦикла;
КонецЦикла;

В этом примере мы напрямую считываем свойства макета, такие как имя и синоним, не затрачивая ресурсы сервера на лишние поисковые операции.

Способ 2. Правильное заполнение Таблицы Значений (ТЧ) на форме

После того как данные получены, их необходимо вывести в интерфейс. Начинающие разработчики часто сталкиваются с проблемой, когда строки в табличной части на форме создаются, но отображаются пустыми. Проанализируем типичную ошибку в коде заполнения:


Для Каждого ДокументМетаданные Из Метаданные.Документы Цикл
    Для Каждого Макет Из ДокументМетаданные.Макеты Цикл
        ДокументМакет = ОбъектМетаданных.Синоним + "\" + Макет.Синоним;
        ДокументМакет = ТЧ.Добавить(); // Ошибка! Переменная перезаписывается пустой строкой
    КонецЦикла;
КонецЦикла;

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

Рассмотрим правильный пример процедуры, которая вызывается на сервере (например, при создании формы) и корректно заполняет реквизит формы с именем ПечатныеФормы:


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

Способ 3. Поиск альтернативных мест хранения печатных форм

Важно помнить, что в реальных конфигурациях 1С печатные формы далеко не всегда привязаны к конкретному документу как его подчиненные макеты. Если мы ограничимся только обходом документов, мы потеряем значительную часть важных печатных форм.

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

  1. Общие макеты (Метаданные.ОбщиеМакеты). В общих макетах разработчики часто размещают универсальные печатные формы, регламентированные законодательством (например, ТОРГ-12, УПД, Счет-фактура, М-15). Эти формы могут вызываться из десятков различных документов. Мы можем обойти их следующим образом:
    
    Для Каждого ОбщийМакет Из Метаданные.ОбщиеМакеты Цикл
        // Логика обработки общего макета
        Сообщить("Обнаружен общий макет: " + ОбщийМакет.Имя);
    КонецЦикла;
    
  2. Макеты в отчетах и обработках. Некоторые сложные алгоритмы формирования печатных форм вместе с макетами выносятся в отдельные встроенные обработки. Например, обработка печати ценников или логистика доставки.
  3. Внешние печатные формы (ВПФ). Они вообще не содержатся в конфигураторе. Это файлы внешних обработок (с расширением .epf), которые загружаются пользователями в режиме «1С:Предприятие» и хранятся в специальном справочнике (чаще всего это справочник ДополнительныеОтчетыИОбработки).

Способ 4. Получение списка печатных форм с помощью механизмов БСП

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

Каждый документ, поддерживающий печать по стандартам БСП, регистрирует свои печатные команды в модуле менеджера с помощью экспортной процедуры ДобавитьКомандыПечати(КомандыПечати). Благодаря этому подсистема динамически строит меню кнопки «Печать» на форме документа.

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

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


// Определим имя интересующего нас документа
ПолноеИмяДокумента = "Документ.РеализацияТоваровУслуг";

// Получаем ссылку на идентификатор объекта метаданных с помощью функции БСП
ИдентификаторОбъекта = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПолноеИмяДокумента);

// Извлекаем таблицу зарегистрированных печатных команд для этого объекта
ТаблицаКоманд = УправлениеПечатью.СтандартныеКомандыПечатиОбъекта(ИдентификаторОбъекта);

Для Каждого СтрокаКоманды Из ТаблицаКоманд Цикл
    // СтрокаКоманды.Представление содержит то имя кнопки, которое видит пользователь
    // СтрокаКоманды.Идентификатор содержит уникальный системный код печатной формы
    Сообщить("Найдена печатная форма БСП: " + СтрокаКоманды.Представление 
             + " [Идентификатор: " + СтрокаКоманды.Идентификатор + "]");
КонецЦикла;

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


ИмяДокумента = "Документ.РеализацияТоваровУслуг";
СписокВнешнихФорм = УправлениеПечатью.СписокПечатныхФормИзВнешнихИсточников(ИмяДокумента);

Для Каждого ЭлементСписка Из СписокВнешнихФорм Цикл
    // ЭлементСписка.Представление - имя внешней печатной формы
    // ЭлементСписка.Значение - ссылка на элемент справочника дополнительных обработок
    Сообщить("Подключена внешняя печатная форма: " + ЭлементСписка.Представление);
КонецЦикла;

Сравнительный анализ подходов

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

  1. Обход через метаданные (Способ 1 и 2) идеально подходит для простых «самописных» конфигураций, где все печатные формы созданы классическим путем непосредственно внутри документов. Он работает быстро и не требует наличия БСП.
  2. Поиск альтернативных хранилищ (Способ 3) необходим в тех случаях, когда в вашей системе используется гибридная схема печати, сочетающая в себе встроенные макеты документов и общие регламентированные бланки.
  3. Интеграция с БСП (Способ 4) — это золотой стандарт для типовых конфигураций фирмы «1С». Данный подход гарантирует получение актуального списка форм, включая внешние обработки, добавленные в режиме предприятия без изменения конфигурации, а также учитывает права доступа текущего пользователя.

Выбирайте наиболее оптимальный инструмент в зависимости от масштаба вашей задачи и архитектуры информационной базы!

← На главную