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

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

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

  1. Контекстный запуск: открываться напрямую из документа, автоматически подхватывать его реквизиты, табличную часть и сразу выводить данные на печать.
  2. Автономный запуск: открываться из общего интерфейса («Дополнительные обработки» или «Избранное») как независимая обработка, где пользователь может вручную заполнить все параметры (номенклатуру, склад, количество) и запустить печать без привязки к конкретному документу.

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

Способ 1. Использование вида «Дополнительная обработка» с назначением объектов (Рекомендуемый)

Это наиболее изящный и современный способ, позволяющий использовать всего один файл .epf. Мы регистрируем обработку в системе с видом «Дополнительная обработка», но программно назначаем ее для вызова из конкретных документов. При этом БСП позволяет выводить ее форму как в общих разделах интерфейса, так и в контекстном меню документов.

Для реализации этого подхода настроим функцию СведенияОВнешнейОбработке в модуле объекта нашей обработки:


Функция СведенияОВнешнейОбработке() Экспорт
    
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке();
    
    // Регистрируем как дополнительную обработку
    ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
    ПараметрыРегистрации.Наименование = "Печать этикеток коробок (универсальная)";
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.БезопасныйРежим = Ложь;
    
    // Указываем документы, в которых будет доступна эта обработка
    ПараметрыРегистрации.Назначение.Добавить("Документ.ПриобретениеТоваровУслуг");
    ПараметрыРегистрации.Назначение.Добавить("Документ.РеализацияТоваровУслуг");
    
    // Настраиваем команду открытия формы
    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = "Печать этикеток коробок";
    НоваяКоманда.Идентификатор = "ОткрытьФормуПечати";
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
    
    Возврат ПараметрыРегистрации;
    
КонецФункции

Теперь проанализируем поведение формы обработки при ее открытии. Если пользователь запускает обработку из документа, БСП автоматически передает в параметры формы массив ссылок на выбранные документы в ключе ОбъектыНазначения. Если запуск происходит из общего интерфейса, этого параметра не будет. Нам остается обработать это условие в модуле формы:


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

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

Преимущества метода: один файл для администрирования и обновления, стандартное использование БСП. Единственный нюанс — в документе кнопка вызова будет находиться в меню Отчеты -> Дополнительные отчеты или Заполнение -> Дополнительные обработки, а не в стандартном меню Печать.

Способ 2. Автоматическая двойная регистрация одного файла

Если бизнес-требования жестко предписывают, чтобы в документе кнопка находилась исключительно в меню Печать (вид ПечатнаяФорма), а в интерфейсе разделов — как ДополнительнаяОбработка, можно применить хитрость с динамическим заполнением сведений о регистрации. Мы можем загрузить один и тот же файл .epf в справочник дважды.

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


Функция СведенияОВнешнейОбработке() Экспорт
    
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке();
    ИмяОбработки = "Печать этикеток коробок";
    
    ПараметрыРегистрации.Наименование = ИмяОбработки;
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.БезопасныйРежим = Ложь;
    
    // Проверяем, зарегистрирована ли уже печатная форма с таким наименованием
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	ДополнительныеОтчетыИОбработки.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.ДополнительныеОтчетыИОбработки КАК ДополнительныеОтчетыИОбработки
        |ГДЕ
        |	ДополнительныеОтчетыИОбработки.Наименование = &Наименование
        |	И ДополнительныеОтчетыИОбработки.Вид = ЗНАЧЕНИЕ(Перечисление.ВидыДополнительныхОтчетовИОбработок.ПечатнаяФорма)
        |	И НЕ ДополнительныеОтчетыИОбработки.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("Наименование", ИмяОбработки);
    РезультатЗапроса = Запрос.Выполнить();
    
    Если РезультатЗапроса.Пустой() Тогда
        // Первый импорт: регистрируем как стандартную ВПФ для меню "Печать"
        ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиПечатнаяФорма();
        ПараметрыРегистрации.Назначение.Добавить("Документ.РеализацияТоваровУслуг");
        
        Команда = ПараметрыРегистрации.Команды.Добавить();
        Команда.Представление = "Печать этикеток коробок (ВПФ)";
        Команда.Идентификатор = "ПечатьЭтикеток";
        Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
    Иначе
        // Второй импорт: если ВПФ уже есть, регистрируем как обработку для интерфейса
        ПараметрыРегистрации.Наименование = ИмяОбработки + " (Произвольная)";
        ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
        
        Команда = ПараметрыРегистрации.Команды.Добавить();
        Команда.Представление = "Печать этикеток коробок (вручную)";
        Команда.Идентификатор = "ОткрытьФормуВручную";
        Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
    КонецЕсли;
    
    Возврат ПараметрыРегистрации;
    
КонецФункции

При таком подходе в базе данных будут две записи, ссылающиеся на один и тот же внутренний код. Единственный минус — при обновлении алгоритма печати вам потребуется обновить файл в обеих карточках справочника БСП.

Способ 3. Использование легкой обработки-стартера

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

  1. Основная обработка (зарегистрирована как ПечатнаяФорма).
  2. Обработка-стартер (зарегистрирована как ДополнительнаяОбработка).

Задача стартера — программно подключить ВПФ во временное хранилище и вызвать ее форму. Разберем рабочий код модуля формы обработки-стартера:


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

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Ищем основную печатную форму в справочнике по наименованию
    НаименованиеВСправочнике = "Печать этикеток коробок";
    СсылкаНаОсновнуюОбработку = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию(НаименованиеВСправочнике);
    
    Если СсылкаНаОсновнуюОбработку.Пустая() Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не найдена основная внешняя обработка """ + НаименованиеВСправочнике + """");
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    
    // Сохраняем ссылку в реквизит формы для передачи на клиент
    Объект.СсылкаНаОсновнуюОбработку = СсылкаНаОсновнуюОбработку;
    
КонецПроцедуры

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

Способ 4. Программный вызов ВПФ через подсистему печати БСП

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


&НаКлиенте
Процедура ВыполнитьПечатьИзВПФ(Команда)
    
    СсылкаНаВПФ = ПолучитьСсылкуНаОбработкуНаСервере();
    ИдентификаторКоманды = "ПечатьЭтикеток"; // Идентификатор команды из СведенийОВнешнейОбработке
    
    // Формируем список объектов (документов), для которых запускается печать
    МассивДокументов = Новый Массив;
    МассивДокументов.Добавить(Объект.ДокументСсылка);
    
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("ИсточникДанных", СсылкаНаВПФ);
    ПараметрыОткрытия.Вставить("ПараметрыИсточникаДанных", Новый Структура("ИдентификаторКоманды", ИдентификаторКоманды));
    ПараметрыОткрытия.Вставить("ОбъектыПечати", МассивДокументов);
    
    // Открываем стандартное окно предпросмотра печати БСП
    ОткрытьФорму("ОбщаяФорма.ПечатьДокументов", ПараметрыОткрытия);
    
КонецПроцедуры

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

← На главную