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

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

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

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

Представим ситуацию: в документе «Расходный ордер на товары» (конфигурация УТ 11.4) товары могут относится к разным рабочим участкам склада. Кладовщику требуется распечатать отдельные задания для каждого участка, присутствующего в конкретном документе. Мы не знаем заранее, сколько участков будет в документе — один или десять. Следовательно, нам нужно проанализировать содержимое документа при его открытии и сформировать соответствующее количество кнопок в подменю «Печать».

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

Шаг 1: Анализ данных и подготовка структуры

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


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

Использование Соответствие или Структура позволяет нам быстро получить уникальный набор ссылок, которые станут основой для будущих команд.

Шаг 2: Программное создание команд и элементов формы

Теперь перейдем к самому важному этапу — модификации формы. Лучше всего использовать обработчик события ПриСозданииНаСервере или ПриЧтенииНаСервере. Рассмотрим вариант с использованием расширения и аннотации &После. Нам нужно не только создать команду в коллекции Команды, но и визуализировать её, добавив элемент типа КнопкаФормы в командную панель.

Разберем алгоритм по шагам:

  1. Получаем список рабочих участков.
  2. Для каждого участка генерируем уникальное имя команды (используем GUID участка, заменяя дефисы на подчеркивания, так как имя команды не может содержать дефис).
  3. Добавляем команду в коллекцию Команды формы и назначаем ей общий обработчик действия.
  4. Создаем кнопку и привязываем её к созданной команде.

&НаСервере
&После("ПриСозданииНаСервере")
Процедура РО_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    // Получаем соответствие участков
    СоответствиеРабочихУчастков = ЗаполнитьРабочиеУчасткиНаСервере();
    
    Для Каждого РУ Из СоответствиеРабочихУчастков Цикл
        // Формируем имя на основе УникальногоИдентификатора ссылки
        СсылкаНаУчасток = РУ.Значение;
        ИмяКоманды = "ПечатьУчастка_" + СтрЗаменить(Строка(СсылкаНаУчасток.УникальныйИдентификатор()), "-", "_");
        
        // 1. Добавляем команду в форму
        НоваяКоманда = Команды.Добавить(ИмяКоманды);
        НоваяКоманда.Действие = "ОбработчикДинамическойПечати"; // Имя клиентской процедуры
        НоваяКоманда.Заголовок = "Печать: " + Строка(СсылкаНаУчасток);
        
        // 2. Добавляем кнопку в подменю печати
        // Предполагаем, что на форме есть группа "ПодменюПечать"
        Родитель = Элементы.Найти("ПодменюПечать");
        Если Родитель = Неопределено Тогда
            Родитель = Элементы.КоманднаяПанель;
        КонецЕсли;
        
        ИмяКнопки = ИмяКоманды + "_Кнопка";
        НоваяКнопка = Элементы.Добавить(ИмяКнопки, Тип("КнопкаФормы"), Родитель);
        НоваяКнопка.ИмяКоманды = ИмяКоманды;
        НоваяКнопка.Заголовок = "Участок: " + Строка(СсылкаНаУчасток);
    КонецЦикла;
    
КонецПроцедуры

Шаг 3: Обработка нажатия на кнопку

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

Выясним причину использования GUID: это самый надежный способ передать ссылку на объект через текстовое имя команды в условиях управляемого приложения.


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

Шаг 4: Формирование печатной формы на сервере

На стороне сервера мы восстанавливаем ссылку на «Рабочий участок» по его GUID и выполняем запрос или алгоритм заполнения макета. Рассмотрим подробнее этот процесс:


&НаСервере
Процедура СформироватьПечатнуюФормуПоУчастку(ТабДок, СтрокаGUID)
    
    Попытка
        УникальныйИд = Новый УникальныйИдентификатор(СтрокаGUID);
        СсылкаНаУчасток = Справочники.РабочиеУчастки.ПолучитьСсылку(УникальныйИд);
    Исключение
        Возврат; // Если GUID невалиден
    КонецПопытки;
    
    Если СсылкаНаУчасток.Пустая() Тогда
        Возврат;
    КонецЕсли;

    // Здесь вызывается ваша логика формирования макета
    // Например:
    // Документы.РасходныйОрдерНаТовары.СформироватьПечатьПоУчастку(Объект.Ссылка, СсылкаНаУчасток, ТабДок);
    
КонецПроцедуры

Важные рекомендации и нюансы

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

  1. Очистка при перечитывании данных: Если пользователь переключается между документами в одной форме (используя навигацию), событие ПриСозданииНаСервере больше не сработает. В этом случае лучше использовать ПриЧтенииНаСервере. Однако помните: перед добавлением новых кнопок нужно обязательно удалить старые, иначе возникнет ошибка «Элемент с таким именем уже существует».
  2. Группировка в интерфейсе: Если рабочих участков много, кнопки «забьют» всю командную панель. Мы рекомендуем создать отдельную группу типа Подменю с заголовком «Печать по участкам» и добавлять кнопки именно туда.
  3. Интеграция с БСП: В типовых конфигурациях (как УТ 11.4) используется Библиотека Стандартных Подсистем (БСП). Если вы хотите, чтобы ваши динамические формы попадали в стандартное меню «Печать» и поддерживали отправку по почте, лучше интегрироваться через механизм ДобавитьКомандыПечати в модуле менеджера. Однако для чисто динамических сценариев, когда состав меню зависит от контента конкретного документа, описанный выше метод через элементы формы является более гибким.
  4. Безопасность имен: Всегда проверяйте, чтобы префикс имени команды (например, ПечатьУчастка_) не пересекался с именами существующих команд конфигурации.

Таким образом, мы рассмотрели полный цикл программного управления интерфейсом: от анализа данных объекта до динамического создания команд и обработки взаимодействия с пользователем. Этот подход позволяет сделать работу в 1С более комфортной и интуитивно понятной, предоставляя пользователю только те инструменты, которые актуальны для текущего контекста данных.

← На главную