Разработка отчетов в системе «1С:Предприятие 8.3» на управляемой платформе часто выходит за рамки простого конструирования схем компоновки данных. Перед разработчиком нередко возникает задача: спроектировать сложный отчёт, который должен выводить несколько абсолютно разных по структуре печатных форм (макетов) на основании одного и того же объекта-владельца или набора параметров. При этом важно сохранить удобство типового интерфейса, обеспечить возможность передачи параметров из любой точки конфигурации и не потерять гибкость при сопровождении кода.
В этой статье мы подробно разберем, как спроектировать подобный отчет, выясним наиболее правильное место для размещения программного кода и детально изучим технологию ручного вывода данных с использованием так называемой «схемы-заглушки» СКД.
Приступая к разработке, мы должны четко определить, где будут располагаться наши процедуры получения данных (запросы) и алгоритмы заполнения макетов. В управляемом приложении 1С у нас есть три основных претендента: модуль управляемой формы, модуль менеджера и модуль объекта отчета. Давайте детально проанализируем каждый вариант с точки зрения стандартов разработки «1С» и удобства дальнейшей поддержки.
На первый взгляд, разместить весь код в серверном контексте формы кажется самым простым и быстрым решением. Однако это тупиковый путь. Согласно стандартам разработки фирмы «1С» (в частности, Стандарту №486), модуль формы должен отвечать исключительно за логику интерфейса и взаимодействие с пользователем. Размещение здесь тяжелых запросов и бизнес-логики формирования отчета считается грубой ошибкой. Более того, если отчет будет формироваться в фоновом режиме (что является стандартом для современных конфигураций на базе БСП), фоновое задание просто не получит доступ к контексту формы, и система выдаст ошибку выполнения.
Модуль менеджера отлично подходит для глобальных методов, не привязанных к конкретному экземпляру объекта. В нем настраиваются варианты отчетов для Библиотеки стандартных подсистем (БСП). Однако у этого модуля есть огромный практический минус: при сохранении отчета во внешний файл (например, для оперативной отладки на рабочей базе или передачи заказчику без изменения конфигурации) модуль менеджера полностью теряется. Платформа 1С для объекта ВнешнийОтчетОбъект физически не имеет модуля менеджера. Весь написанный там код придется вручную переносить в другие модули, что существенно замедляет разработку.
Это наиболее сбалансированный и архитектурно верный компромисс. Код, написанный в модуле объекта, прекрасно работает как во встроенном в конфигурацию отчете, так и во внешнем файле. Именно здесь доступно стандартное событие компоновки данных ПриКомпоновкеРезультата, перехватив которое, мы можем полностью управлять процессом построения отчета. Логика формирования данных гарантированно выполнится на сервере, в том числе в фоновом задании БСП, без привязки к клиентскому интерфейсу.
Если нам необходимо вывести нестандартные макеты (например, 6 различных печатных форм), но при этом хочется сохранить типовую форму отчета с ее отборами, параметрами и кнопками, мы применим классический паттерн проектирования — схему-заглушку.
Рассмотрим этот метод подробно и разберем его по шагам:
Шаг 1. Создание фиктивной схемы компоновки. Мы создаем пустую схему компоновки данных (СКД) и назначаем ее основной схемой нашего отчета. В этой схеме мы определяем только параметры данных (например, параметр ОбъектСвязи или Период) и, при необходимости, простые отборы. Нам это нужно для того, чтобы платформа 1С и механизмы БСП распознали наш отчет как полноценный отчет СКД, автоматически сгенерировали форму настроек и вывели стандартные элементы управления.
Шаг 2. Перехват события компоновки. В модуле объекта нашего отчета мы объявляем предопределенную процедуру ПриКомпоновкеРезультата. В самом начале ее выполнения мы отключаем стандартный механизм формирования отчета платформой, устанавливая параметр СтандартнаяОбработка в значение Ложь. Таким образом, платформа передает бразды правления в наши руки.
Посмотрим на практический пример реализации такого механизма в коде модуля объекта:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем автоматический вывод отчета платформой
СтандартнаяОбработка = Ложь;
// Очищаем табличный документ перед выводом
ДокументРезультат.Очистить();
// Получаем настройки, установленные пользователем на форме
НастройкиКомпоновщика = КомпоновщикНастроек.ПолучитьНастройки();
// Извлекаем значение нашего ключевого параметра
ПараметрОбъектСвязи = НастройкиКомпоновщика.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ОбъектСвязи"));
Если ПараметрОбъектСвязи = Неопределено Или Не ЗначениеЗаполнено(ПараметрОбъектСвязи.Значение) Тогда
ВызватьИсключение "Для формирования отчета необходимо заполнить параметр ""Объект связи""!";
КонецЕсли;
СсылкаНаОбъект = ПараметрОбъектСвязи.Значение;
// Определяем, какой именно макет из 6 доступных нам нужно вывести.
// Способ выбора макета может быть передан через другой параметр СКД или доп. настройки.
ПараметрВидФормы = НастройкиКомпоновщика.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ВидПечатнойФормы"));
ИмяВыбранногоМакета = ?(ПараметрВидФормы <> Неопределено, ПараметрВидФормы.Значение, "МакетПоУмолчанию");
// Запускаем процедуру ручного формирования табличного документа
СформироватьРучнойМакет(ДокументРезультат, СсылкаНаОбъект, ИмяВыбранногоМакета);
КонецПроцедуры
Шаг 3. Реализация алгоритма ручного заполнения табличного документа. В этой же процедуре или во вспомогательных экспортных методах модуля объекта мы пишем классический код работы с табличным документом: получаем макет по имени, выполняем запросы к нужным регистрам сведений или справочникам, обходим выборку данных в цикле, заполняем параметры областей макета и последовательно выводим их в ДокументРезультат.
Рассмотрим пример вспомогательного метода формирования конкретного макета:
Процедура СформироватьРучнойМакет(ТабличныйДокумент, ОбъектСсылка, ИмяМакета)
// Получаем макет, встроенный в наш отчет
Макет = ПолучитьМакет(ИмяМакета);
// Получаем области макета
Шапка = Макет.ПолучитьОбласть("Шапка");
СтрокаТаблицы = Макет.ПолучитьОбласть("Строка");
Подвал = Макет.ПолучитьОбласть("Подвал");
// Шаг 1. Вывод Шапки. Запрос к связанным данным объекта
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Партнеры.Наименование КАК ПартнерНаименование,
| Партнеры.Код КАК ПартнерКод
|ИЗ
| Справочник.Партнеры КАК Партнеры
|ГДЕ
| Партнеры.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ОбъектСсылка);
ВыборкаШапки = Запрос.Выполнить().Выбрать();
Если ВыборкаШапки.Следующий() Тогда
Шапка.Параметры.Заполнить(ВыборкаШапки);
КонецЕсли;
ТабличныйДокумент.Вывести(Шапка);
// Шаг 2. Вывод табличной части или связанных движений из регистров сведений
ЗапросДетали = Новый Запрос;
ЗапросДетали.Текст =
"ВЫБРАТЬ
| КонтактнаяИнформация.Вид КАК ВидКонтакта,
| КонтактнаяИнформация.Представление КАК КонтактноеПредставление
|ИЗ
| РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
|ГДЕ
| КонтактнаяИнформация.Объект = &Объект";
ЗапросДетали.УстановитьПараметр("Объект", ОбъектСсылка);
РезультатЗапросаДетали = ЗапросДетали.Выполнить();
ВыборкаДетали = РезультатЗапросаДетали.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
СтрокаТаблицы.Параметры.Заполнить(ВыборкаДетали);
ТабличныйДокумент.Вывести(СтрокаТаблицы);
КонецЦикла;
// Шаг 3. Вывод Подвала
ТабличныйДокумент.Вывести(Подвал);
КонецПроцедуры
Проанализируем важный нюанс работы современных систем на базе БСП. Когда пользователь нажимает кнопку «Сформировать», отчет по умолчанию генерируется в фоновом режиме через подсистему ДлительныеОперации. Это сделано для того, чтобы интерфейс программы не зависал при получении больших объемов данных.
Для разработчика это накладывает ряд ограничений:
ПриКомпоновкеРезультата, категорически запрещено использовать любые интерактивные методы (такие как Предупреждение, Вопрос, открытие диалоговых окон). Фоновое задание выполняется на сервере без участия пользователя, и любая попытка вызвать интерактивное окно приведет к аварийному завершению работы фонового процесса.ПриКомпоновкеРезультата в модуле объекта, а отладчик на ней не останавливается, не спешите паниковать. Это означает, что отчет выполняется в фоновом задании. Чтобы отладчик сработал, зайдите в меню конфигуратора: Отладка -> Подключение... и убедитесь, что у вас установлен флаг автоматического подключения фоновых заданий, либо временно отключите фоновое формирование отчетов в настройках параметров вашей информационной базы.Если ваша задача состоит исключительно в том, чтобы сформировать и показать пользователю 6 видов печатных форм для конкретного объекта, использование объекта метаданных «Отчет» может оказаться избыточным и архитектурно не совсем верным шагом. В БСП для решения подобных задач существует мощная встроенная подсистема — «Управление печатью».
Выясним основные преимущества создания внешних или встроенных печатных форм вместо разработки полноценного отчета:
Выбор между отчетом со схемой-заглушкой и механизмом печати БСП всегда зависит от конечных бизнес-требований. Если пользователю критически важна возможность гибко настраивать отборы на форме перед выводом печатных форм (например, отсекать определенные группы контактов или устанавливать сложные условия), то вариант с отчетом и схемой-заглушкой будет более предпочтительным. Если же печатные формы жестко привязаны к реквизитам одного конкретного документа — обязательно используйте подсистему «Управление печатью».