При разработке внешних отчетов или обработок на платформе 1С:Предприятие 8.3 в управляемых формах часто возникает задача вывода сформированного табличного документа не просто в стандартное окно просмотра (которое открывается по команде ТабДок.Показать()), а в типовую форму "Печать документов". Эта форма, являющаяся частью Библиотеки Стандартных Подсистем (БСП), предоставляет расширенную функциональность: возможность печати, сохранения в различные форматы, отправки по почте, предварительного просмотра и управления настройками печати.
Разберем, как реализовать такой вывод, используя функциональность БСП, на примере конфигурации УНФ редакции 1.4.
Для того чтобы ваш табличный документ появился в стандартной форме "Печать документов", нам потребуется выполнить несколько ключевых шагов, соблюдая принципы клиент-серверного взаимодействия в 1С:Предприятии.
Начнем с формирования самого табличного документа. Этот процесс всегда должен происходить на сервере, так как он часто включает работу с запросами к базе данных и макетами, которые могут быть недоступны на клиенте.
Создадим функцию на сервере, которая будет отвечать за сбор данных, получение макета и вывод информации в ТабличныйДокумент. Обратите внимание, что для получения макета внешней обработки или отчета на сервере необходимо использовать функцию РеквизитФормыВЗначение("Объект"), чтобы получить ссылку на сам объект обработки/отчета.
Рассмотрим пример формирования табличного документа:
&НаСервере
Функция ПолучитьМойТабличныйДокументНаСервере(МассивОбъектов)
// Создаем новый табличный документ
ТабДок = Новый ТабличныйДокумент;
// Получаем объект внешней обработки/отчета, чтобы получить доступ к макету
ДокументОбъект = РеквизитФормыВЗначение("Объект");
Макет = ДокументОбъект.ПолучитьМакет("МакетОтчета"); // "МакетОтчета" - имя вашего макета в обработке/отчете
// Пример запроса к базе данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СборкаЗапасовПродукция.Номенклатура.Наименование КАК Номенклатура,
| СборкаЗапасовПродукция.Количество КАК КоличествоМест
|ИЗ
| Документ.СборкаЗапасов.Продукция КАК СборкаЗапасовПродукция
|ГДЕ
| СборкаЗапасовПродукция.Ссылка В (&МассивОбъектов)"; // Используем МассивОбъектов для фильтрации
// Если МассивОбъектов содержит ссылки на документы СборкаЗапасов
Если МассивОбъектов.Количество() > 0 Тогда
Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
Иначе
// Если отчет не привязан к конкретным объектам, можно использовать другие параметры
// или формировать данные без привязки к МассивОбъектов.
// Для примера, заглушка:
Запрос.Текст = "ВЫБРАТЬ 1 КАК Номенклатура, 1 КАК КоличествоМест ГДЕ ЛОЖЬ";
КонецЕсли;
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
// Очищаем табличный документ перед выводом
ТабДок.Очистить();
// Выводим заголовок
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьЗаголовок.Параметры.ЗаголовокОтчета = "Отчет по сборке запасов";
ТабДок.Вывести(ОбластьЗаголовок);
// Выводим шапку таблицы
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ТабДок.Вывести(ОбластьШапкаТаблицы);
// Выводим строки данных
ОбластьСтроки = Макет.ПолучитьОбласть("Строки");
Пока Выборка.Следующий() Цикл
ОбластьСтроки.Параметры.Номенклатура = Выборка.Номенклатура;
ОбластьСтроки.Параметры.Количество = Выборка.КоличествоМест;
ТабДок.Вывести(ОбластьСтроки);
КонецЦикла;
// Дополнительные параметры табличного документа
ТабДок.АвтоМасштаб = Истина;
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
Возврат ТабДок;
КонецФункции
Функция ПолучитьМойТабличныйДокументНаСервере в данном примере принимает МассивОбъектов, который может быть массивом ссылок на документы, для которых формируется печатная форма. Если ваш отчет не привязан к конкретным объектам, вы можете передать пустой массив или Неопределено и скорректировать логику запроса.
После того как табличный документ сформирован на сервере, нам необходимо передать его на клиент и вызвать типовые процедуры печати из БСП. Эти процедуры находятся в общем модуле УправлениеПечатьюКлиент.
Для начала, в клиентской процедуре (например, в обработчике команды кнопки на форме отчета или обработки) мы вызываем нашу серверную функцию, чтобы получить сформированный ТабличныйДокумент.
&НаКлиенте
Процедура СформироватьИНапечатать(Команда)
// МассивОбъектов может быть сформирован из выделенных строк таблицы или текущего объекта.
// Для внешнего отчета, возможно, это будет пустой массив или список ссылок на объекты,
// по которым строится отчет.
МассивОбъектов = Новый Массив; // Внешний отчет может работать без привязки к конкретным объектам
// Получаем табличный документ с сервера
ТабДок = ПолучитьМойТабличныйДокументНаСервере(МассивОбъектов);
// ... дальнейший код для вывода в форму печати ...
КонецПроцедуры
Теперь, когда у нас есть ТабДок на клиенте, мы можем использовать модуль УправлениеПечатьюКлиент. Рассмотрим, как это сделать.
&НаКлиенте
Процедура Печать(ИдентификаторКоманды, МассивОбъектов) Экспорт // Эта процедура может быть вызвана из команды формы
// Получаем табличный документ с сервера.
// Если МассивОбъектов не используется для формирования, можно передать пустой массив.
ТабДок = ПолучитьМойТабличныйДокументНаСервере(МассивОбъектов);
// Определим уникальный идентификатор и название вашей печатной формы.
// ИдентификаторПечатнойФормы должен быть уникальным строковым значением.
ИдентификаторПечатнойФормы = "МойВнешнийОтчет_ПФ";
НазваниеПечатнойФормы = НСтр("ru = 'Моя печатная форма из внешнего отчета'");
// Прежде чем вызывать БСП, полезно проверить, доступна ли подсистема "Печать".
// Если БСП не подключена или неактивна, можно использовать простой ТабДок.Показать().
Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
ТабДок.Показать(НазваниеПечатнойФормы);
Возврат;
КонецЕсли;
// Получаем ссылку на общий модуль УправлениеПечатьюКлиент
МодульУправлениеПечатьюКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("УправлениеПечатьюКлиент");
// Создаем новую коллекцию печатных форм.
// ИдентификаторПечатнойФормы используется как ключ для первого элемента коллекции.
КоллекцияПечатныхФорм = МодульУправлениеПечатьюКлиент.НоваяКоллекцияПечатныхФорм(ИдентификаторПечатнойФормы);
// В зависимости от версии БСП, способ добавления ТабличногоДокумента в коллекцию может отличаться.
// Вариант 1: Для более новых версий БСП (например, 2.3.4 и выше, как в сообщении 24)
// ТабличныйДокумент можно присвоить напрямую первому элементу коллекции.
КоллекцияПечатныхФорм[0].ТабличныйДокумент = ТабДок;
// Обязательно устанавливаем синоним макета, иначе в форме печати не будет отображаться название.
КоллекцияПечатныхФорм[0].СинонимМакета = НазваниеПечатнойФормы;
// При необходимости можно также указать имя файла для сохранения
КоллекцияПечатныхФорм[0].ИмяФайлаПечатнойФормы = НазваниеПечатнойФормы;
// Вариант 2: Для старых версий БСП (как в сообщении 17),
// требуется получить объект ОписаниеПечатнойФормы и заполнить его.
// Если используете этот вариант, закомментируйте Вариант 1.
// ПечатнаяФорма = МодульУправлениеПечатьюКлиент.ОписаниеПечатнойФормы(КоллекцияПечатныхФорм, ИдентификаторПечатнойФормы);
// ПечатнаяФорма.СинонимМакета = НазваниеПечатнойФормы;
// ПечатнаяФорма.ТабличныйДокумент = ТабДок;
// ПечатнаяФорма.ИмяФайлаПечатнойФормы = НазваниеПечатнойФормы;
// ОбластиОбъектов - список значений, обычно содержит ссылки на объекты,
// к которым относится печать. Для отчета может быть пустым или Неопределено.
ОбластиОбъектов = Новый СписокЗначений;
// Вызываем типовую процедуру печати документов.
// Эта процедура откроет форму "ПечатьДокументов" и отобразит ваш ТабДок.
МодульУправлениеПечатьюКлиент.ПечатьДокументов(КоллекцияПечатныхФорм, ОбластиОбъектов);
// ДокументыПечатались = Истина; // Это может быть полезно для внутренних нужд обработки
КонецПроцедуры
Для улучшения читаемости и повторного использования кода, а также для создания более гибкого механизма вывода печати, мы можем вынести логику вызова БСП в собственный клиентский общий модуль. Это позволяет создать единую точку входа для печати из различных мест вашей обработки или отчета.
Рассмотрим пример создания вспомогательных процедур в общем модуле (например, КФ_Клиент) по аналогии с сообщением 35:
// В общем модуле КФ_Клиент (клиентский, глобальный)
Процедура ПечатьДокументов(КоллекцияПечатныхФорм, Знач ОбъектыПечати = Неопределено, ВладелецФормы = Неопределено, ЗаголовокФормы = Неопределено) Экспорт
Если ОбъектыПечати = Неопределено Тогда
ОбъектыПечати = Новый СписокЗначений;
КонецЕсли;
КлючУникальности = Строка(Новый УникальныйИдентификатор);
ПараметрыОткрытия = Новый Структура("ИмяМенеджераПечати,ИменаМакетов,ПараметрКоманды,ПараметрыПечати");
ПараметрыОткрытия.ПараметрКоманды = Новый Массив; // Если не передаются конкретные команды
ПараметрыОткрытия.ПараметрыПечати = Новый Структура;
ПараметрыОткрытия.Вставить("КоллекцияПечатныхФорм", КоллекцияПечатныхФорм);
ПараметрыОткрытия.Вставить("ОбъектыПечати", ОбъектыПечати);
ПараметрыОткрытия.ПараметрыПечати.Вставить("ЗаголовокФормы", ЗаголовокФормы);
// Открываем типовую общую форму "ПечатьДокументов"
ОткрытьФорму("ОбщаяФорма.ПечатьДокументов", ПараметрыОткрытия, ВладелецФормы, КлючУникальности);
КонецПроцедуры
Процедура ПечатьДокумента(ИдентификаторПечатнойФормы, ИмяПечатнойФормы, ТабДок, Знач ОбъектыПечати = Неопределено, ВладелецФормы = Неопределено) Экспорт
МодульУправлениеПечатьюКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("УправлениеПечатьюКлиент");
КоллекцияПечатныхФорм = МодульУправлениеПечатьюКлиент.НоваяКоллекцияПечатныхФорм(ИдентификаторПечатнойФормы);
// Используем вариант для новых БСП
КоллекцияПечатныхФорм[0].ТабличныйДокумент = ТабДок;
КоллекцияПечатныхФорм[0].СинонимМакета = ИмяПечатнойФормы;
КоллекцияПечатныхФорм[0].ИмяФайлаПечатнойФормы = ИмяПечатнойФормы; // Опционально
// Если ОбъектыПечати не переданы, создадим пустой список
Если ОбъектыПечати = Неопределено Тогда
ОбъектыПечати = Новый СписокЗначений;
КонецЕсли;
// Вызываем нашу обертку для открытия формы печати
ПечатьДокументов(КоллекцияПечатныхФорм, ОбъектыПечати, ВладелецФормы, ИмяПечатнойФормы);
КонецПроцедуры
Теперь в вашей форме обработки или отчета вызов будет выглядеть значительно проще:
&НаКлиенте
Процедура РешениеОВыплатеНадбавок(Команда)
Если Не ЗначениеЗаполнено(Объект.МесяцОтчета) Тогда
ПоказатьПредупреждение(,"Введите месяц отчета.");
Возврат;
КонецЕсли;
// Вызываем серверную функцию для формирования ТабличногоДокумента
ТабДок = РешениеОНадбавкахНаСервере();
ИдентификаторПечатнойФормы = "КФ_РешениеОНадбавках";
ИмяПечатнойФормы = "Надбавки_" + Формат(Объект.МесяцОтчета,"ДФ='MMMM_yyyy'");
// Вызываем процедуру из нашего общего модуля
КФ_Клиент.ПечатьДокумента(ИдентификаторПечатнойФормы, ИмяПечатнойФормы, ТабДок);
КонецПроцедуры
При работе с БСП и выводом в типовые формы печати могут возникнуть некоторые сложности, которые мы обязательно рассмотрим:
Мы должны помнить, что на тонком клиенте доступны не все типы данных. В частности, такие типы, как ТаблицаЗначений, недоступны для прямой передачи в параметры форм или между клиентом и сервером без сериализации. Если вам необходимо передать сложную структуру данных из клиентской части для формирования табличного документа на сервере, или наоборот, обработать полученные данные на клиенте перед отправкой в форму печати, вы можете столкнуться с ошибками.
В таких случаях рекомендуется преобразовывать ТаблицуЗначений в Структуру или Массив структур на клиенте перед передачей, а затем восстанавливать исходный тип на сервере. Или, что чаще всего предпочтительнее, все операции с ТаблицейЗначений выполнять непосредственно на сервере.
Если же ТаблицаЗначений требуется на форме, ее можно создать как реквизит формы и использовать метод ЗначениеВРеквизитФормы() для передачи данных с сервера на клиент, как было предложено в сообщении 15.
МассивОбъектов.В типовых командах печати часто используется параметр МассивОбъектов, который содержит ссылки на объекты базы данных (например, документы), для которых формируется печатная форма. Если ваш внешний отчет не привязан к конкретным объектам или формирует данные по произвольному диапазону, вы можете передать пустой массив (Новый Массив()) или Неопределено в те места, где этот параметр ожидается, если он не является критичным для логики формирования.
Эта распространенная ошибка (упоминается в сообщениях 34, 37) возникает, когда в функцию или цикл, ожидающий итерируемый объект (например, Массив, СписокЗначений, КоллекцияПечатныхФорм), передается переменная типа Неопределено или объект другого типа, который не поддерживает итерацию.
Всегда убеждайтесь, что параметры, которые должны быть коллекциями (такие как КоллекцияПечатныхФорм, ОбластиОбъектов, МассивОбъектов), правильно инициализированы перед их использованием или передачей в функции. Например, Новый Массив() или Новый СписокЗначений().
При создании коллекции печатных форм (МодульУправлениеПечатьюКлиент.НоваяКоллекцияПечатныхФорм(ИдентификаторПечатнойФормы)) важно использовать уникальный строковый идентификатор для вашей печатной формы. Это позволит БСП корректно управлять ею и отображать в списке доступных для печати форм.
Применяя эти шаги и учитывая указанные нюансы, вы сможете успешно интегрировать вывод ваших табличных документов из внешних отчетов и обработок в стандартную форму "Печать документов" 1С, предоставляя пользователям всю полноту функциональности, предлагаемой БСП.