Многие разработчики, начинающие работать с конфигурациями на базе БСП (Библиотека Стандартных Подсистем), и в частности с "1С:Зарплата и Управление Персоналом" (ЗУП 3.1), сталкиваются с одной и той же ситуацией. Потребовалось доработать типовой отчет, например, "Отчеты по сотрудникам". Вы сохраняете его как внешний отчет, открываете, нажимаете "Сформировать", а в ответ получаете пустой результат, хотя в самой конфигурации он работает исправно.
В этой статье мы подробно разберем причины такого поведения, проанализируем архитектуру отчетов в современных конфигурациях 1С и рассмотрим несколько способов решения этой задачи: от быстрого "хирургического" вмешательства до архитектурно правильной настройки.
Давайте разберемся, почему так происходит. Причина кроется в механизме работы типовых отчетов в ЗУП 3.1. Если вы откроете Схему Компоновки Данных (СКД) сохраненного отчета, вы часто можете увидеть там либо очень простой запрос, либо запрос-заготовку, в котором отсутствуют многие поля или таблицы.
Дело в том, что в современных конфигурациях текст запроса часто формируется программно "на лету". Это делается для того, чтобы отчет мог адаптироваться под функциональные опции программы (например, ведется ли штатное расписание, используются ли северные надбавки и т.д.).
Логика работы следующая:
ЗарплатаКадрыОтчеты), которые содержат алгоритмы сборки текста запроса.Рассмотрим способы, как заставить внешний отчет работать.
Этот метод подходит, если вам нужно быстро сделать разовую выгрузку или доработку, и вы не планируете поддерживать сложную логику обновлений типового отчета. Суть метода заключается в том, чтобы перехватить готовый текст запроса в момент работы типового отчета и вставить его в ваш внешний файл.
Проанализируем порядок действий:
КомпоновщикМакета.Выполнить.Более простой вариант для типовых отчетов ЗУП — найти место, где вызывается фоновое задание. Обычно это происходит в общей форме отчета:
РезультатФоновогоЗадания = ДлительныеОперации.ВыполнитьВФоне(
"ВариантыОтчетов.СформироватьОтчетВФоне",
ПараметрыФормированияОтчета,
ПараметрыЗапуска);
В этой точке в переменной ПараметрыФормированияОтчета уже содержится схема компоновки данных с модифицированным запросом. Нам нужно "вытащить" текст запроса:
Shift+F9 (Вычислить выражение).ПараметрыФормированияОтчета.СхемаКД.НаборыДанных.Данные.Запрос (путь может немного отличаться в зависимости от структуры наборов данных).Теперь вернемся к нашему внешнему отчету:
Важно: При таком подходе отчет станет статичным. Если в будущем в базе включат новую функциональную опцию (например, начнут использовать новые начисления), ваш внешний отчет об этом "не узнает", так как запрос в нем жестко зафиксирован.
Если вы хотите, чтобы внешний отчет работал так же гибко, как и встроенный, необходимо правильно его зарегистрировать в системе БСП. Для этого нужно дописать код в модуле объекта внешнего отчета.
Проблема пустого результата часто связана с тем, что для внешних отчетов не вызывается процедура ПередЗагрузкойНастроекВКомпоновщик, где и происходит магия подмены запроса.
Чтобы исправить это, выполним следующие шаги в модуле объекта внешнего отчета:
Шаг 1. Настройка сведений о внешней обработке
Найдите функцию СведенияОВнешнейОбработке. Если ее нет — создайте (она нужна для подключения через механизм "Дополнительные отчеты и обработки"). В этой функции необходимо явно указать, что отчет должен определять настройки формы.
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительныйОтчет();
ПараметрыРегистрации.Версия = "1.0";
ПараметрыРегистрации.БезопасныйРежим = Ложь; // Важно для выполнения привилегированных операций
// ... заполнение остальных параметров (наименование, команды) ...
// КЛЮЧЕВОЙ МОМЕНТ:
ПараметрыРегистрации.ОпределитьНастройкиФормы = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
Параметр ОпределитьНастройкиФормы = Истина сообщает системе, что при открытии формы отчета нужно обратиться к модулю объекта за инструкциями.
Шаг 2. Реализация процедуры определения настроек
Теперь добавим в модуль объекта процедуру ОпределитьНастройкиФормы. В ней мы должны "подсказать" системе, как инициализировать наш отчет. Часто достаточно просто указать имя схемы компоновки или вызвать инициализацию событий.
Процедура ОпределитьНастройкиФормы(Форма, КлючВарианта, Настройки) Экспорт
// Принудительно указываем настройки, чтобы отчет вел себя как типовой
Настройки.События.ПередЗагрузкойНастроекВКомпоновщик = Истина;
Настройки.События.ПриОпределенииПараметровВыбора = Истина;
// Если отчет сделан на базе типового, иногда полезно скопировать логику из
// модуля менеджера типового отчета, если она там есть.
КонецПроцедуры
В некоторых случаях (как указано в обсуждении), проблема решается тем, что внешний отчет начинает восприниматься системой корректно, и срабатывают стандартные подписки на события формирования отчетов ЗУП.
Бывает, что типовой отчет полностью полагается на код в своем Модуле Менеджера. У внешнего отчета, как известно, модуль менеджера работает ограниченно (к нему трудно обратиться извне в том же контексте). Поэтому код инициализации нужно перенести в Модуль Объекта внешнего отчета.
Рассмотрим пример. В типовом отчете есть событие ПриКомпоновкеРезультата. В нем часто вызывается общий модуль:
// Код в типовом отчете
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
ЗарплатаКадрыОтчеты.ПриКомпоновкеРезультата(ЭтотОбъект, ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка);
КонецПроцедуры
Если во внешнем отчете этот код есть, но он не отрабатывает корректно (отчет пустой), значит, общий модуль ЗарплатаКадрыОтчеты не может правильно определить метаданные вашего внешнего файла.
В этом случае вам придется продублировать логику инициализации внутри модуля объекта внешнего отчета. Проанализируйте, что именно делает общий модуль для вашего отчета. Часто он заполняет временные таблицы или параметры.
Например, можно попробовать явно вызвать настройку вариантов отчета в событии ПриКомпоновкеРезультата, имитируя поведение типового:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Здесь мы можем вручную инициализировать настройки компоновщика,
// если типовой механизм не сработал.
// Часто требуется программно установить текст запроса,
// взяв логику из типового модуля менеджера.
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// ... Ваш код по модификации запроса или настроек ...
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Стоит отметить, что с развитием платформы 1С использование внешних отчетов для доработки типовых постепенно уходит на второй план. Наиболее современным и надежным способом является использование Расширений конфигурации.
Если вы добавите отчет в расширение, он останется "частью конфигурации" с точки зрения платформы. В этом случае:
Поэтому, если есть возможность, рекомендуем создавать доработку через механизм расширений, заимствуя типовой отчет и внося изменения непосредственно в расширении.
Если внешний отчет из ЗУП 3.1 выдает пустой результат:
СведенияОВнешнейОбработке с параметром ОпределитьНастройкиФормы = Истина и реализуйте соответствующую процедуру в модуле объекта.